diff options
author | Pierre Ossman <ossman@cendio.se> | 2018-12-10 21:16:07 +0100 |
---|---|---|
committer | Pierre Ossman <ossman@cendio.se> | 2018-12-10 21:16:07 +0100 |
commit | d8bbbeb3b37c713a72a113f7ef78741e15cc4a4d (patch) | |
tree | 7d8076302c65cf6ffbd2ccbf9d581476412be36b | |
parent | 139b96741004adc92032a93b8ef6e5927a618f6d (diff) | |
parent | c3826bb2fcb60efa495b54dd66296bc55ce28ecf (diff) | |
download | tigervnc-d8bbbeb3b37c713a72a113f7ef78741e15cc4a4d.tar.gz tigervnc-d8bbbeb3b37c713a72a113f7ef78741e15cc4a4d.zip |
Merge branch 'connparams' of https://github.com/CendioOssman/tigervnc
55 files changed, 1234 insertions, 1084 deletions
diff --git a/common/rfb/CConnection.cxx b/common/rfb/CConnection.cxx index fb953775..3ea217fa 100644 --- a/common/rfb/CConnection.cxx +++ b/common/rfb/CConnection.cxx @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ +#include <assert.h> #include <stdio.h> #include <string.h> @@ -24,6 +25,7 @@ #include <rfb/CMsgReader.h> #include <rfb/CMsgWriter.h> #include <rfb/CSecurity.h> +#include <rfb/Decoder.h> #include <rfb/Security.h> #include <rfb/SecurityClient.h> #include <rfb/CConnection.h> @@ -39,9 +41,17 @@ using namespace rfb; static LogWriter vlog("CConnection"); CConnection::CConnection() - : csecurity(0), is(0), os(0), reader_(0), writer_(0), + : csecurity(0), + supportsLocalCursor(false), supportsDesktopResize(false), + supportsLEDState(false), + is(0), os(0), reader_(0), writer_(0), shared(false), state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false), + pendingPFChange(false), preferredEncoding(encodingTight), + compressLevel(2), qualityLevel(-1), + formatChange(false), encodingChange(false), + firstUpdate(true), pendingUpdate(false), continuousUpdates(false), + forceNonincremental(true), framebuffer(NULL), decoder(this) { } @@ -67,6 +77,11 @@ void CConnection::setFramebuffer(ModifiablePixelBuffer* fb) { decoder.flush(); + if (fb) { + assert(fb->width() == server.width()); + assert(fb->height() == server.height()); + } + if ((framebuffer != NULL) && (fb != NULL)) { Rect rect; @@ -128,35 +143,51 @@ void CConnection::processMsg() void CConnection::processVersionMsg() { + char verStr[13]; + int majorVersion; + int minorVersion; + vlog.debug("reading protocol version"); - bool done; - if (!cp.readVersion(is, &done)) { + + if (!is->checkNoWait(12)) + return; + + is->readBytes(verStr, 12); + verStr[12] = '\0'; + + if (sscanf(verStr, "RFB %03d.%03d\n", + &majorVersion, &minorVersion) != 2) { state_ = RFBSTATE_INVALID; throw Exception("reading version failed: not an RFB server?"); } - if (!done) return; + + server.setVersion(majorVersion, minorVersion); vlog.info("Server supports RFB protocol version %d.%d", - cp.majorVersion, cp.minorVersion); + server.majorVersion, server.minorVersion); // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8 - if (cp.beforeVersion(3,3)) { + if (server.beforeVersion(3,3)) { vlog.error("Server gave unsupported RFB protocol version %d.%d", - cp.majorVersion, cp.minorVersion); + server.majorVersion, server.minorVersion); state_ = RFBSTATE_INVALID; throw Exception("Server gave unsupported RFB protocol version %d.%d", - cp.majorVersion, cp.minorVersion); - } else if (useProtocol3_3 || cp.beforeVersion(3,7)) { - cp.setVersion(3,3); - } else if (cp.afterVersion(3,8)) { - cp.setVersion(3,8); + server.majorVersion, server.minorVersion); + } else if (useProtocol3_3 || server.beforeVersion(3,7)) { + server.setVersion(3,3); + } else if (server.afterVersion(3,8)) { + server.setVersion(3,8); } - cp.writeVersion(os); + sprintf(verStr, "RFB %03d.%03d\n", + server.majorVersion, server.minorVersion); + os->writeBytes(verStr, 12); + os->flush(); + state_ = RFBSTATE_SECURITY_TYPES; vlog.info("Using RFB protocol version %d.%d", - cp.majorVersion, cp.minorVersion); + server.majorVersion, server.minorVersion); } @@ -169,7 +200,7 @@ void CConnection::processSecurityTypesMsg() std::list<rdr::U8> secTypes; secTypes = security.GetEnabledSecTypes(); - if (cp.isVersion(3,3)) { + if (server.isVersion(3,3)) { // legacy 3.3 server may only offer "vnc authentication" or "none" @@ -252,7 +283,7 @@ void CConnection::processSecurityResultMsg() { vlog.debug("processing security result message"); int result; - if (cp.beforeVersion(3,8) && csecurity->getType() == secTypeNone) { + if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) { result = secResultOK; } else { if (!is->checkNoWait(1)) return; @@ -272,7 +303,7 @@ void CConnection::processSecurityResultMsg() throw Exception("Unknown security result from server"); } state_ = RFBSTATE_INVALID; - if (cp.beforeVersion(3,8)) + if (server.beforeVersion(3,8)) throw AuthFailureException(); CharArray reason(is->readString()); throw AuthFailureException(reason.buf); @@ -296,7 +327,7 @@ void CConnection::securityCompleted() { state_ = RFBSTATE_INITIALISATION; reader_ = new CMsgReader(this, is); - writer_ = new CMsgWriter(&cp, os); + writer_ = new CMsgWriter(&server, os); vlog.debug("Authentication success!"); authSuccess(); writer_->writeClientInit(shared); @@ -307,6 +338,16 @@ void CConnection::setDesktopSize(int w, int h) decoder.flush(); CMsgHandler::setDesktopSize(w,h); + + if (continuousUpdates) + writer()->writeEnableContinuousUpdates(true, 0, 0, + server.width(), + server.height()); + + resizeFramebuffer(); + assert(framebuffer != NULL); + assert(framebuffer->width() == server.width()); + assert(framebuffer->height() == server.height()); } void CConnection::setExtendedDesktopSize(unsigned reason, @@ -317,6 +358,59 @@ 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()); + + resizeFramebuffer(); + assert(framebuffer != NULL); + assert(framebuffer->width() == server.width()); + assert(framebuffer->height() == 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, + const PixelFormat& pf, + const char* name) +{ + CMsgHandler::serverInit(width, height, pf, name); + + state_ = RFBSTATE_NORMAL; + vlog.debug("initialisation done"); + + initDone(); + 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, @@ -329,6 +423,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() @@ -336,6 +437,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) @@ -347,10 +467,64 @@ void CConnection::authSuccess() { } -void CConnection::serverInit() +void CConnection::initDone() { - state_ = RFBSTATE_NORMAL; - vlog.debug("initialisation done"); +} + +void CConnection::resizeFramebuffer() +{ + assert(false); +} + +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 (compressLevel == level) + return; + + compressLevel = level; + encodingChange = true; +} + +void CConnection::setQualityLevel(int level) +{ + if (qualityLevel == level) + return; + + 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[]) @@ -365,3 +539,94 @@ 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) { + updateEncodings(); + encodingChange = false; + } + + if (forceNonincremental || !continuousUpdates) { + pendingUpdate = true; + writer()->writeFramebufferUpdateRequest(Rect(0, 0, + server.width(), + server.height()), + !forceNonincremental); + } + + forceNonincremental = false; +} + +// Ask for encodings based on which decoders are supported. Assumes higher +// encoding numbers are more desirable. + +void CConnection::updateEncodings() +{ + std::list<rdr::U32> encodings; + + if (supportsLocalCursor) { + encodings.push_back(pseudoEncodingCursorWithAlpha); + encodings.push_back(pseudoEncodingCursor); + encodings.push_back(pseudoEncodingXCursor); + } + if (supportsDesktopResize) { + encodings.push_back(pseudoEncodingDesktopSize); + encodings.push_back(pseudoEncodingExtendedDesktopSize); + } + if (supportsLEDState) + encodings.push_back(pseudoEncodingLEDState); + + encodings.push_back(pseudoEncodingDesktopName); + encodings.push_back(pseudoEncodingLastRect); + encodings.push_back(pseudoEncodingContinuousUpdates); + encodings.push_back(pseudoEncodingFence); + encodings.push_back(pseudoEncodingQEMUKeyEvent); + + if (Decoder::supported(preferredEncoding)) { + encodings.push_back(preferredEncoding); + } + + encodings.push_back(encodingCopyRect); + + for (int i = encodingMax; i >= 0; i--) { + if ((i != preferredEncoding) && Decoder::supported(i)) + encodings.push_back(i); + } + + if (compressLevel >= 0 && compressLevel <= 9) + encodings.push_back(pseudoEncodingCompressLevel0 + compressLevel); + if (qualityLevel >= 0 && qualityLevel <= 9) + encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel); + + writer()->writeSetEncodings(encodings); +} diff --git a/common/rfb/CConnection.h b/common/rfb/CConnection.h index e29c0331..5a3ef919 100644 --- a/common/rfb/CConnection.h +++ b/common/rfb/CConnection.h @@ -100,6 +100,12 @@ 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); + virtual void readAndDecodeRect(const Rect& r, int encoding, ModifiablePixelBuffer* pb); @@ -110,20 +116,43 @@ namespace rfb { // Methods to be overridden in a derived class - // getIdVerifier() returns the identity verifier associated with the connection. - // Ownership of the IdentityVerifier is retained by the CConnection instance. - virtual IdentityVerifier* getIdentityVerifier() {return 0;} - // authSuccess() is called when authentication has succeeded. virtual void authSuccess(); - // serverInit() is called when the ServerInit message is received. The - // derived class must call on to CConnection::serverInit(). - virtual void serverInit(); + // initDone() is called when the connection is fully established + // and standard messages can be sent. This is called before the + // initial FramebufferUpdateRequest giving a derived class the + // chance to modify pixel format and settings. The derived class + // must also make sure it has provided a valid framebuffer before + // returning. + virtual void initDone() = 0; + + // resizeFramebuffer() is called whenever the framebuffer + // dimensions or the screen layout changes. A subclass must make + // sure the pixel buffer has been updated once this call returns. + virtual void resizeFramebuffer(); // 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_; } @@ -159,6 +188,13 @@ namespace rfb { ModifiablePixelBuffer* getFramebuffer() { return framebuffer; } + protected: + // Optional capabilities that a subclass is expected to set to true + // if supported + bool supportsLocalCursor; + bool supportsDesktopResize; + bool supportsLEDState; + private: // This is a default implementation of fences that automatically // responds to requests, stating no support for synchronisation. @@ -176,6 +212,9 @@ namespace rfb { void throwConnFailedException(); void securityCompleted(); + void requestNewUpdate(); + void updateEncodings(); + rdr::InStream* is; rdr::OutStream* os; CMsgReader* reader_; @@ -188,6 +227,23 @@ namespace rfb { bool useProtocol3_3; + bool pendingPFChange; + rfb::PixelFormat pendingPF; + + int preferredEncoding; + int compressLevel; + int qualityLevel; + + bool formatChange; + rfb::PixelFormat nextPF; + bool encodingChange; + + bool firstUpdate; + bool pendingUpdate; + bool continuousUpdates; + + bool forceNonincremental; + ModifiablePixelBuffer* framebuffer; DecodeManager decoder; }; diff --git a/common/rfb/CMakeLists.txt b/common/rfb/CMakeLists.txt index b8d08137..8e532a28 100644 --- a/common/rfb/CMakeLists.txt +++ b/common/rfb/CMakeLists.txt @@ -11,9 +11,9 @@ set(RFB_SOURCES CSecurityStack.cxx CSecurityVeNCrypt.cxx CSecurityVncAuth.cxx + ClientParams.cxx ComparingUpdateTracker.cxx Configuration.cxx - ConnParams.cxx CopyRectDecoder.cxx Cursor.cxx DecodeManager.cxx @@ -43,6 +43,7 @@ set(RFB_SOURCES SMsgReader.cxx SMsgWriter.cxx ServerCore.cxx + ServerParams.cxx Security.cxx SecurityServer.cxx SecurityClient.cxx diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx index b89bc184..4fe50414 100644 --- a/common/rfb/CMsgHandler.cxx +++ b/common/rfb/CMsgHandler.cxx @@ -34,50 +34,53 @@ CMsgHandler::~CMsgHandler() void CMsgHandler::setDesktopSize(int width, int height) { - cp.width = width; - cp.height = height; + server.setDimensions(width, height); } void CMsgHandler::setExtendedDesktopSize(unsigned reason, unsigned result, int width, int height, const ScreenSet& layout) { - cp.supportsSetDesktopSize = true; + server.supportsSetDesktopSize = true; if ((reason == reasonClient) && (result != resultSuccess)) return; - if (!layout.validate(width, height)) - fprintf(stderr, "Server sent us an invalid screen layout\n"); - - cp.width = width; - cp.height = height; - cp.screenLayout = layout; + server.setDimensions(width, height, layout); } void CMsgHandler::setPixelFormat(const PixelFormat& pf) { - cp.setPF(pf); + server.setPF(pf); } void CMsgHandler::setName(const char* name) { - cp.setName(name); + server.setName(name); } void CMsgHandler::fence(rdr::U32 flags, unsigned len, const char data[]) { - cp.supportsFence = true; + server.supportsFence = true; } void CMsgHandler::endOfContinuousUpdates() { - cp.supportsContinuousUpdates = true; + server.supportsContinuousUpdates = true; } void CMsgHandler::supportsQEMUKeyEvent() { - cp.supportsQEMUKeyEvent = true; + server.supportsQEMUKeyEvent = true; +} + +void CMsgHandler::serverInit(int width, int height, + const PixelFormat& pf, + const char* name) +{ + server.setDimensions(width, height); + server.setPF(pf); + server.setName(name); } void CMsgHandler::framebufferUpdateStart() @@ -90,5 +93,5 @@ void CMsgHandler::framebufferUpdateEnd() void CMsgHandler::setLEDState(unsigned int state) { - cp.setLEDState(state); + server.setLEDState(state); } diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h index 903ee156..effdaabf 100644 --- a/common/rfb/CMsgHandler.h +++ b/common/rfb/CMsgHandler.h @@ -26,7 +26,7 @@ #include <rdr/types.h> #include <rfb/Pixel.h> -#include <rfb/ConnParams.h> +#include <rfb/ServerParams.h> #include <rfb/Rect.h> #include <rfb/ScreenSet.h> @@ -41,9 +41,9 @@ namespace rfb { // The following methods are called as corresponding messages are read. A // derived class should override these methods as desired. Note that for - // the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat() and - // setName() methods, a derived class should call on to CMsgHandler's - // methods to set the members of cp appropriately. + // the setDesktopSize(), setExtendedDesktopSize(), setPixelFormat(), + // setName() and serverInit() methods, a derived class should call on to + // CMsgHandler's methods to set the members of "server" appropriately. virtual void setDesktopSize(int w, int h); virtual void setExtendedDesktopSize(unsigned reason, unsigned result, @@ -56,7 +56,9 @@ namespace rfb { virtual void fence(rdr::U32 flags, unsigned len, const char data[]); virtual void endOfContinuousUpdates(); virtual void supportsQEMUKeyEvent(); - virtual void serverInit() = 0; + virtual void serverInit(int width, int height, + const PixelFormat& pf, + const char* name) = 0; virtual void readAndDecodeRect(const Rect& r, int encoding, ModifiablePixelBuffer* pb) = 0; @@ -72,7 +74,7 @@ namespace rfb { virtual void setLEDState(unsigned int state); - ConnParams cp; + ServerParams server; }; } #endif diff --git a/common/rfb/CMsgReader.cxx b/common/rfb/CMsgReader.cxx index e42546d4..3422ebf5 100644 --- a/common/rfb/CMsgReader.cxx +++ b/common/rfb/CMsgReader.cxx @@ -43,13 +43,10 @@ void CMsgReader::readServerInit() { int width = is->readU16(); int height = is->readU16(); - handler->setDesktopSize(width, height); PixelFormat pf; pf.read(is); - handler->setPixelFormat(pf); CharArray name(is->readString()); - handler->setName(name.buf); - handler->serverInit(); + handler->serverInit(width, height, pf, name.buf); } void CMsgReader::readMsg() @@ -192,10 +189,11 @@ void CMsgReader::readFramebufferUpdate() void CMsgReader::readRect(const Rect& r, int encoding) { - if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) { + if ((r.br.x > handler->server.width()) || + (r.br.y > handler->server.height())) { fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n", r.width(), r.height(), r.tl.x, r.tl.y, - handler->cp.width, handler->cp.height); + handler->server.width(), handler->server.height()); throw Exception("Rect too big"); } @@ -269,7 +267,7 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot) if (width > maxCursorSize || height > maxCursorSize) throw Exception("Too big cursor"); - int data_len = width * height * (handler->cp.pf().bpp/8); + int data_len = width * height * (handler->server.pf().bpp/8); int mask_len = ((width+7)/8) * height; rdr::U8Array data(data_len); rdr::U8Array mask(mask_len); @@ -290,14 +288,14 @@ void CMsgReader::readSetCursor(int width, int height, const Point& hotspot) int byte = y * maskBytesPerRow + x / 8; int bit = 7 - x % 8; - handler->cp.pf().rgbFromBuffer(out, in, 1); + handler->server.pf().rgbFromBuffer(out, in, 1); if (mask.buf[byte] & (1 << bit)) out[3] = 255; else out[3] = 0; - in += handler->cp.pf().bpp/8; + in += handler->server.pf().bpp/8; out += 4; } } @@ -321,10 +319,10 @@ void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hots encoding = is->readS32(); - origPF = handler->cp.pf(); - handler->cp.setPF(rgbaPF); + origPF = handler->server.pf(); + handler->server.setPF(rgbaPF); handler->readAndDecodeRect(pb.getRect(), encoding, &pb); - handler->cp.setPF(origPF); + handler->server.setPF(origPF); // On-wire data has pre-multiplied alpha, but we store it // non-pre-multiplied diff --git a/common/rfb/CMsgWriter.cxx b/common/rfb/CMsgWriter.cxx index 44b73dab..d357c976 100644 --- a/common/rfb/CMsgWriter.cxx +++ b/common/rfb/CMsgWriter.cxx @@ -20,19 +20,17 @@ #include <rdr/OutStream.h> #include <rfb/msgTypes.h> #include <rfb/fenceTypes.h> -#include <rfb/encodings.h> #include <rfb/qemuTypes.h> #include <rfb/Exception.h> #include <rfb/PixelFormat.h> #include <rfb/Rect.h> -#include <rfb/ConnParams.h> -#include <rfb/Decoder.h> +#include <rfb/ServerParams.h> #include <rfb/CMsgWriter.h> using namespace rfb; -CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_) - : cp(cp_), os(os_) +CMsgWriter::CMsgWriter(ServerParams* server_, rdr::OutStream* os_) + : server(server_), os(os_) { } @@ -54,96 +52,21 @@ void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf) endMsg(); } -void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings) +void CMsgWriter::writeSetEncodings(const std::list<rdr::U32> encodings) { + std::list<rdr::U32>::const_iterator iter; startMsg(msgTypeSetEncodings); os->skip(1); - os->writeU16(nEncodings); - for (int i = 0; i < nEncodings; i++) - os->writeU32(encodings[i]); + os->writeU16(encodings.size()); + for (iter = encodings.begin(); iter != encodings.end(); ++iter) + os->writeU32(*iter); endMsg(); } -// Ask for encodings based on which decoders are supported. Assumes higher -// encoding numbers are more desirable. - -void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect) -{ - int nEncodings = 0; - rdr::U32 encodings[encodingMax+3]; - - if (cp->supportsLocalCursor) { - encodings[nEncodings++] = pseudoEncodingCursorWithAlpha; - encodings[nEncodings++] = pseudoEncodingCursor; - encodings[nEncodings++] = pseudoEncodingXCursor; - } - if (cp->supportsDesktopResize) - encodings[nEncodings++] = pseudoEncodingDesktopSize; - if (cp->supportsExtendedDesktopSize) - encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize; - if (cp->supportsDesktopRename) - encodings[nEncodings++] = pseudoEncodingDesktopName; - if (cp->supportsLEDState) - encodings[nEncodings++] = pseudoEncodingLEDState; - - encodings[nEncodings++] = pseudoEncodingLastRect; - encodings[nEncodings++] = pseudoEncodingContinuousUpdates; - encodings[nEncodings++] = pseudoEncodingFence; - encodings[nEncodings++] = pseudoEncodingQEMUKeyEvent; - - if (Decoder::supported(preferredEncoding)) { - encodings[nEncodings++] = preferredEncoding; - } - - if (useCopyRect) { - encodings[nEncodings++] = encodingCopyRect; - } - - /* - * Prefer encodings in this order: - * - * Tight, ZRLE, Hextile, * - */ - - if ((preferredEncoding != encodingTight) && - Decoder::supported(encodingTight)) - encodings[nEncodings++] = encodingTight; - - if ((preferredEncoding != encodingZRLE) && - Decoder::supported(encodingZRLE)) - encodings[nEncodings++] = encodingZRLE; - - if ((preferredEncoding != encodingHextile) && - Decoder::supported(encodingHextile)) - encodings[nEncodings++] = encodingHextile; - - // Remaining encodings - for (int i = encodingMax; i >= 0; i--) { - switch (i) { - case encodingCopyRect: - case encodingTight: - case encodingZRLE: - case encodingHextile: - /* These have already been sent earlier */ - break; - default: - if ((i != preferredEncoding) && Decoder::supported(i)) - encodings[nEncodings++] = i; - } - } - - if (cp->compressLevel >= 0 && cp->compressLevel <= 9) - encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel; - if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9) - encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel; - - writeSetEncodings(nEncodings, encodings); -} - void CMsgWriter::writeSetDesktopSize(int width, int height, const ScreenSet& layout) { - if (!cp->supportsSetDesktopSize) + if (!server->supportsSetDesktopSize) throw Exception("Server does not support SetDesktopSize"); startMsg(msgTypeSetDesktopSize); @@ -182,7 +105,7 @@ void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental) void CMsgWriter::writeEnableContinuousUpdates(bool enable, int x, int y, int w, int h) { - if (!cp->supportsContinuousUpdates) + if (!server->supportsContinuousUpdates) throw Exception("Server does not support continuous updates"); startMsg(msgTypeEnableContinuousUpdates); @@ -199,7 +122,7 @@ void CMsgWriter::writeEnableContinuousUpdates(bool enable, void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) { - if (!cp->supportsFence) + if (!server->supportsFence) throw Exception("Server does not support fences"); if (len > 64) throw Exception("Too large fence payload"); @@ -219,7 +142,7 @@ void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { - if (!cp->supportsQEMUKeyEvent || !keycode) { + if (!server->supportsQEMUKeyEvent || !keycode) { /* This event isn't meaningful without a valid keysym */ if (!keysym) return; @@ -245,8 +168,8 @@ void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask) Point p(pos); if (p.x < 0) p.x = 0; if (p.y < 0) p.y = 0; - if (p.x >= cp->width) p.x = cp->width - 1; - if (p.y >= cp->height) p.y = cp->height - 1; + if (p.x >= server->width()) p.x = server->width() - 1; + if (p.y >= server->height()) p.y = server->height() - 1; startMsg(msgTypePointerEvent); os->writeU8(buttonMask); diff --git a/common/rfb/CMsgWriter.h b/common/rfb/CMsgWriter.h index 1322186a..4d533d42 100644 --- a/common/rfb/CMsgWriter.h +++ b/common/rfb/CMsgWriter.h @@ -23,6 +23,8 @@ #ifndef __RFB_CMSGWRITER_H__ #define __RFB_CMSGWRITER_H__ +#include <list> + #include <rdr/types.h> namespace rdr { class OutStream; } @@ -30,21 +32,20 @@ namespace rdr { class OutStream; } namespace rfb { class PixelFormat; - class ConnParams; + class ServerParams; struct ScreenSet; struct Point; struct Rect; class CMsgWriter { public: - CMsgWriter(ConnParams* cp, rdr::OutStream* os); + CMsgWriter(ServerParams* server, rdr::OutStream* os); virtual ~CMsgWriter(); void writeClientInit(bool shared); void writeSetPixelFormat(const PixelFormat& pf); - void writeSetEncodings(int nEncodings, rdr::U32* encodings); - void writeSetEncodings(int preferredEncoding, bool useCopyRect); + void writeSetEncodings(const std::list<rdr::U32> encodings); void writeSetDesktopSize(int width, int height, const ScreenSet& layout); void writeFramebufferUpdateRequest(const Rect& r,bool incremental); @@ -60,7 +61,7 @@ namespace rfb { void startMsg(int type); void endMsg(); - ConnParams* cp; + ServerParams* server; rdr::OutStream* os; }; } diff --git a/common/rfb/CSecurityTLS.cxx b/common/rfb/CSecurityTLS.cxx index d6a8d7f8..c6d1e310 100644 --- a/common/rfb/CSecurityTLS.cxx +++ b/common/rfb/CSecurityTLS.cxx @@ -34,7 +34,6 @@ #endif #include <rfb/CSecurityTLS.h> -#include <rfb/SSecurityVeNCrypt.h> #include <rfb/CConnection.h> #include <rfb/LogWriter.h> #include <rfb/Exception.h> diff --git a/common/rfb/CSecurityTLS.h b/common/rfb/CSecurityTLS.h index 4932c078..476d0ef8 100644 --- a/common/rfb/CSecurityTLS.h +++ b/common/rfb/CSecurityTLS.h @@ -31,7 +31,6 @@ #endif #include <rfb/CSecurity.h> -#include <rfb/SSecurityVeNCrypt.h> #include <rfb/Security.h> #include <rfb/UserMsgBox.h> #include <rdr/InStream.h> diff --git a/common/rfb/ClientParams.cxx b/common/rfb/ClientParams.cxx new file mode 100644 index 00000000..2f8783bb --- /dev/null +++ b/common/rfb/ClientParams.cxx @@ -0,0 +1,178 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * Copyright 2014-2018 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#include <rfb/Exception.h> +#include <rfb/encodings.h> +#include <rfb/ledStates.h> +#include <rfb/ClientParams.h> + +using namespace rfb; + +ClientParams::ClientParams() + : majorVersion(0), minorVersion(0), + compressLevel(2), qualityLevel(-1), fineQualityLevel(-1), + subsampling(subsampleUndefined), + width_(0), height_(0), name_(0), + ledState_(ledUnknown) +{ + setName(""); + cursor_ = new Cursor(0, 0, Point(), NULL); +} + +ClientParams::~ClientParams() +{ + delete [] name_; + delete cursor_; +} + +void ClientParams::setDimensions(int width, int height) +{ + ScreenSet layout; + layout.add_screen(rfb::Screen(0, 0, 0, width, height, 0)); + setDimensions(width, height, layout); +} + +void ClientParams::setDimensions(int width, int height, const ScreenSet& layout) +{ + if (!layout.validate(width, height)) + throw Exception("Attempted to configure an invalid screen layout"); + + width_ = width; + height_ = height; + screenLayout_ = layout; +} + +void ClientParams::setPF(const PixelFormat& pf) +{ + pf_ = pf; + + if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) + throw Exception("setPF: not 8, 16 or 32 bpp?"); +} + +void ClientParams::setName(const char* name) +{ + delete [] name_; + name_ = strDup(name); +} + +void ClientParams::setCursor(const Cursor& other) +{ + delete cursor_; + cursor_ = new Cursor(other); +} + +bool ClientParams::supportsEncoding(rdr::S32 encoding) const +{ + return encodings_.count(encoding) != 0; +} + +void ClientParams::setEncodings(int nEncodings, const rdr::S32* encodings) +{ + compressLevel = -1; + qualityLevel = -1; + fineQualityLevel = -1; + subsampling = subsampleUndefined; + + encodings_.clear(); + encodings_.insert(encodingRaw); + + for (int i = nEncodings-1; i >= 0; i--) { + switch (encodings[i]) { + case pseudoEncodingSubsamp1X: + subsampling = subsampleNone; + break; + case pseudoEncodingSubsampGray: + subsampling = subsampleGray; + break; + case pseudoEncodingSubsamp2X: + subsampling = subsample2X; + break; + case pseudoEncodingSubsamp4X: + subsampling = subsample4X; + break; + case pseudoEncodingSubsamp8X: + subsampling = subsample8X; + break; + case pseudoEncodingSubsamp16X: + subsampling = subsample16X; + break; + } + + if (encodings[i] >= pseudoEncodingCompressLevel0 && + encodings[i] <= pseudoEncodingCompressLevel9) + compressLevel = encodings[i] - pseudoEncodingCompressLevel0; + + if (encodings[i] >= pseudoEncodingQualityLevel0 && + encodings[i] <= pseudoEncodingQualityLevel9) + qualityLevel = encodings[i] - pseudoEncodingQualityLevel0; + + if (encodings[i] >= pseudoEncodingFineQualityLevel0 && + encodings[i] <= pseudoEncodingFineQualityLevel100) + fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0; + + encodings_.insert(encodings[i]); + } +} + +void ClientParams::setLEDState(unsigned int state) +{ + ledState_ = state; +} + +bool ClientParams::supportsLocalCursor() const +{ + if (supportsEncoding(pseudoEncodingCursorWithAlpha)) + return true; + if (supportsEncoding(pseudoEncodingCursor)) + return true; + if (supportsEncoding(pseudoEncodingXCursor)) + return true; + return false; +} + +bool ClientParams::supportsDesktopSize() const +{ + if (supportsEncoding(pseudoEncodingExtendedDesktopSize)) + return true; + if (supportsEncoding(pseudoEncodingDesktopSize)) + return true; + return false; +} + +bool ClientParams::supportsLEDState() const +{ + if (supportsEncoding(pseudoEncodingLEDState)) + return true; + return false; +} + +bool ClientParams::supportsFence() const +{ + if (supportsEncoding(pseudoEncodingFence)) + return true; + return false; +} + +bool ClientParams::supportsContinuousUpdates() const +{ + if (supportsEncoding(pseudoEncodingContinuousUpdates)) + return true; + return false; +} diff --git a/common/rfb/ConnParams.h b/common/rfb/ClientParams.h index b3222936..f7a7044b 100644 --- a/common/rfb/ConnParams.h +++ b/common/rfb/ClientParams.h @@ -1,5 +1,5 @@ /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB + * Copyright 2014-2018 Pierre Ossman for Cendio AB * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,11 +17,11 @@ * USA. */ // -// ConnParams - structure containing the connection parameters. +// ClientParams - structure describing the current state of the remote client // -#ifndef __RFB_CONNPARAMS_H__ -#define __RFB_CONNPARAMS_H__ +#ifndef __RFB_CLIENTPARAMS_H__ +#define __RFB_CLIENTPARAMS_H__ #include <set> @@ -30,8 +30,6 @@ #include <rfb/PixelFormat.h> #include <rfb/ScreenSet.h> -namespace rdr { class InStream; } - namespace rfb { const int subsampleUndefined = -1; @@ -42,13 +40,10 @@ namespace rfb { const int subsample8X = 4; const int subsample16X = 5; - class ConnParams { + class ClientParams { public: - ConnParams(); - ~ConnParams(); - - bool readVersion(rdr::InStream* is, bool* done); - void writeVersion(rdr::OutStream* os); + ClientParams(); + ~ClientParams(); int majorVersion; int minorVersion; @@ -67,9 +62,11 @@ namespace rfb { return !beforeVersion(major,minor+1); } - int width; - int height; - ScreenSet screenLayout; + const int width() const { return width_; } + const int height() const { return height_; } + const ScreenSet& screenLayout() const { return screenLayout_; } + void setDimensions(int width, int height); + void setDimensions(int width, int height, const ScreenSet& layout); const PixelFormat& pf() const { return pf_; } void setPF(const PixelFormat& pf); @@ -87,21 +84,13 @@ namespace rfb { unsigned int ledState() { return ledState_; } void setLEDState(unsigned int state); - bool useCopyRect; - - bool supportsLocalCursor; - bool supportsLocalXCursor; - bool supportsLocalCursorWithAlpha; - bool supportsDesktopResize; - bool supportsExtendedDesktopSize; - bool supportsDesktopRename; - bool supportsLastRect; - bool supportsLEDState; - bool supportsQEMUKeyEvent; - - bool supportsSetDesktopSize; - bool supportsFence; - bool supportsContinuousUpdates; + // Wrappers to check for functionality rather than specific + // encodings + bool supportsLocalCursor() const; + bool supportsDesktopSize() const; + bool supportsLEDState() const; + bool supportsFence() const; + bool supportsContinuousUpdates() const; int compressLevel; int qualityLevel; @@ -110,12 +99,14 @@ namespace rfb { private: + int width_; + int height_; + ScreenSet screenLayout_; + PixelFormat pf_; char* name_; Cursor* cursor_; std::set<rdr::S32> encodings_; - char verStr[13]; - int verStrPos; unsigned int ledState_; }; } diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx deleted file mode 100644 index 80b4a5ac..00000000 --- a/common/rfb/ConnParams.cxx +++ /dev/null @@ -1,200 +0,0 @@ -/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. - * Copyright (C) 2011 D. R. Commander. All Rights Reserved. - * Copyright 2014 Pierre Ossman for Cendio AB - * - * This is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this software; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - * USA. - */ -#include <stdio.h> -#include <rdr/InStream.h> -#include <rdr/OutStream.h> -#include <rfb/Exception.h> -#include <rfb/encodings.h> -#include <rfb/ledStates.h> -#include <rfb/ConnParams.h> -#include <rfb/util.h> - -using namespace rfb; - -ConnParams::ConnParams() - : majorVersion(0), minorVersion(0), - width(0), height(0), useCopyRect(false), - supportsLocalCursor(false), supportsLocalXCursor(false), - supportsLocalCursorWithAlpha(false), - supportsDesktopResize(false), supportsExtendedDesktopSize(false), - supportsDesktopRename(false), supportsLastRect(false), - supportsLEDState(false), supportsQEMUKeyEvent(false), - supportsSetDesktopSize(false), supportsFence(false), - supportsContinuousUpdates(false), - compressLevel(2), qualityLevel(-1), fineQualityLevel(-1), - subsampling(subsampleUndefined), name_(0), verStrPos(0), - ledState_(ledUnknown) -{ - setName(""); - cursor_ = new Cursor(0, 0, Point(), NULL); -} - -ConnParams::~ConnParams() -{ - delete [] name_; - delete cursor_; -} - -bool ConnParams::readVersion(rdr::InStream* is, bool* done) -{ - if (verStrPos >= 12) return false; - while (is->checkNoWait(1) && verStrPos < 12) { - verStr[verStrPos++] = is->readU8(); - } - - if (verStrPos < 12) { - *done = false; - return true; - } - *done = true; - verStr[12] = 0; - return (sscanf(verStr, "RFB %03d.%03d\n", &majorVersion,&minorVersion) == 2); -} - -void ConnParams::writeVersion(rdr::OutStream* os) -{ - char str[13]; - sprintf(str, "RFB %03d.%03d\n", majorVersion, minorVersion); - os->writeBytes(str, 12); - os->flush(); -} - -void ConnParams::setPF(const PixelFormat& pf) -{ - pf_ = pf; - - if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) - throw Exception("setPF: not 8, 16 or 32 bpp?"); -} - -void ConnParams::setName(const char* name) -{ - delete [] name_; - name_ = strDup(name); -} - -void ConnParams::setCursor(const Cursor& other) -{ - delete cursor_; - cursor_ = new Cursor(other); -} - -bool ConnParams::supportsEncoding(rdr::S32 encoding) const -{ - return encodings_.count(encoding) != 0; -} - -void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings) -{ - useCopyRect = false; - supportsLocalCursor = false; - supportsLocalCursorWithAlpha = false; - supportsDesktopResize = false; - supportsExtendedDesktopSize = false; - supportsLocalXCursor = false; - supportsLastRect = false; - supportsQEMUKeyEvent = false; - compressLevel = -1; - qualityLevel = -1; - fineQualityLevel = -1; - subsampling = subsampleUndefined; - - encodings_.clear(); - encodings_.insert(encodingRaw); - - for (int i = nEncodings-1; i >= 0; i--) { - switch (encodings[i]) { - case encodingCopyRect: - useCopyRect = true; - break; - case pseudoEncodingCursor: - supportsLocalCursor = true; - break; - case pseudoEncodingXCursor: - supportsLocalXCursor = true; - break; - case pseudoEncodingCursorWithAlpha: - supportsLocalCursorWithAlpha = true; - break; - case pseudoEncodingDesktopSize: - supportsDesktopResize = true; - break; - case pseudoEncodingExtendedDesktopSize: - supportsExtendedDesktopSize = true; - break; - case pseudoEncodingDesktopName: - supportsDesktopRename = true; - break; - case pseudoEncodingLastRect: - supportsLastRect = true; - break; - case pseudoEncodingLEDState: - supportsLEDState = true; - break; - case pseudoEncodingQEMUKeyEvent: - supportsQEMUKeyEvent = true; - break; - case pseudoEncodingFence: - supportsFence = true; - break; - case pseudoEncodingContinuousUpdates: - supportsContinuousUpdates = true; - break; - case pseudoEncodingSubsamp1X: - subsampling = subsampleNone; - break; - case pseudoEncodingSubsampGray: - subsampling = subsampleGray; - break; - case pseudoEncodingSubsamp2X: - subsampling = subsample2X; - break; - case pseudoEncodingSubsamp4X: - subsampling = subsample4X; - break; - case pseudoEncodingSubsamp8X: - subsampling = subsample8X; - break; - case pseudoEncodingSubsamp16X: - subsampling = subsample16X; - break; - } - - if (encodings[i] >= pseudoEncodingCompressLevel0 && - encodings[i] <= pseudoEncodingCompressLevel9) - compressLevel = encodings[i] - pseudoEncodingCompressLevel0; - - if (encodings[i] >= pseudoEncodingQualityLevel0 && - encodings[i] <= pseudoEncodingQualityLevel9) - qualityLevel = encodings[i] - pseudoEncodingQualityLevel0; - - if (encodings[i] >= pseudoEncodingFineQualityLevel0 && - encodings[i] <= pseudoEncodingFineQualityLevel100) - fineQualityLevel = encodings[i] - pseudoEncodingFineQualityLevel0; - - if (encodings[i] > 0) - encodings_.insert(encodings[i]); - } -} - -void ConnParams::setLEDState(unsigned int state) -{ - ledState_ = state; -} diff --git a/common/rfb/CopyRectDecoder.cxx b/common/rfb/CopyRectDecoder.cxx index 23949a8b..ecf50323 100644 --- a/common/rfb/CopyRectDecoder.cxx +++ b/common/rfb/CopyRectDecoder.cxx @@ -32,7 +32,7 @@ CopyRectDecoder::~CopyRectDecoder() } void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os) + const ServerParams& server, rdr::OutStream* os) { os->copyBytes(is, 4); } @@ -41,21 +41,21 @@ void CopyRectDecoder::readRect(const Rect& r, rdr::InStream* is, void CopyRectDecoder::getAffectedRegion(const Rect& rect, const void* buffer, size_t buflen, - const ConnParams& cp, + const ServerParams& server, Region* region) { rdr::MemInStream is(buffer, buflen); int srcX = is.readU16(); int srcY = is.readU16(); - Decoder::getAffectedRegion(rect, buffer, buflen, cp, region); + Decoder::getAffectedRegion(rect, buffer, buflen, server, region); region->assign_union(Region(rect.translate(Point(srcX-rect.tl.x, srcY-rect.tl.y)))); } void CopyRectDecoder::decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { rdr::MemInStream is(buffer, buflen); diff --git a/common/rfb/CopyRectDecoder.h b/common/rfb/CopyRectDecoder.h index 1d2ce53b..546266e1 100644 --- a/common/rfb/CopyRectDecoder.h +++ b/common/rfb/CopyRectDecoder.h @@ -27,12 +27,12 @@ namespace rfb { CopyRectDecoder(); virtual ~CopyRectDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os); + const ServerParams& server, rdr::OutStream* os); virtual void getAffectedRegion(const Rect& rect, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, Region* region); virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); }; } diff --git a/common/rfb/DecodeManager.cxx b/common/rfb/DecodeManager.cxx index c509db09..98b6e790 100644 --- a/common/rfb/DecodeManager.cxx +++ b/common/rfb/DecodeManager.cxx @@ -132,9 +132,9 @@ void DecodeManager::decodeRect(const Rect& r, int encoding, if (threads.empty()) { bufferStream = freeBuffers.front(); bufferStream->clear(); - decoder->readRect(r, conn->getInStream(), conn->cp, bufferStream); + decoder->readRect(r, conn->getInStream(), conn->server, bufferStream); decoder->decodeRect(r, bufferStream->data(), bufferStream->length(), - conn->cp, pb); + conn->server, pb); return; } @@ -155,7 +155,7 @@ void DecodeManager::decodeRect(const Rect& r, int encoding, // Read the rect bufferStream->clear(); - decoder->readRect(r, conn->getInStream(), conn->cp, bufferStream); + decoder->readRect(r, conn->getInStream(), conn->server, bufferStream); // Then try to put it on the queue entry = new QueueEntry; @@ -164,12 +164,12 @@ void DecodeManager::decodeRect(const Rect& r, int encoding, entry->rect = r; entry->encoding = encoding; entry->decoder = decoder; - entry->cp = &conn->cp; + entry->server = &conn->server; entry->pb = pb; entry->bufferStream = bufferStream; decoder->getAffectedRegion(r, bufferStream->data(), - bufferStream->length(), conn->cp, + bufferStream->length(), conn->server, &entry->affectedRegion); queueMutex->lock(); @@ -276,7 +276,7 @@ void DecodeManager::DecodeThread::worker() try { entry->decoder->decodeRect(entry->rect, entry->bufferStream->data(), entry->bufferStream->length(), - *entry->cp, entry->pb); + *entry->server, entry->pb); } catch (rdr::Exception& e) { manager->setThreadException(e); } catch(...) { @@ -346,7 +346,7 @@ DecodeManager::QueueEntry* DecodeManager::DecodeThread::findEntry() (*iter2)->rect, (*iter2)->bufferStream->data(), (*iter2)->bufferStream->length(), - *entry->cp)) + *entry->server)) goto next; } } diff --git a/common/rfb/DecodeManager.h b/common/rfb/DecodeManager.h index 2098063e..058d8240 100644 --- a/common/rfb/DecodeManager.h +++ b/common/rfb/DecodeManager.h @@ -65,7 +65,7 @@ namespace rfb { Rect rect; int encoding; Decoder* decoder; - const ConnParams* cp; + const ServerParams* server; ModifiablePixelBuffer* pb; rdr::MemOutStream* bufferStream; Region affectedRegion; diff --git a/common/rfb/Decoder.cxx b/common/rfb/Decoder.cxx index 370e1f9a..9827a732 100644 --- a/common/rfb/Decoder.cxx +++ b/common/rfb/Decoder.cxx @@ -38,7 +38,7 @@ Decoder::~Decoder() } void Decoder::getAffectedRegion(const Rect& rect, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, Region* region) { region->reset(rect); @@ -47,7 +47,7 @@ void Decoder::getAffectedRegion(const Rect& rect, const void* buffer, bool Decoder::doRectsConflict(const Rect& rectA, const void* bufferA, size_t buflenA, const Rect& rectB, const void* bufferB, size_t buflenB, - const ConnParams& cp) + const ServerParams& server) { return false; } diff --git a/common/rfb/Decoder.h b/common/rfb/Decoder.h index 86ee4ef8..e074f3ec 100644 --- a/common/rfb/Decoder.h +++ b/common/rfb/Decoder.h @@ -25,7 +25,7 @@ namespace rdr { } namespace rfb { - class ConnParams; + class ServerParams; class ModifiablePixelBuffer; class Region; @@ -53,7 +53,7 @@ namespace rfb { // make it easier to decode. This function will always be called in // a serial manner on the main thread. virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os)=0; + const ServerParams& server, rdr::OutStream* os)=0; // These functions will be called from any of the worker threads. // A lock will be held whilst these are called so it is safe to @@ -63,7 +63,7 @@ namespace rfb { // be either read from or written do when decoding this rect. The // default implementation simply returns the given rectangle. virtual void getAffectedRegion(const Rect& rect, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, Region* region); // doesRectsConflict() determines if two rectangles must be decoded @@ -75,14 +75,14 @@ namespace rfb { const Rect& rectB, const void* bufferB, size_t buflenB, - const ConnParams& cp); + const ServerParams& server); // decodeRect() decodes the given rectangle with data from the // given buffer, onto the ModifiablePixelBuffer. The PixelFormat of // the PixelBuffer might not match the ConnParams and it is up to // the decoder to do any necessary conversion. virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb)=0; public: diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 02128f7f..735be072 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -325,6 +325,9 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, changed = changed_; + if (!conn->client.supportsEncoding(encodingCopyRect)) + changed.assign_union(copied); + /* * We need to render the cursor seperately as it has its own * magical pixel buffer, so split it out from the changed region. @@ -334,7 +337,7 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, changed.assign_subtract(renderedCursor->getEffectiveRect()); } - if (conn->cp.supportsLastRect) + if (conn->client.supportsEncoding(pseudoEncodingLastRect)) nRects = 0xFFFF; else { nRects = copied.numRects(); @@ -344,13 +347,14 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, conn->writer()->writeFramebufferUpdateStart(nRects); - writeCopyRects(copied, copyDelta); + if (conn->client.supportsEncoding(encodingCopyRect)) + writeCopyRects(copied, copyDelta); /* * We start by searching for solid rects, which are then removed * from the changed region. */ - if (conn->cp.supportsLastRect) + if (conn->client.supportsEncoding(pseudoEncodingLastRect)) writeSolidRects(&changed, pb); writeRects(changed, pb); @@ -373,7 +377,7 @@ void EncodeManager::prepareEncoders(bool allowLossy) solid = bitmap = bitmapRLE = encoderRaw; indexed = indexedRLE = fullColour = encoderRaw; - allowJPEG = conn->cp.pf().bpp >= 16; + allowJPEG = conn->client.pf().bpp >= 16; if (!allowLossy) { if (encoders[encoderTightJPEG]->losslessQuality == -1) allowJPEG = false; @@ -447,7 +451,7 @@ void EncodeManager::prepareEncoders(bool allowLossy) } // JPEG is the only encoder that can reduce things to grayscale - if ((conn->cp.subsampling == subsampleGray) && + if ((conn->client.subsampling == subsampleGray) && encoders[encoderTightJPEG]->isSupported() && allowLossy) { solid = bitmap = bitmapRLE = encoderTightJPEG; indexed = indexedRLE = fullColour = encoderTightJPEG; @@ -465,14 +469,14 @@ void EncodeManager::prepareEncoders(bool allowLossy) encoder = encoders[*iter]; - encoder->setCompressLevel(conn->cp.compressLevel); + encoder->setCompressLevel(conn->client.compressLevel); if (allowLossy) { - encoder->setQualityLevel(conn->cp.qualityLevel); - encoder->setFineQualityLevel(conn->cp.fineQualityLevel, - conn->cp.subsampling); + encoder->setQualityLevel(conn->client.qualityLevel); + encoder->setFineQualityLevel(conn->client.fineQualityLevel, + conn->client.subsampling); } else { - int level = __rfbmax(conn->cp.qualityLevel, + int level = __rfbmax(conn->client.qualityLevel, encoder->losslessQuality); encoder->setQualityLevel(level); encoder->setFineQualityLevel(-1, subsampleUndefined); @@ -575,7 +579,7 @@ Encoder *EncodeManager::startRect(const Rect& rect, int type) stats[klass][activeType].rects++; stats[klass][activeType].pixels += rect.area(); - equiv = 12 + rect.area() * (conn->cp.pf().bpp/8); + equiv = 12 + rect.area() * (conn->client.pf().bpp/8); stats[klass][activeType].equivalent += equiv; encoder = encoders[klass]; @@ -623,7 +627,7 @@ void EncodeManager::writeCopyRects(const Region& copied, const Point& delta) copyStats.rects++; copyStats.pixels += rect->area(); - equiv = 12 + rect->area() * (conn->cp.pf().bpp/8); + equiv = 12 + rect->area() * (conn->client.pf().bpp/8); copyStats.equivalent += equiv; conn->writer()->writeCopyRect(*rect, rect->tl.x - delta.x, @@ -710,11 +714,11 @@ void EncodeManager::findSolidRect(const Rect& rect, Region *changed, rdr::U32 _buffer2; rdr::U8* converted = (rdr::U8*)&_buffer2; - conn->cp.pf().bufferFromBuffer(converted, pb->getPF(), + conn->client.pf().bufferFromBuffer(converted, pb->getPF(), colourValue, 1); encoder->writeSolidRect(erp.width(), erp.height(), - conn->cp.pf(), converted); + conn->client.pf(), converted); } endRect(); @@ -808,10 +812,10 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb) // compression setting means spending less effort in building // a palette. It might be that they figured the increase in // zlib setting compensated for the loss. - if (conn->cp.compressLevel == -1) + if (conn->client.compressLevel == -1) divisor = 2 * 8; else - divisor = conn->cp.compressLevel * 8; + divisor = conn->client.compressLevel * 8; if (divisor < 4) divisor = 4; @@ -819,7 +823,7 @@ void EncodeManager::writeSubRect(const Rect& rect, const PixelBuffer *pb) // Special exception inherited from the Tight encoder if (activeEncoders[encoderFullColour] == encoderTightJPEG) { - if ((conn->cp.compressLevel != -1) && (conn->cp.compressLevel < 2)) + if ((conn->client.compressLevel != -1) && (conn->client.compressLevel < 2)) maxColours = 24; else maxColours = 96; @@ -992,8 +996,8 @@ PixelBuffer* EncodeManager::preparePixelBuffer(const Rect& rect, int stride; // Do wo need to convert the data? - if (convert && !conn->cp.pf().equal(pb->getPF())) { - convertedPixelBuffer.setPF(conn->cp.pf()); + if (convert && !conn->client.pf().equal(pb->getPF())) { + convertedPixelBuffer.setPF(conn->client.pf()); convertedPixelBuffer.setSize(rect.width(), rect.height()); buffer = pb->getBuffer(rect, &stride); diff --git a/common/rfb/HextileDecoder.cxx b/common/rfb/HextileDecoder.cxx index eae00408..742dfb28 100644 --- a/common/rfb/HextileDecoder.cxx +++ b/common/rfb/HextileDecoder.cxx @@ -20,7 +20,7 @@ #include <rdr/MemInStream.h> #include <rdr/OutStream.h> -#include <rfb/ConnParams.h> +#include <rfb/ServerParams.h> #include <rfb/PixelBuffer.h> #include <rfb/HextileDecoder.h> @@ -45,12 +45,12 @@ HextileDecoder::~HextileDecoder() } void HextileDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os) + const ServerParams& server, rdr::OutStream* os) { Rect t; size_t bytesPerPixel; - bytesPerPixel = cp.pf().bpp/8; + bytesPerPixel = server.pf().bpp/8; for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) { @@ -91,11 +91,11 @@ void HextileDecoder::readRect(const Rect& r, rdr::InStream* is, } void HextileDecoder::decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { rdr::MemInStream is(buffer, buflen); - const PixelFormat& pf = cp.pf(); + const PixelFormat& pf = server.pf(); switch (pf.bpp) { case 8: hextileDecode8 (r, &is, pf, pb); break; case 16: hextileDecode16(r, &is, pf, pb); break; diff --git a/common/rfb/HextileDecoder.h b/common/rfb/HextileDecoder.h index bdc76bcc..b8515bfc 100644 --- a/common/rfb/HextileDecoder.h +++ b/common/rfb/HextileDecoder.h @@ -27,9 +27,9 @@ namespace rfb { HextileDecoder(); virtual ~HextileDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os); + const ServerParams& server, rdr::OutStream* os); virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); }; } diff --git a/common/rfb/HextileEncoder.cxx b/common/rfb/HextileEncoder.cxx index 47e52510..1e20eb92 100644 --- a/common/rfb/HextileEncoder.cxx +++ b/common/rfb/HextileEncoder.cxx @@ -55,7 +55,7 @@ HextileEncoder::~HextileEncoder() bool HextileEncoder::isSupported() { - return conn->cp.supportsEncoding(encodingHextile); + return conn->client.supportsEncoding(encodingHextile); } void HextileEncoder::writeRect(const PixelBuffer* pb, const Palette& palette) diff --git a/common/rfb/JpegCompressor.cxx b/common/rfb/JpegCompressor.cxx index 27cb9de3..23b8f8cf 100644 --- a/common/rfb/JpegCompressor.cxx +++ b/common/rfb/JpegCompressor.cxx @@ -22,7 +22,7 @@ #include <rdr/Exception.h> #include <rfb/Rect.h> #include <rfb/PixelFormat.h> -#include <rfb/ConnParams.h> +#include <rfb/ClientParams.h> #include <stdio.h> extern "C" { diff --git a/common/rfb/Logger.cxx b/common/rfb/Logger.cxx index 3daf2486..ad10a4cf 100644 --- a/common/rfb/Logger.cxx +++ b/common/rfb/Logger.cxx @@ -47,7 +47,16 @@ void Logger::write(int level, const char *logname, const char* format, char buf1[4096]; vsnprintf(buf1, sizeof(buf1)-1, format, ap); buf1[sizeof(buf1)-1] = 0; - write(level, logname, buf1); + char *buf = buf1; + while (true) { + char *end = strchr(buf, '\n'); + if (end) + *end = '\0'; + write(level, logname, buf); + if (!end) + break; + buf = end + 1; + } } void diff --git a/common/rfb/RREDecoder.cxx b/common/rfb/RREDecoder.cxx index 218c9b0b..70a7ddb2 100644 --- a/common/rfb/RREDecoder.cxx +++ b/common/rfb/RREDecoder.cxx @@ -20,7 +20,7 @@ #include <rdr/MemInStream.h> #include <rdr/OutStream.h> -#include <rfb/ConnParams.h> +#include <rfb/ServerParams.h> #include <rfb/PixelBuffer.h> #include <rfb/RREDecoder.h> @@ -45,22 +45,22 @@ RREDecoder::~RREDecoder() } void RREDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os) + const ServerParams& server, rdr::OutStream* os) { rdr::U32 numRects; numRects = is->readU32(); os->writeU32(numRects); - os->copyBytes(is, cp.pf().bpp/8 + numRects * (cp.pf().bpp/8 + 8)); + os->copyBytes(is, server.pf().bpp/8 + numRects * (server.pf().bpp/8 + 8)); } void RREDecoder::decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { rdr::MemInStream is(buffer, buflen); - const PixelFormat& pf = cp.pf(); + const PixelFormat& pf = server.pf(); switch (pf.bpp) { case 8: rreDecode8 (r, &is, pf, pb); break; case 16: rreDecode16(r, &is, pf, pb); break; diff --git a/common/rfb/RREDecoder.h b/common/rfb/RREDecoder.h index f89fef4a..f47eddad 100644 --- a/common/rfb/RREDecoder.h +++ b/common/rfb/RREDecoder.h @@ -27,9 +27,9 @@ namespace rfb { RREDecoder(); virtual ~RREDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os); + const ServerParams& server, rdr::OutStream* os); virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); }; } diff --git a/common/rfb/RREEncoder.cxx b/common/rfb/RREEncoder.cxx index 7287e7eb..83585490 100644 --- a/common/rfb/RREEncoder.cxx +++ b/common/rfb/RREEncoder.cxx @@ -47,7 +47,7 @@ RREEncoder::~RREEncoder() bool RREEncoder::isSupported() { - return conn->cp.supportsEncoding(encodingRRE); + return conn->client.supportsEncoding(encodingRRE); } void RREEncoder::writeRect(const PixelBuffer* pb, const Palette& palette) diff --git a/common/rfb/RawDecoder.cxx b/common/rfb/RawDecoder.cxx index ec0c68ee..61235047 100644 --- a/common/rfb/RawDecoder.cxx +++ b/common/rfb/RawDecoder.cxx @@ -19,7 +19,7 @@ #include <assert.h> #include <rdr/OutStream.h> -#include <rfb/ConnParams.h> +#include <rfb/ServerParams.h> #include <rfb/PixelBuffer.h> #include <rfb/RawDecoder.h> @@ -34,15 +34,15 @@ RawDecoder::~RawDecoder() } void RawDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os) + const ServerParams& server, rdr::OutStream* os) { - os->copyBytes(is, r.area() * (cp.pf().bpp/8)); + os->copyBytes(is, r.area() * (server.pf().bpp/8)); } void RawDecoder::decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { - assert(buflen >= (size_t)r.area() * (cp.pf().bpp/8)); - pb->imageRect(cp.pf(), r, buffer); + assert(buflen >= (size_t)r.area() * (server.pf().bpp/8)); + pb->imageRect(server.pf(), r, buffer); } diff --git a/common/rfb/RawDecoder.h b/common/rfb/RawDecoder.h index 21ea738b..4ab80717 100644 --- a/common/rfb/RawDecoder.h +++ b/common/rfb/RawDecoder.h @@ -26,9 +26,9 @@ namespace rfb { RawDecoder(); virtual ~RawDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os); + const ServerParams& server, rdr::OutStream* os); virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); }; } diff --git a/common/rfb/SConnection.cxx b/common/rfb/SConnection.cxx index a79abeef..690653a2 100644 --- a/common/rfb/SConnection.cxx +++ b/common/rfb/SConnection.cxx @@ -59,7 +59,7 @@ SConnection::SConnection() if (rfb::Server::protocol3_3) defaultMinorVersion = 3; - cp.setVersion(defaultMajorVersion, defaultMinorVersion); + client.setVersion(defaultMajorVersion, defaultMinorVersion); } SConnection::~SConnection() @@ -80,7 +80,12 @@ void SConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_) void SConnection::initialiseProtocol() { - cp.writeVersion(os); + char str[13]; + + sprintf(str, "RFB %03d.%03d\n", defaultMajorVersion, defaultMinorVersion); + os->writeBytes(str, 12); + os->flush(); + state_ = RFBSTATE_PROTOCOL_VERSION; } @@ -104,35 +109,47 @@ void SConnection::processMsg() void SConnection::processVersionMsg() { + char verStr[13]; + int majorVersion; + int minorVersion; + vlog.debug("reading protocol version"); - bool done; - if (!cp.readVersion(is, &done)) { + + if (!is->checkNoWait(12)) + return; + + is->readBytes(verStr, 12); + verStr[12] = '\0'; + + if (sscanf(verStr, "RFB %03d.%03d\n", + &majorVersion, &minorVersion) != 2) { state_ = RFBSTATE_INVALID; throw Exception("reading version failed: not an RFB client?"); } - if (!done) return; + + client.setVersion(majorVersion, minorVersion); vlog.info("Client needs protocol version %d.%d", - cp.majorVersion, cp.minorVersion); + client.majorVersion, client.minorVersion); - if (cp.majorVersion != 3) { + if (client.majorVersion != 3) { // unknown protocol version throwConnFailedException("Client needs protocol version %d.%d, server has %d.%d", - cp.majorVersion, cp.minorVersion, + client.majorVersion, client.minorVersion, defaultMajorVersion, defaultMinorVersion); } - if (cp.minorVersion != 3 && cp.minorVersion != 7 && cp.minorVersion != 8) { + if (client.minorVersion != 3 && client.minorVersion != 7 && client.minorVersion != 8) { vlog.error("Client uses unofficial protocol version %d.%d", - cp.majorVersion,cp.minorVersion); - if (cp.minorVersion >= 8) - cp.minorVersion = 8; - else if (cp.minorVersion == 7) - cp.minorVersion = 7; + client.majorVersion,client.minorVersion); + if (client.minorVersion >= 8) + client.minorVersion = 8; + else if (client.minorVersion == 7) + client.minorVersion = 7; else - cp.minorVersion = 3; + client.minorVersion = 3; vlog.error("Assuming compatibility with version %d.%d", - cp.majorVersion,cp.minorVersion); + client.majorVersion,client.minorVersion); } versionReceived(); @@ -141,7 +158,7 @@ void SConnection::processVersionMsg() std::list<rdr::U8>::iterator i; secTypes = security.GetEnabledSecTypes(); - if (cp.isVersion(3,3)) { + if (client.isVersion(3,3)) { // cope with legacy 3.3 client only if "no authentication" or "vnc // authentication" is supported. @@ -150,7 +167,7 @@ void SConnection::processVersionMsg() } if (i == secTypes.end()) { throwConnFailedException("No supported security type for %d.%d client", - cp.majorVersion, cp.minorVersion); + client.majorVersion, client.minorVersion); } os->writeU32(*i); @@ -220,7 +237,7 @@ void SConnection::processSecurityMsg() } catch (AuthFailureException& e) { vlog.error("AuthFailureException: %s", e.str()); os->writeU32(secResultFailed); - if (!cp.beforeVersion(3,8)) // 3.8 onwards have failure message + if (!client.beforeVersion(3,8)) // 3.8 onwards have failure message os->writeString(e.str()); os->flush(); throw; @@ -245,7 +262,7 @@ void SConnection::throwConnFailedException(const char* format, ...) vlog.info("Connection failed: %s", str); if (state_ == RFBSTATE_PROTOCOL_VERSION) { - if (cp.majorVersion == 3 && cp.minorVersion == 3) { + if (client.majorVersion == 3 && client.minorVersion == 3) { os->writeU32(0); os->writeString(str); os->flush(); @@ -308,12 +325,12 @@ void SConnection::approveConnection(bool accept, const char* reason) if (state_ != RFBSTATE_QUERYING) throw Exception("SConnection::approveConnection: invalid state"); - if (!cp.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) { + if (!client.beforeVersion(3,8) || ssecurity->getType() != secTypeNone) { if (accept) { os->writeU32(secResultOK); } else { os->writeU32(secResultFailed); - if (!cp.beforeVersion(3,8)) { // 3.8 onwards have failure message + if (!client.beforeVersion(3,8)) { // 3.8 onwards have failure message if (reason) os->writeString(reason); else @@ -326,7 +343,7 @@ void SConnection::approveConnection(bool accept, const char* reason) if (accept) { state_ = RFBSTATE_INITIALISATION; reader_ = new SMsgReader(this, is); - writer_ = new SMsgWriter(&cp, os); + writer_ = new SMsgWriter(&client, os); authSuccess(); } else { state_ = RFBSTATE_INVALID; @@ -339,7 +356,8 @@ void SConnection::approveConnection(bool accept, const char* reason) void SConnection::clientInit(bool shared) { - writer_->writeServerInit(); + writer_->writeServerInit(client.width(), client.height(), + client.pf(), client.name()); state_ = RFBSTATE_NORMAL; } @@ -360,7 +378,7 @@ void SConnection::framebufferUpdateRequest(const Rect& r, bool incremental) { if (!readyForSetColourMapEntries) { readyForSetColourMapEntries = true; - if (!cp.pf().trueColour) { + if (!client.pf().trueColour) { writeFakeColourMap(); } } @@ -388,7 +406,7 @@ void SConnection::writeFakeColourMap(void) rdr::U16 red[256], green[256], blue[256]; for (i = 0;i < 256;i++) - cp.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]); + client.pf().rgbFromPixel(i, &red[i], &green[i], &blue[i]); writer()->writeSetColourMapEntries(0, 256, red, green, blue); } diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx index c38458c3..f952ec2b 100644 --- a/common/rfb/SMsgHandler.cxx +++ b/common/rfb/SMsgHandler.cxx @@ -19,6 +19,7 @@ #include <rfb/Exception.h> #include <rfb/SMsgHandler.h> #include <rfb/ScreenSet.h> +#include <rfb/encodings.h> using namespace rfb; @@ -36,7 +37,7 @@ void SMsgHandler::clientInit(bool shared) void SMsgHandler::setPixelFormat(const PixelFormat& pf) { - cp.setPF(pf); + client.setPF(pf); } void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings) @@ -44,22 +45,22 @@ void SMsgHandler::setEncodings(int nEncodings, const rdr::S32* encodings) bool firstFence, firstContinuousUpdates, firstLEDState, firstQEMUKeyEvent; - firstFence = !cp.supportsFence; - firstContinuousUpdates = !cp.supportsContinuousUpdates; - firstLEDState = !cp.supportsLEDState; - firstQEMUKeyEvent = !cp.supportsQEMUKeyEvent; + firstFence = !client.supportsFence(); + firstContinuousUpdates = !client.supportsContinuousUpdates(); + firstLEDState = !client.supportsLEDState(); + firstQEMUKeyEvent = !client.supportsEncoding(pseudoEncodingQEMUKeyEvent); - cp.setEncodings(nEncodings, encodings); + client.setEncodings(nEncodings, encodings); supportsLocalCursor(); - if (cp.supportsFence && firstFence) + if (client.supportsFence() && firstFence) supportsFence(); - if (cp.supportsContinuousUpdates && firstContinuousUpdates) + if (client.supportsContinuousUpdates() && firstContinuousUpdates) supportsContinuousUpdates(); - if (cp.supportsLEDState && firstLEDState) + if (client.supportsLEDState() && firstLEDState) supportsLEDState(); - if (cp.supportsQEMUKeyEvent && firstQEMUKeyEvent) + if (client.supportsEncoding(pseudoEncodingQEMUKeyEvent) && firstQEMUKeyEvent) supportsQEMUKeyEvent(); } @@ -82,12 +83,3 @@ void SMsgHandler::supportsLEDState() void SMsgHandler::supportsQEMUKeyEvent() { } - -void SMsgHandler::setDesktopSize(int fb_width, int fb_height, - const ScreenSet& layout) -{ - cp.width = fb_width; - cp.height = fb_height; - cp.screenLayout = layout; -} - diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h index 749f0560..8548d911 100644 --- a/common/rfb/SMsgHandler.h +++ b/common/rfb/SMsgHandler.h @@ -25,7 +25,7 @@ #include <rdr/types.h> #include <rfb/PixelFormat.h> -#include <rfb/ConnParams.h> +#include <rfb/ClientParams.h> #include <rfb/InputHandler.h> #include <rfb/ScreenSet.h> @@ -40,8 +40,8 @@ namespace rfb { // The following methods are called as corresponding messages are read. A // derived class should override these methods as desired. Note that for - // the setPixelFormat(), setEncodings() and setDesktopSize() methods, a - // derived class must call on to SMsgHandler's methods. + // the setPixelFormat(), and setEncodings() methods, a derived class must + // call on to SMsgHandler's methods. virtual void clientInit(bool shared); @@ -85,7 +85,7 @@ namespace rfb { // handler will send a pseudo-rect back, signalling server support. virtual void supportsQEMUKeyEvent(); - ConnParams cp; + ClientParams client; }; } #endif diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 3da9413f..a12a6d40 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -22,7 +22,7 @@ #include <rfb/msgTypes.h> #include <rfb/fenceTypes.h> #include <rfb/Exception.h> -#include <rfb/ConnParams.h> +#include <rfb/ClientParams.h> #include <rfb/UpdateTracker.h> #include <rfb/Encoder.h> #include <rfb/SMsgWriter.h> @@ -33,12 +33,10 @@ using namespace rfb; static LogWriter vlog("SMsgWriter"); -SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_) - : cp(cp_), os(os_), +SMsgWriter::SMsgWriter(ClientParams* client_, rdr::OutStream* os_) + : client(client_), os(os_), nRectsInUpdate(0), nRectsInHeader(0), - needSetDesktopSize(false), needExtendedDesktopSize(false), - needSetDesktopName(false), needSetCursor(false), - needSetXCursor(false), needSetCursorWithAlpha(false), + needSetDesktopName(false), needCursor(false), needLEDState(false), needQEMUKeyEvent(false) { } @@ -47,12 +45,13 @@ SMsgWriter::~SMsgWriter() { } -void SMsgWriter::writeServerInit() +void SMsgWriter::writeServerInit(rdr::U16 width, rdr::U16 height, + const PixelFormat& pf, const char* name) { - os->writeU16(cp->width); - os->writeU16(cp->height); - cp->pf().write(os); - os->writeString(cp->name()); + os->writeU16(width); + os->writeU16(height); + pf.write(os); + os->writeString(name); endMsg(); } @@ -90,7 +89,7 @@ void SMsgWriter::writeServerCutText(const char* str, int len) void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) { - if (!cp->supportsFence) + if (!client->supportsEncoding(pseudoEncodingFence)) throw Exception("Client does not support fences"); if (len > 64) throw Exception("Too large fence payload"); @@ -112,116 +111,68 @@ void SMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[]) void SMsgWriter::writeEndOfContinuousUpdates() { - if (!cp->supportsContinuousUpdates) + if (!client->supportsEncoding(pseudoEncodingContinuousUpdates)) throw Exception("Client does not support continuous updates"); startMsg(msgTypeEndOfContinuousUpdates); endMsg(); } -bool SMsgWriter::writeSetDesktopSize() { - if (!cp->supportsDesktopResize) - return false; - - needSetDesktopSize = true; - - return true; -} - -bool SMsgWriter::writeExtendedDesktopSize() { - if (!cp->supportsExtendedDesktopSize) - return false; - - needExtendedDesktopSize = true; - - return true; -} - -bool SMsgWriter::writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, - int fb_width, int fb_height, - const ScreenSet& layout) { +void SMsgWriter::writeDesktopSize(rdr::U16 reason, rdr::U16 result) +{ ExtendedDesktopSizeMsg msg; - if (!cp->supportsExtendedDesktopSize) - return false; + if (!client->supportsEncoding(pseudoEncodingDesktopSize) && + !client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) + throw Exception("Client does not support desktop size changes"); msg.reason = reason; msg.result = result; - msg.fb_width = fb_width; - msg.fb_height = fb_height; - msg.layout = layout; extendedDesktopSizeMsgs.push_back(msg); - - return true; } -bool SMsgWriter::writeSetDesktopName() { - if (!cp->supportsDesktopRename) - return false; - - needSetDesktopName = true; - - return true; -} - -bool SMsgWriter::writeSetCursor() -{ - if (!cp->supportsLocalCursor) - return false; - - needSetCursor = true; - - return true; -} - -bool SMsgWriter::writeSetXCursor() +void SMsgWriter::writeSetDesktopName() { - if (!cp->supportsLocalXCursor) - return false; - - needSetXCursor = true; + if (!client->supportsEncoding(pseudoEncodingDesktopName)) + throw Exception("Client does not support desktop name changes"); - return true; + needSetDesktopName = true; } -bool SMsgWriter::writeSetCursorWithAlpha() +void SMsgWriter::writeCursor() { - if (!cp->supportsLocalCursorWithAlpha) - return false; + if (!client->supportsEncoding(pseudoEncodingCursor) && + !client->supportsEncoding(pseudoEncodingXCursor) && + !client->supportsEncoding(pseudoEncodingCursorWithAlpha)) + throw Exception("Client does not support local cursor"); - needSetCursorWithAlpha = true; - - return true; + needCursor = true; } -bool SMsgWriter::writeLEDState() +void SMsgWriter::writeLEDState() { - if (!cp->supportsLEDState) - return false; - if (cp->ledState() == ledUnknown) - return false; + if (!client->supportsEncoding(pseudoEncodingLEDState)) + throw Exception("Client does not support LED state"); + if (client->ledState() == ledUnknown) + throw Exception("Server has not specified LED state"); needLEDState = true; - - return true; } -bool SMsgWriter::writeQEMUKeyEvent() +void SMsgWriter::writeQEMUKeyEvent() { - if (!cp->supportsQEMUKeyEvent) - return false; + if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent)) + throw Exception("Client does not support QEMU key events"); needQEMUKeyEvent = true; - - return true; } bool SMsgWriter::needFakeUpdate() { if (needSetDesktopName) return true; - if (needSetCursor || needSetXCursor || needSetCursorWithAlpha) + if (needCursor) return true; if (needLEDState) return true; @@ -235,9 +186,7 @@ bool SMsgWriter::needFakeUpdate() bool SMsgWriter::needNoDataUpdate() { - if (needSetDesktopSize) - return true; - if (needExtendedDesktopSize || !extendedDesktopSizeMsgs.empty()) + if (!extendedDesktopSizeMsgs.empty()) return true; return false; @@ -249,12 +198,12 @@ void SMsgWriter::writeNoDataUpdate() nRects = 0; - if (needSetDesktopSize) - nRects++; - if (needExtendedDesktopSize) - nRects++; - if (!extendedDesktopSizeMsgs.empty()) - nRects += extendedDesktopSizeMsgs.size(); + if (!extendedDesktopSizeMsgs.empty()) { + if (client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) + nRects += extendedDesktopSizeMsgs.size(); + else + nRects++; + } writeFramebufferUpdateStart(nRects); writeNoDataRects(); @@ -269,11 +218,7 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects) if (nRects != 0xFFFF) { if (needSetDesktopName) nRects++; - if (needSetCursor) - nRects++; - if (needSetXCursor) - nRects++; - if (needSetCursorWithAlpha) + if (needCursor) nRects++; if (needLEDState) nRects++; @@ -347,56 +292,52 @@ void SMsgWriter::endMsg() void SMsgWriter::writePseudoRects() { - if (needSetCursor) { - const Cursor& cursor = cp->cursor(); - - rdr::U8Array data(cursor.width()*cursor.height() * (cp->pf().bpp/8)); - rdr::U8Array mask(cursor.getMask()); - - const rdr::U8* in; - rdr::U8* out; - - in = cursor.getBuffer(); - out = data.buf; - for (int i = 0;i < cursor.width()*cursor.height();i++) { - cp->pf().bufferFromRGB(out, in, 1); - in += 4; - out += cp->pf().bpp/8; + if (needCursor) { + const Cursor& cursor = client->cursor(); + + if (client->supportsEncoding(pseudoEncodingCursorWithAlpha)) { + writeSetCursorWithAlphaRect(cursor.width(), cursor.height(), + cursor.hotspot().x, cursor.hotspot().y, + cursor.getBuffer()); + } else if (client->supportsEncoding(pseudoEncodingCursor)) { + rdr::U8Array data(cursor.width()*cursor.height() * (client->pf().bpp/8)); + rdr::U8Array mask(cursor.getMask()); + + const rdr::U8* in; + rdr::U8* out; + + in = cursor.getBuffer(); + out = data.buf; + for (int i = 0;i < cursor.width()*cursor.height();i++) { + client->pf().bufferFromRGB(out, in, 1); + in += 4; + out += client->pf().bpp/8; + } + + writeSetCursorRect(cursor.width(), cursor.height(), + cursor.hotspot().x, cursor.hotspot().y, + data.buf, mask.buf); + } else if (client->supportsEncoding(pseudoEncodingXCursor)) { + rdr::U8Array bitmap(cursor.getBitmap()); + rdr::U8Array mask(cursor.getMask()); + + writeSetXCursorRect(cursor.width(), cursor.height(), + cursor.hotspot().x, cursor.hotspot().y, + bitmap.buf, mask.buf); + } else { + throw Exception("Client does not support local cursor"); } - writeSetCursorRect(cursor.width(), cursor.height(), - cursor.hotspot().x, cursor.hotspot().y, - data.buf, mask.buf); - needSetCursor = false; - } - - if (needSetXCursor) { - const Cursor& cursor = cp->cursor(); - rdr::U8Array bitmap(cursor.getBitmap()); - rdr::U8Array mask(cursor.getMask()); - - writeSetXCursorRect(cursor.width(), cursor.height(), - cursor.hotspot().x, cursor.hotspot().y, - bitmap.buf, mask.buf); - needSetXCursor = false; - } - - if (needSetCursorWithAlpha) { - const Cursor& cursor = cp->cursor(); - - writeSetCursorWithAlphaRect(cursor.width(), cursor.height(), - cursor.hotspot().x, cursor.hotspot().y, - cursor.getBuffer()); - needSetCursorWithAlpha = false; + needCursor = false; } if (needSetDesktopName) { - writeSetDesktopNameRect(cp->name()); + writeSetDesktopNameRect(client->name()); needSetDesktopName = false; } if (needLEDState) { - writeLEDStateRect(cp->ledState()); + writeLEDStateRect(client->ledState()); needLEDState = false; } @@ -408,36 +349,30 @@ void SMsgWriter::writePseudoRects() void SMsgWriter::writeNoDataRects() { - // Start with specific ExtendedDesktopSize messages if (!extendedDesktopSizeMsgs.empty()) { - std::list<ExtendedDesktopSizeMsg>::const_iterator ri; - - for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) { - writeExtendedDesktopSizeRect(ri->reason, ri->result, - ri->fb_width, ri->fb_height, ri->layout); + if (client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) { + std::list<ExtendedDesktopSizeMsg>::const_iterator ri; + for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) { + // FIXME: We can probably skip multiple reasonServer entries + writeExtendedDesktopSizeRect(ri->reason, ri->result, + client->width(), client->height(), + client->screenLayout()); + } + } else if (client->supportsEncoding(pseudoEncodingDesktopSize)) { + // Some clients assume this is the last rectangle so don't send anything + // more after this + writeSetDesktopSizeRect(client->width(), client->height()); + } else { + throw Exception("Client does not support desktop size changes"); } extendedDesktopSizeMsgs.clear(); } - - // Send this before SetDesktopSize to make life easier on the clients - if (needExtendedDesktopSize) { - writeExtendedDesktopSizeRect(0, 0, cp->width, cp->height, - cp->screenLayout); - needExtendedDesktopSize = false; - } - - // Some clients assume this is the last rectangle so don't send anything - // more after this - if (needSetDesktopSize) { - writeSetDesktopSizeRect(cp->width, cp->height); - needSetDesktopSize = false; - } } void SMsgWriter::writeSetDesktopSizeRect(int width, int height) { - if (!cp->supportsDesktopResize) + if (!client->supportsEncoding(pseudoEncodingDesktopSize)) throw Exception("Client does not support desktop resize"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeSetDesktopSizeRect: nRects out of sync"); @@ -457,7 +392,7 @@ void SMsgWriter::writeExtendedDesktopSizeRect(rdr::U16 reason, { ScreenSet::const_iterator si; - if (!cp->supportsExtendedDesktopSize) + if (!client->supportsEncoding(pseudoEncodingExtendedDesktopSize)) throw Exception("Client does not support extended desktop resize"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeExtendedDesktopSizeRect: nRects out of sync"); @@ -483,7 +418,7 @@ void SMsgWriter::writeExtendedDesktopSizeRect(rdr::U16 reason, void SMsgWriter::writeSetDesktopNameRect(const char *name) { - if (!cp->supportsDesktopRename) + if (!client->supportsEncoding(pseudoEncodingDesktopName)) throw Exception("Client does not support desktop rename"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeSetDesktopNameRect: nRects out of sync"); @@ -500,7 +435,7 @@ void SMsgWriter::writeSetCursorRect(int width, int height, int hotspotX, int hotspotY, const void* data, const void* mask) { - if (!cp->supportsLocalCursor) + if (!client->supportsEncoding(pseudoEncodingCursor)) throw Exception("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeSetCursorRect: nRects out of sync"); @@ -510,7 +445,7 @@ void SMsgWriter::writeSetCursorRect(int width, int height, os->writeU16(width); os->writeU16(height); os->writeU32(pseudoEncodingCursor); - os->writeBytes(data, width * height * (cp->pf().bpp/8)); + os->writeBytes(data, width * height * (client->pf().bpp/8)); os->writeBytes(mask, (width+7)/8 * height); } @@ -518,7 +453,7 @@ void SMsgWriter::writeSetXCursorRect(int width, int height, int hotspotX, int hotspotY, const void* data, const void* mask) { - if (!cp->supportsLocalXCursor) + if (!client->supportsEncoding(pseudoEncodingXCursor)) throw Exception("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeSetXCursorRect: nRects out of sync"); @@ -544,7 +479,7 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height, int hotspotX, int hotspotY, const rdr::U8* data) { - if (!cp->supportsLocalCursorWithAlpha) + if (!client->supportsEncoding(pseudoEncodingCursorWithAlpha)) throw Exception("Client does not support local cursors"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeSetCursorWithAlphaRect: nRects out of sync"); @@ -570,9 +505,9 @@ void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height, void SMsgWriter::writeLEDStateRect(rdr::U8 state) { - if (!cp->supportsLEDState) + if (!client->supportsEncoding(pseudoEncodingLEDState)) throw Exception("Client does not support LED state updates"); - if (cp->ledState() == ledUnknown) + if (client->ledState() == ledUnknown) throw Exception("Server does not support LED state updates"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeLEDStateRect: nRects out of sync"); @@ -587,7 +522,7 @@ void SMsgWriter::writeLEDStateRect(rdr::U8 state) void SMsgWriter::writeQEMUKeyEventRect() { - if (!cp->supportsQEMUKeyEvent) + if (!client->supportsEncoding(pseudoEncodingQEMUKeyEvent)) throw Exception("Client does not support QEMU extended key events"); if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) throw Exception("SMsgWriter::writeQEMUKeyEventRect: nRects out of sync"); diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index e9859416..80f6de91 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -31,17 +31,19 @@ namespace rdr { class OutStream; } namespace rfb { - class ConnParams; + class ClientParams; + class PixelFormat; struct ScreenSet; class SMsgWriter { public: - SMsgWriter(ConnParams* cp, rdr::OutStream* os); + SMsgWriter(ClientParams* client, rdr::OutStream* os); virtual ~SMsgWriter(); // writeServerInit() must only be called at the appropriate time in the // protocol initialisation. - void writeServerInit(); + void writeServerInit(rdr::U16 width, rdr::U16 height, + const PixelFormat& pf, const char* name); // Methods to write normal protocol messages @@ -63,30 +65,21 @@ namespace rfb { // updates mode. void writeEndOfContinuousUpdates(); - // writeSetDesktopSize() won't actually write immediately, but will + // writeDesktopSize() won't actually write immediately, but will // write the relevant pseudo-rectangle as part of the next update. - bool writeSetDesktopSize(); - // Same thing for the extended version. The first version queues up a - // generic update of the current server state, but the second queues a - // specific message. - bool writeExtendedDesktopSize(); - bool writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result, - int fb_width, int fb_height, - const ScreenSet& layout); + void writeDesktopSize(rdr::U16 reason, rdr::U16 result=0); - bool writeSetDesktopName(); + void writeSetDesktopName(); // Like setDesktopSize, we can't just write out a cursor message // immediately. - bool writeSetCursor(); - bool writeSetXCursor(); - bool writeSetCursorWithAlpha(); + void writeCursor(); // Same for LED state message - bool writeLEDState(); + void writeLEDState(); // And QEMU keyboard event handshake - bool writeQEMUKeyEvent(); + void writeQEMUKeyEvent(); // needFakeUpdate() returns true when an immediate update is needed in // order to flush out pseudo-rectangles to the client. @@ -140,25 +133,19 @@ namespace rfb { void writeLEDStateRect(rdr::U8 state); void writeQEMUKeyEventRect(); - ConnParams* cp; + ClientParams* client; rdr::OutStream* os; int nRectsInUpdate; int nRectsInHeader; - bool needSetDesktopSize; - bool needExtendedDesktopSize; bool needSetDesktopName; - bool needSetCursor; - bool needSetXCursor; - bool needSetCursorWithAlpha; + bool needCursor; bool needLEDState; bool needQEMUKeyEvent; typedef struct { rdr::U16 reason, result; - int fb_width, fb_height; - ScreenSet layout; } ExtendedDesktopSizeMsg; std::list<ExtendedDesktopSizeMsg> extendedDesktopSizeMsgs; diff --git a/common/rfb/ServerParams.cxx b/common/rfb/ServerParams.cxx new file mode 100644 index 00000000..bfeb80d6 --- /dev/null +++ b/common/rfb/ServerParams.cxx @@ -0,0 +1,84 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright (C) 2011 D. R. Commander. All Rights Reserved. + * Copyright 2014-2018 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +#include <rfb/Exception.h> +#include <rfb/ledStates.h> +#include <rfb/ServerParams.h> + +using namespace rfb; + +ServerParams::ServerParams() + : majorVersion(0), minorVersion(0), + supportsQEMUKeyEvent(false), + supportsSetDesktopSize(false), supportsFence(false), + supportsContinuousUpdates(false), + width_(0), height_(0), name_(0), + ledState_(ledUnknown) +{ + setName(""); + cursor_ = new Cursor(0, 0, Point(), NULL); +} + +ServerParams::~ServerParams() +{ + delete [] name_; + delete cursor_; +} + +void ServerParams::setDimensions(int width, int height) +{ + ScreenSet layout; + layout.add_screen(rfb::Screen(0, 0, 0, width, height, 0)); + setDimensions(width, height, layout); +} + +void ServerParams::setDimensions(int width, int height, const ScreenSet& layout) +{ + if (!layout.validate(width, height)) + throw Exception("Attempted to configure an invalid screen layout"); + + width_ = width; + height_ = height; + screenLayout_ = layout; +} + +void ServerParams::setPF(const PixelFormat& pf) +{ + pf_ = pf; + + if (pf.bpp != 8 && pf.bpp != 16 && pf.bpp != 32) + throw Exception("setPF: not 8, 16 or 32 bpp?"); +} + +void ServerParams::setName(const char* name) +{ + delete [] name_; + name_ = strDup(name); +} + +void ServerParams::setCursor(const Cursor& other) +{ + delete cursor_; + cursor_ = new Cursor(other); +} + +void ServerParams::setLEDState(unsigned int state) +{ + ledState_ = state; +} diff --git a/common/rfb/ServerParams.h b/common/rfb/ServerParams.h new file mode 100644 index 00000000..7a58ea37 --- /dev/null +++ b/common/rfb/ServerParams.h @@ -0,0 +1,89 @@ +/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved. + * Copyright 2014-2018 Pierre Ossman for Cendio AB + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + */ +// +// ServerParams - structure describing the current state of the remote server +// + +#ifndef __RFB_SERVERPARAMS_H__ +#define __RFB_SERVERPARAMS_H__ + +#include <rfb/Cursor.h> +#include <rfb/PixelFormat.h> +#include <rfb/ScreenSet.h> + +namespace rfb { + + class ServerParams { + public: + ServerParams(); + ~ServerParams(); + + int majorVersion; + int minorVersion; + + void setVersion(int major, int minor) { + majorVersion = major; minorVersion = minor; + } + bool isVersion(int major, int minor) const { + return majorVersion == major && minorVersion == minor; + } + bool beforeVersion(int major, int minor) const { + return (majorVersion < major || + (majorVersion == major && minorVersion < minor)); + } + bool afterVersion(int major, int minor) const { + return !beforeVersion(major,minor+1); + } + + const int width() const { return width_; } + const int height() const { return height_; } + const ScreenSet& screenLayout() const { return screenLayout_; } + void setDimensions(int width, int height); + void setDimensions(int width, int height, const ScreenSet& layout); + + const PixelFormat& pf() const { return pf_; } + void setPF(const PixelFormat& pf); + + const char* name() const { return name_; } + void setName(const char* name); + + const Cursor& cursor() const { return *cursor_; } + void setCursor(const Cursor& cursor); + + unsigned int ledState() { return ledState_; } + void setLEDState(unsigned int state); + + bool supportsQEMUKeyEvent; + bool supportsSetDesktopSize; + bool supportsFence; + bool supportsContinuousUpdates; + + private: + + int width_; + int height_; + ScreenSet screenLayout_; + + PixelFormat pf_; + char* name_; + Cursor* cursor_; + unsigned int ledState_; + }; +} +#endif diff --git a/common/rfb/TightDecoder.cxx b/common/rfb/TightDecoder.cxx index 548c1906..5b7c553d 100644 --- a/common/rfb/TightDecoder.cxx +++ b/common/rfb/TightDecoder.cxx @@ -25,7 +25,7 @@ #include <rdr/MemInStream.h> #include <rdr/OutStream.h> -#include <rfb/ConnParams.h> +#include <rfb/ServerParams.h> #include <rfb/Exception.h> #include <rfb/PixelBuffer.h> #include <rfb/TightConstants.h> @@ -55,7 +55,7 @@ TightDecoder::~TightDecoder() } void TightDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os) + const ServerParams& server, rdr::OutStream* os) { rdr::U8 comp_ctl; @@ -66,10 +66,10 @@ void TightDecoder::readRect(const Rect& r, rdr::InStream* is, // "Fill" compression type. if (comp_ctl == tightFill) { - if (cp.pf().is888()) + if (server.pf().is888()) os->copyBytes(is, 3); else - os->copyBytes(is, cp.pf().bpp/8); + os->copyBytes(is, server.pf().bpp/8); return; } @@ -106,13 +106,13 @@ void TightDecoder::readRect(const Rect& r, rdr::InStream* is, palSize = is->readU8() + 1; os->writeU8(palSize - 1); - if (cp.pf().is888()) + if (server.pf().is888()) os->copyBytes(is, palSize * 3); else - os->copyBytes(is, palSize * cp.pf().bpp/8); + os->copyBytes(is, palSize * server.pf().bpp/8); break; case tightFilterGradient: - if (cp.pf().bpp == 8) + if (server.pf().bpp == 8) throw Exception("TightDecoder: invalid BPP for gradient filter"); break; case tightFilterCopy: @@ -129,10 +129,10 @@ void TightDecoder::readRect(const Rect& r, rdr::InStream* is, rowSize = (r.width() + 7) / 8; else rowSize = r.width(); - } else if (cp.pf().is888()) { + } else if (server.pf().is888()) { rowSize = r.width() * 3; } else { - rowSize = r.width() * cp.pf().bpp/8; + rowSize = r.width() * server.pf().bpp/8; } dataSize = r.height() * rowSize; @@ -154,7 +154,7 @@ bool TightDecoder::doRectsConflict(const Rect& rectA, const Rect& rectB, const void* bufferB, size_t buflenB, - const ConnParams& cp) + const ServerParams& server) { rdr::U8 comp_ctl_a, comp_ctl_b; @@ -177,11 +177,11 @@ bool TightDecoder::doRectsConflict(const Rect& rectA, } void TightDecoder::decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { const rdr::U8* bufptr; - const PixelFormat& pf = cp.pf(); + const PixelFormat& pf = server.pf(); rdr::U8 comp_ctl; diff --git a/common/rfb/TightDecoder.h b/common/rfb/TightDecoder.h index 6eb93d2a..28b6c30f 100644 --- a/common/rfb/TightDecoder.h +++ b/common/rfb/TightDecoder.h @@ -32,16 +32,16 @@ namespace rfb { TightDecoder(); virtual ~TightDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os); + const ServerParams& server, rdr::OutStream* os); virtual bool doRectsConflict(const Rect& rectA, const void* bufferA, size_t buflenA, const Rect& rectB, const void* bufferB, size_t buflenB, - const ConnParams& cp); + const ServerParams& server); virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); private: diff --git a/common/rfb/TightEncoder.cxx b/common/rfb/TightEncoder.cxx index 0d428f16..1b0792c4 100644 --- a/common/rfb/TightEncoder.cxx +++ b/common/rfb/TightEncoder.cxx @@ -23,7 +23,6 @@ #include <rfb/PixelBuffer.h> #include <rfb/Palette.h> #include <rfb/encodings.h> -#include <rfb/ConnParams.h> #include <rfb/SConnection.h> #include <rfb/TightEncoder.h> #include <rfb/TightConstants.h> @@ -68,7 +67,7 @@ TightEncoder::~TightEncoder() bool TightEncoder::isSupported() { - return conn->cp.supportsEncoding(encodingTight); + return conn->client.supportsEncoding(encodingTight); } void TightEncoder::setCompressLevel(int level) diff --git a/common/rfb/TightJPEGEncoder.cxx b/common/rfb/TightJPEGEncoder.cxx index 38cb4eb7..75575389 100644 --- a/common/rfb/TightJPEGEncoder.cxx +++ b/common/rfb/TightJPEGEncoder.cxx @@ -76,15 +76,15 @@ TightJPEGEncoder::~TightJPEGEncoder() bool TightJPEGEncoder::isSupported() { - if (!conn->cp.supportsEncoding(encodingTight)) + if (!conn->client.supportsEncoding(encodingTight)) return false; // Any one of these indicates support for JPEG - if (conn->cp.qualityLevel != -1) + if (conn->client.qualityLevel != -1) return true; - if (conn->cp.fineQualityLevel != -1) + if (conn->client.fineQualityLevel != -1) return true; - if (conn->cp.subsampling != -1) + if (conn->client.subsampling != -1) return true; // Tight support, but not JPEG diff --git a/common/rfb/UpdateTracker.cxx b/common/rfb/UpdateTracker.cxx index b53b8509..28e916d5 100644 --- a/common/rfb/UpdateTracker.cxx +++ b/common/rfb/UpdateTracker.cxx @@ -60,32 +60,17 @@ void ClippingUpdateTracker::add_copied(const Region &dest, const Point &delta) { // SimpleUpdateTracker -SimpleUpdateTracker::SimpleUpdateTracker(bool use_copyrect) { - copy_enabled = use_copyrect; +SimpleUpdateTracker::SimpleUpdateTracker() { } SimpleUpdateTracker::~SimpleUpdateTracker() { } -void SimpleUpdateTracker::enable_copyrect(bool enable) { - if (!enable && copy_enabled) { - add_changed(copied); - copied.clear(); - } - copy_enabled=enable; -} - void SimpleUpdateTracker::add_changed(const Region ®ion) { changed.assign_union(region); } void SimpleUpdateTracker::add_copied(const Region &dest, const Point &delta) { - // Do we support copyrect? - if (!copy_enabled) { - add_changed(dest); - return; - } - // Is there anything to do? if (dest.is_empty()) return; diff --git a/common/rfb/UpdateTracker.h b/common/rfb/UpdateTracker.h index 8e96d55e..8983b378 100644 --- a/common/rfb/UpdateTracker.h +++ b/common/rfb/UpdateTracker.h @@ -68,11 +68,9 @@ namespace rfb { class SimpleUpdateTracker : public UpdateTracker { public: - SimpleUpdateTracker(bool use_copyrect=true); + SimpleUpdateTracker(); virtual ~SimpleUpdateTracker(); - virtual void enable_copyrect(bool enable); - virtual void add_changed(const Region ®ion); virtual void add_copied(const Region &dest, const Point &delta); virtual void subtract(const Region& region); @@ -94,7 +92,6 @@ namespace rfb { Region changed; Region copied; Point copy_delta; - bool copy_enabled; }; } diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index dbbf1d80..ea5c52aa 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -49,7 +49,7 @@ VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s, inProcessMessages(false), pendingSyncFence(false), syncFence(false), fenceFlags(0), fenceDataLen(0), fenceData(NULL), congestionTimer(this), - losslessTimer(this), server(server_), updates(false), + losslessTimer(this), server(server_), updateRenderedCursor(false), removeRenderedCursor(false), continuousUpdates(false), encodeManager(this), idleTimer(this), pointerEventTime(0), clientHasCursor(false) @@ -199,9 +199,9 @@ void VNCSConnectionST::pixelBufferChange() { try { if (!authenticated()) return; - if (cp.width && cp.height && - (server->getPixelBuffer()->width() != cp.width || - server->getPixelBuffer()->height() != cp.height)) + if (client.width() && client.height() && + (server->getPixelBuffer()->width() != client.width() || + server->getPixelBuffer()->height() != client.height())) { // We need to clip the next update to the new size, but also add any // extra bits if it's bigger. If we wanted to do this exactly, something @@ -211,26 +211,24 @@ void VNCSConnectionST::pixelBufferChange() //updates.intersect(server->pb->getRect()); // - //if (server->pb->width() > cp.width) - // updates.add_changed(Rect(cp.width, 0, server->pb->width(), + //if (server->pb->width() > client.width()) + // updates.add_changed(Rect(client.width(), 0, server->pb->width(), // server->pb->height())); - //if (server->pb->height() > cp.height) - // updates.add_changed(Rect(0, cp.height, cp.width, + //if (server->pb->height() > client.height()) + // updates.add_changed(Rect(0, client.height(), client.width(), // server->pb->height())); damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect()); - cp.width = server->getPixelBuffer()->width(); - cp.height = server->getPixelBuffer()->height(); - cp.screenLayout = server->getScreenLayout(); + client.setDimensions(server->getPixelBuffer()->width(), + server->getPixelBuffer()->height(), + server->getScreenLayout()); if (state() == RFBSTATE_NORMAL) { - // We should only send EDS to client asking for both - if (!writer()->writeExtendedDesktopSize()) { - if (!writer()->writeSetDesktopSize()) { - close("Client does not support desktop resize"); - return; - } + if (!client.supportsDesktopSize()) { + close("Client does not support desktop resize"); + return; } + writer()->writeDesktopSize(reasonServer); } // Drop any lossy tracking that is now outside the framebuffer @@ -325,7 +323,7 @@ bool VNCSConnectionST::getComparerState() // We interpret a low compression level as an indication that the client // wants to prioritise CPU usage over bandwidth, and hence disable the // comparing update tracker. - return (cp.compressLevel == -1) || (cp.compressLevel > 1); + return (client.compressLevel == -1) || (client.compressLevel > 1); } @@ -363,8 +361,7 @@ bool VNCSConnectionST::needRenderedCursor() if (state() != RFBSTATE_NORMAL) return false; - if (!cp.supportsLocalCursorWithAlpha && - !cp.supportsLocalCursor && !cp.supportsLocalXCursor) + if (!client.supportsLocalCursor()) return true; if (!server->getCursorPos().equals(pointerEventPos) && (time(0) - pointerEventTime) > 0) @@ -394,16 +391,16 @@ void VNCSConnectionST::authSuccess() idleTimer.start(secsToMillis(rfb::Server::idleTimeout)); // - Set the connection parameters appropriately - cp.width = server->getPixelBuffer()->width(); - cp.height = server->getPixelBuffer()->height(); - cp.screenLayout = server->getScreenLayout(); - cp.setName(server->getName()); - cp.setLEDState(server->getLEDState()); + client.setDimensions(server->getPixelBuffer()->width(), + server->getPixelBuffer()->height(), + server->getScreenLayout()); + client.setName(server->getName()); + client.setLEDState(server->getLEDState()); // - Set the default pixel format - cp.setPF(server->getPixelBuffer()->getPF()); + client.setPF(server->getPixelBuffer()->getPF()); char buffer[256]; - cp.pf().print(buffer, 256); + client.pf().print(buffer, 256); vlog.info("Server default pixel format %s", buffer); // - Mark the entire display as "dirty" @@ -492,7 +489,7 @@ void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) { // Lock key heuristics // (only for clients that do not support the LED state extension) - if (!cp.supportsLEDState) { + if (!client.supportsLEDState()) { // Always ignore ScrollLock as we don't have a heuristic // for that if (keysym == XK_Scroll_Lock) { @@ -597,10 +594,11 @@ void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental) SConnection::framebufferUpdateRequest(r, incremental); // Check that the client isn't sending crappy requests - if (!r.enclosed_by(Rect(0, 0, cp.width, cp.height))) { + if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) { vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d", - r.width(), r.height(), r.tl.x, r.tl.y, cp.width, cp.height); - safeRect = r.intersect(Rect(0, 0, cp.width, cp.height)); + r.width(), r.height(), r.tl.x, r.tl.y, + client.width(), client.height()); + safeRect = r.intersect(Rect(0, 0, client.width(), client.height())); } else { safeRect = r; } @@ -617,7 +615,8 @@ void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental) // And send the screen layout to the client (which, unlike the // framebuffer dimensions, the client doesn't get during init) - writer()->writeExtendedDesktopSize(); + if (client.supportsEncoding(pseudoEncodingExtendedDesktopSize)) + writer()->writeDesktopSize(reasonServer); // We do not send a DesktopSize since it only contains the // framebuffer size (which the client already should know) and @@ -635,8 +634,7 @@ void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height, if (!rfb::Server::acceptSetDesktopSize) return; result = server->setDesktopSize(this, fb_width, fb_height, layout); - writer()->writeExtendedDesktopSize(reasonClient, result, - fb_width, fb_height, layout); + writer()->writeDesktopSize(reasonClient, result); } void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[]) @@ -688,7 +686,7 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable, { Rect rect; - if (!cp.supportsFence || !cp.supportsContinuousUpdates) + if (!client.supportsFence() || !client.supportsContinuousUpdates()) throw Exception("Client tried to enable continuous updates when not allowed"); continuousUpdates = enable; @@ -704,7 +702,7 @@ void VNCSConnectionST::enableContinuousUpdates(bool enable, } // supportsLocalCursor() is called whenever the status of -// cp.supportsLocalCursor has changed. If the client does now support local +// client.supportsLocalCursor() has changed. If the client does now support local // cursor, we make sure that the old server-side rendered cursor is cleaned up // and the cursor is sent to the client. @@ -726,7 +724,7 @@ void VNCSConnectionST::supportsContinuousUpdates() { // We refuse to use continuous updates if we cannot monitor the buffer // usage using fences. - if (!cp.supportsFence) + if (!client.supportsFence()) return; writer()->writeEndOfContinuousUpdates(); @@ -734,6 +732,9 @@ void VNCSConnectionST::supportsContinuousUpdates() void VNCSConnectionST::supportsLEDState() { + if (client.ledState() == ledUnknown) + return; + writer()->writeLEDState(); } @@ -772,7 +773,7 @@ void VNCSConnectionST::writeRTTPing() { char type; - if (!cp.supportsFence) + if (!client.supportsFence()) return; congestion.updatePosition(sock->outStream().length()); @@ -799,7 +800,7 @@ bool VNCSConnectionST::isCongested() if (sock->outStream().bufferUsage() > 0) return true; - if (!cp.supportsFence) + if (!client.supportsFence()) return false; congestion.updatePosition(sock->outStream().length()); @@ -876,8 +877,6 @@ void VNCSConnectionST::writeDataUpdate() bool needNewUpdateInfo; const RenderedCursor *cursor; - updates.enable_copyrect(cp.useCopyRect); - // See what the client has requested (if anything) if (continuousUpdates) req = cuRegion.union_(requested); @@ -1063,13 +1062,13 @@ void VNCSConnectionST::screenLayoutChange(rdr::U16 reason) if (!authenticated()) return; - cp.screenLayout = server->getScreenLayout(); + client.setDimensions(client.width(), client.height(), + server->getScreenLayout()); if (state() != RFBSTATE_NORMAL) return; - writer()->writeExtendedDesktopSize(reason, 0, cp.width, cp.height, - cp.screenLayout); + writer()->writeDesktopSize(reason); } @@ -1084,34 +1083,26 @@ void VNCSConnectionST::setCursor() // We need to blank out the client's cursor or there will be two if (needRenderedCursor()) { - cp.setCursor(emptyCursor); + client.setCursor(emptyCursor); clientHasCursor = false; } else { - cp.setCursor(*server->getCursor()); + client.setCursor(*server->getCursor()); clientHasCursor = true; } - if (!writer()->writeSetCursorWithAlpha()) { - if (!writer()->writeSetCursor()) { - if (!writer()->writeSetXCursor()) { - // No client support - return; - } - } - } + if (client.supportsLocalCursor()) + writer()->writeCursor(); } void VNCSConnectionST::setDesktopName(const char *name) { - cp.setName(name); + client.setName(name); if (state() != RFBSTATE_NORMAL) return; - if (!writer()->writeSetDesktopName()) { - fprintf(stderr, "Client does not support desktop rename\n"); - return; - } + if (client.supportsEncoding(pseudoEncodingDesktopName)) + writer()->writeSetDesktopName(); } void VNCSConnectionST::setLEDState(unsigned int ledstate) @@ -1119,9 +1110,10 @@ void VNCSConnectionST::setLEDState(unsigned int ledstate) if (state() != RFBSTATE_NORMAL) return; - cp.setLEDState(ledstate); + client.setLEDState(ledstate); - writer()->writeLEDState(); + if (client.supportsLEDState()) + writer()->writeLEDState(); } void VNCSConnectionST::setSocketTimeouts() diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index 40580b16..c95c14f0 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -255,8 +255,6 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout) delete comparer; comparer = 0; - screenLayout = layout; - if (!pb) { screenLayout = ScreenSet(); @@ -266,16 +264,17 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout) return; } + if (!layout.validate(pb->width(), pb->height())) + throw Exception("setPixelBuffer: invalid screen layout"); + + screenLayout = layout; + // Assume the framebuffer contents wasn't saved and reset everything // that tracks its contents comparer = new ComparingUpdateTracker(pb); renderedCursorInvalid = true; add_changed(pb->getRect()); - // Make sure that we have at least one screen - if (screenLayout.num_screens() == 0) - screenLayout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0)); - std::list<VNCSConnectionST*>::iterator ci, ci_next; for (ci=clients.begin();ci!=clients.end();ci=ci_next) { ci_next = ci; ci_next++; @@ -309,6 +308,10 @@ void VNCServerST::setPixelBuffer(PixelBuffer* pb_) } } + // Make sure that we have at least one screen + if (layout.num_screens() == 0) + layout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0)); + setPixelBuffer(pb_, layout); } diff --git a/common/rfb/ZRLEDecoder.cxx b/common/rfb/ZRLEDecoder.cxx index 1dfb72af..9d1ff6b6 100644 --- a/common/rfb/ZRLEDecoder.cxx +++ b/common/rfb/ZRLEDecoder.cxx @@ -21,7 +21,7 @@ #include <rdr/MemInStream.h> #include <rdr/OutStream.h> -#include <rfb/ConnParams.h> +#include <rfb/ServerParams.h> #include <rfb/PixelBuffer.h> #include <rfb/ZRLEDecoder.h> @@ -72,7 +72,7 @@ ZRLEDecoder::~ZRLEDecoder() } void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os) + const ServerParams& server, rdr::OutStream* os) { rdr::U32 len; @@ -82,11 +82,11 @@ void ZRLEDecoder::readRect(const Rect& r, rdr::InStream* is, } void ZRLEDecoder::decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb) { rdr::MemInStream is(buffer, buflen); - const rfb::PixelFormat& pf = cp.pf(); + const rfb::PixelFormat& pf = server.pf(); switch (pf.bpp) { case 8: zrleDecode8 (r, &is, &zis, pf, pb); break; case 16: zrleDecode16(r, &is, &zis, pf, pb); break; diff --git a/common/rfb/ZRLEDecoder.h b/common/rfb/ZRLEDecoder.h index 1e338510..a530586e 100644 --- a/common/rfb/ZRLEDecoder.h +++ b/common/rfb/ZRLEDecoder.h @@ -28,9 +28,9 @@ namespace rfb { ZRLEDecoder(); virtual ~ZRLEDecoder(); virtual void readRect(const Rect& r, rdr::InStream* is, - const ConnParams& cp, rdr::OutStream* os); + const ServerParams& server, rdr::OutStream* os); virtual void decodeRect(const Rect& r, const void* buffer, - size_t buflen, const ConnParams& cp, + size_t buflen, const ServerParams& server, ModifiablePixelBuffer* pb); private: rdr::ZlibInStream zis; diff --git a/common/rfb/ZRLEEncoder.cxx b/common/rfb/ZRLEEncoder.cxx index 8917d8ff..92fd13d1 100644 --- a/common/rfb/ZRLEEncoder.cxx +++ b/common/rfb/ZRLEEncoder.cxx @@ -19,7 +19,6 @@ #include <rdr/OutStream.h> #include <rfb/Exception.h> #include <rfb/encodings.h> -#include <rfb/ConnParams.h> #include <rfb/Palette.h> #include <rfb/SConnection.h> #include <rfb/ZRLEEncoder.h> @@ -43,7 +42,7 @@ ZRLEEncoder::~ZRLEEncoder() bool ZRLEEncoder::isSupported() { - return conn->cp.supportsEncoding(encodingZRLE); + return conn->client.supportsEncoding(encodingZRLE); } void ZRLEEncoder::writeRect(const PixelBuffer* pb, const Palette& palette) diff --git a/tests/decperf.cxx b/tests/decperf.cxx index 9061cb53..301e45e0 100644 --- a/tests/decperf.cxx +++ b/tests/decperf.cxx @@ -47,7 +47,7 @@ public: CConn(const char *filename); ~CConn(); - virtual void setDesktopSize(int w, int h); + virtual void initDone(); virtual void setPixelFormat(const rfb::PixelFormat& pf); virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*); virtual void framebufferUpdateStart(); @@ -81,11 +81,11 @@ CConn::~CConn() delete in; } -void CConn::setDesktopSize(int w, int h) +void CConn::initDone() { - CConnection::setDesktopSize(w, h); - - setFramebuffer(new rfb::ManagedPixelBuffer(filePF, cp.width, cp.height)); + setFramebuffer(new rfb::ManagedPixelBuffer(filePF, + server.width(), + server.height())); } void CConn::setPixelFormat(const rfb::PixelFormat& pf) diff --git a/tests/encperf.cxx b/tests/encperf.cxx index 733d55b6..6523eb72 100644 --- a/tests/encperf.cxx +++ b/tests/encperf.cxx @@ -89,7 +89,7 @@ public: void getStats(double& ratio, unsigned long long& bytes, unsigned long long& rawEquivalent); - virtual void setDesktopSize(int w, int h); + virtual void initDone(); virtual void setCursor(int, int, const rfb::Point&, const rdr::U8*); virtual void framebufferUpdateStart(); virtual void framebufferUpdateEnd(); @@ -180,7 +180,7 @@ CConn::CConn(const char *filename) setDesktopSize(width, height); sc = new SConn(); - sc->cp.setPF((bool)translate ? fbPF : pf); + sc->client.setPF((bool)translate ? fbPF : pf); sc->setEncodings(sizeof(encodings) / sizeof(*encodings), encodings); } @@ -196,14 +196,12 @@ void CConn::getStats(double& ratio, unsigned long long& bytes, sc->getStats(ratio, bytes, rawEquivalent); } -void CConn::setDesktopSize(int w, int h) +void CConn::initDone() { rfb::ModifiablePixelBuffer *pb; - CConnection::setDesktopSize(w, h); - - pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : cp.pf(), - cp.width, cp.height); + pb = new rfb::ManagedPixelBuffer((bool)translate ? fbPF : server.pf(), + server.width(), server.height()); setFramebuffer(pb); } @@ -290,7 +288,7 @@ SConn::SConn() out = new DummyOutStream; setStreams(NULL, out); - setWriter(new rfb::SMsgWriter(&cp, out)); + setWriter(new rfb::SMsgWriter(&client, out)); manager = new Manager(this); } diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx index 1fdc9e2c..564b2d51 100644 --- a/unix/x0vncserver/XDesktop.cxx +++ b/unix/x0vncserver/XDesktop.cxx @@ -423,8 +423,27 @@ ScreenSet XDesktop::computeScreenLayout() layout = ::computeScreenLayout(&outputIdMap); XRRFreeScreenResources(res); + + // Adjust the layout relative to the geometry + ScreenSet::iterator iter, iter_next; + Point offset(-geometry->offsetLeft(), -geometry->offsetTop()); + for (iter = layout.begin();iter != layout.end();iter = iter_next) { + iter_next = iter; ++iter_next; + iter->dimensions = iter->dimensions.translate(offset); + if (iter->dimensions.enclosed_by(geometry->getRect())) + continue; + iter->dimensions = iter->dimensions.intersect(geometry->getRect()); + if (iter->dimensions.is_empty()) { + layout.remove_screen(iter->id); + } + } #endif + // Make sure that we have at least one screen + if (layout.num_screens() == 0) + layout.add_screen(rfb::Screen(0, 0, 0, geometry->width(), + geometry->height(), 0)); + return layout; } diff --git a/vncviewer/CConn.cxx b/vncviewer/CConn.cxx index 69186c55..b4610e6a 100644 --- a/vncviewer/CConn.cxx +++ b/vncviewer/CConn.cxx @@ -36,8 +36,6 @@ #include <rfb/screenTypes.h> #include <rfb/fenceTypes.h> #include <rfb/Timer.h> -#include <rdr/MemInStream.h> -#include <rdr/MemOutStream.h> #include <network/TcpSocket.h> #ifndef WIN32 #include <network/UnixSocket.h> @@ -76,36 +74,21 @@ 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), supportsSyncFence(false) + updateCount(0), pixelCount(0), + lastServerEncoding((unsigned int)-1) { setShared(::shared); sock = socket; - int encNum = encodingNum(preferredEncoding); - if (encNum != -1) - currentEncoding = encNum; - - cp.supportsLocalCursor = true; - - cp.supportsDesktopResize = true; - cp.supportsExtendedDesktopSize = true; - cp.supportsDesktopRename = true; - - cp.supportsLEDState = true; + supportsLocalCursor = true; + supportsDesktopResize = true; + supportsLEDState = true; if (customCompressLevel) - cp.compressLevel = compressLevel; - else - cp.compressLevel = -1; + setCompressLevel(::compressLevel); if (!noJpeg) - cp.qualityLevel = qualityLevel; - else - cp.qualityLevel = -1; + setQualityLevel(::qualityLevel); if(sock == NULL) { try { @@ -158,16 +141,6 @@ CConn::~CConn() delete sock; } -void CConn::refreshFramebuffer() -{ - forceNonincremental = true; - - // Without fences, we cannot safely trigger an update request directly - // but must wait for the next update to arrive. - if (supportsSyncFence) - requestNewUpdate(); -} - const char *CConn::connectionInfo() { static char infoText[1024] = ""; @@ -181,7 +154,7 @@ const char *CConn::connectionInfo() infoText[0] = '\0'; snprintf(scratch, sizeof(scratch), - _("Desktop name: %.80s"), cp.name()); + _("Desktop name: %.80s"), server.name()); strcat(infoText, scratch); strcat(infoText, "\n"); @@ -191,13 +164,13 @@ const char *CConn::connectionInfo() strcat(infoText, "\n"); snprintf(scratch, sizeof(scratch), - _("Size: %d x %d"), cp.width, cp.height); + _("Size: %d x %d"), server.width(), server.height()); strcat(infoText, scratch); strcat(infoText, "\n"); // TRANSLATORS: Will be filled in with a string describing the // protocol pixel format in a fairly language neutral way - cp.pf().print(pfStr, 100); + server.pf().print(pfStr, 100); snprintf(scratch, sizeof(scratch), _("Pixel format: %s"), pfStr); strcat(infoText, scratch); @@ -211,7 +184,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"); @@ -226,7 +199,7 @@ const char *CConn::connectionInfo() strcat(infoText, "\n"); snprintf(scratch, sizeof(scratch), - _("Protocol version: %d.%d"), cp.majorVersion, cp.minorVersion); + _("Protocol version: %d.%d"), server.majorVersion, server.minorVersion); strcat(infoText, scratch); strcat(infoText, "\n"); @@ -310,34 +283,27 @@ void CConn::socketEvent(FL_SOCKET fd, void *data) ////////////////////// CConnection callback methods ////////////////////// -// serverInit() is called when the serverInit message has been received. At +// initDone() is called when the serverInit message has been received. At // this point we create the desktop window and display it. We also tell the // server the pixel format and encodings to use and request the first update. -void CConn::serverInit() +void CConn::initDone() { - CConnection::serverInit(); - // If using AutoSelect with old servers, start in FullColor // mode. See comment in autoSelectFormatAndEncoding. - if (cp.beforeVersion(3, 8) && autoSelect) + if (server.beforeVersion(3, 8) && autoSelect) fullColour.setParam(true); - serverPF = cp.pf(); + serverPF = server.pf(); - desktop = new DesktopWindow(cp.width, cp.height, cp.name(), serverPF, this); + desktop = new DesktopWindow(server.width(), server.height(), + server.name(), serverPF, this); 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); - cp.setPF(pendingPF); - pendingPFChange = false; + updatePixelFormat(); + int encNum = encodingNum(::preferredEncoding); + if (encNum != -1) + setPreferredEncoding(encNum); } // setDesktopSize() is called when the desktop size changes (including when @@ -366,8 +332,7 @@ void CConn::setExtendedDesktopSize(unsigned reason, unsigned result, void CConn::setName(const char* name) { CConnection::setName(name); - if (desktop) - desktop->setName(name); + desktop->setName(name); } // framebufferUpdateStart() is called at the beginning of an update. @@ -378,11 +343,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); } @@ -400,22 +360,6 @@ void CConn::framebufferUpdateEnd() Fl::remove_timeout(handleUpdateTimeout, this); desktop->updateWindow(); - if (firstUpdate) { - // We need fences to make extra update requests and continuous - // updates "safe". See fence() for the next step. - if (cp.supportsFence) - writer()->writeFence(fenceFlagRequest | fenceFlagSyncNext, 0, NULL); - - firstUpdate = false; - } - - // 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) { - cp.setPF(pendingPF); - pendingPFChange = false; - } - // Compute new settings based on updated bandwidth values if (autoSelect) autoSelectFormatAndEncoding(); @@ -469,27 +413,6 @@ void CConn::fence(rdr::U32 flags, unsigned len, const char data[]) writer()->writeFence(flags, len, data); return; } - - if (len == 0) { - // Initial probe - if (flags & fenceFlagSyncNext) { - supportsSyncFence = true; - - if (cp.supportsContinuousUpdates) { - vlog.info(_("Enabling continuous updates")); - continuousUpdates = true; - writer()->writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height); - } - } - } else { - // Pixel format change - rdr::MemInStream memStream(data, len); - PixelFormat pf; - - pf.read(&memStream); - - cp.setPF(pf); - } } void CConn::setLEDState(unsigned int state) @@ -504,13 +427,7 @@ void CConn::setLEDState(unsigned int state) void CConn::resizeFramebuffer() { - if (!desktop) - return; - - if (continuousUpdates) - writer()->writeEnableContinuousUpdates(true, 0, 0, cp.width, cp.height); - - desktop->resizeFramebuffer(cp.width, cp.height); + desktop->resizeFramebuffer(server.width(), server.height()); } // autoSelectFormatAndEncoding() chooses the format and encoding appropriate @@ -533,13 +450,10 @@ void CConn::autoSelectFormatAndEncoding() int kbitsPerSecond = sock->inStream().kbitsPerSecond(); unsigned int timeWaited = sock->inStream().timeWaited(); bool newFullColour = fullColour; - int newQualityLevel = qualityLevel; + 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)) @@ -552,16 +466,15 @@ void CConn::autoSelectFormatAndEncoding() else newQualityLevel = 6; - if (newQualityLevel != qualityLevel) { + if (newQualityLevel != ::qualityLevel) { vlog.info(_("Throughput %d kbit/s - changing to quality %d"), kbitsPerSecond, newQualityLevel); - cp.qualityLevel = newQualityLevel; - qualityLevel.setParam(newQualityLevel); - encodingChange = true; + ::qualityLevel.setParam(newQualityLevel); + setQualityLevel(newQualityLevel); } } - if (cp.beforeVersion(3, 8)) { + if (server.beforeVersion(3, 8)) { // Xvnc from TightVNC 1.2.9 sends out FramebufferUpdates with // cursors "asynchronously". If this happens in the middle of a // pixel format change, the server will encode the cursor with @@ -582,76 +495,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) { - PixelFormat pf; - - /* Catch incorrect requestNewUpdate calls */ - assert(!pendingUpdate || supportsSyncFence); - - if (fullColour) { - pf = fullColourPF; - } else { - if (lowColourLevel == 0) - pf = verylowColourPF; - else if (lowColourLevel == 1) - pf = lowColourPF; - else - pf = mediumColourPF; - } - - if (supportsSyncFence) { - // We let the fence carry the pixel format and switch once we - // get the response back. That way we will be synchronised with - // when the server switches. - rdr::MemOutStream memStream; - - pf.write(&memStream); - - writer()->writeFence(fenceFlagRequest | fenceFlagSyncNext, - memStream.length(), (const char*)memStream.data()); - } else { - // New requests are sent out at the start of processing the last - // one, so we cannot switch our internal format right now (doing so - // would mean misdecoding the current update). - pendingPFChange = true; - pendingPF = pf; - } - - char str[256]; - pf.print(str, 256); - vlog.info(_("Using pixel format %s"),str); - writer()->writeSetPixelFormat(pf); + 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, cp.width, cp.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) @@ -663,50 +531,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->cp.supportsLocalCursor = true; - if (customCompressLevel) - self->cp.compressLevel = compressLevel; + self->setCompressLevel(::compressLevel); else - self->cp.compressLevel = -1; + self->setCompressLevel(-1); if (!noJpeg && !autoSelect) - self->cp.qualityLevel = qualityLevel; + self->setQualityLevel(::qualityLevel); else - self->cp.qualityLevel = -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; + self->setQualityLevel(-1); - if (fullColour) { - pf = self->fullColourPF; - } else { - if (lowColourLevel == 0) - pf = verylowColourPF; - else if (lowColourLevel == 1) - pf = lowColourPF; - else - pf = mediumColourPF; - } - - if (!pf.equal(self->cp.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->supportsSyncFence) - self->requestNewUpdate(); - } + self->updatePixelFormat(); } void CConn::handleUpdateTimeout(void *data) diff --git a/vncviewer/CConn.h b/vncviewer/CConn.h index dd4ae893..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(); @@ -51,7 +49,7 @@ public: static void socketEvent(FL_SOCKET fd, void *data); // CConnection callback methods - void serverInit(); + void initDone(); void setDesktopSize(int w, int h); void setExtendedDesktopSize(unsigned reason, unsigned result, @@ -81,8 +79,7 @@ private: void resizeFramebuffer(); void autoSelectFormatAndEncoding(); - void checkEncodings(); - void requestNewUpdate(); + void updatePixelFormat(); static void handleOptions(void *data); @@ -101,21 +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; - - bool supportsSyncFence; + int lastServerEncoding; }; #endif diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index 1843485a..150c39bc 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -235,7 +235,7 @@ void DesktopWindow::setName(const char *name) void DesktopWindow::updateWindow() { if (firstUpdate) { - if (cc->cp.supportsSetDesktopSize) { + if (cc->server.supportsSetDesktopSize) { // Hack: Wait until we're in the proper mode and position until // resizing things, otherwise we might send the wrong thing. if (delayedFullscreen) @@ -487,7 +487,7 @@ void DesktopWindow::resize(int x, int y, int w, int h) // d) We're not still waiting for startup fullscreen to kick in // if (not firstUpdate and not delayedFullscreen and - ::remoteResize and cc->cp.supportsSetDesktopSize) { + ::remoteResize and cc->server.supportsSetDesktopSize) { // We delay updating the remote desktop as we tend to get a flood // of resize events as the user is dragging the window. Fl::remove_timeout(handleResizeTimeout, this); @@ -1014,14 +1014,14 @@ void DesktopWindow::handleResizeTimeout(void *data) void DesktopWindow::remoteResize(int width, int height) { ScreenSet layout; - ScreenSet::iterator iter; + ScreenSet::const_iterator iter; if (!fullscreen_active() || (width > w()) || (height > h())) { // In windowed mode (or the framebuffer is so large that we need // to scroll) we just report a single virtual screen that covers // the entire framebuffer. - layout = cc->cp.screenLayout; + layout = cc->server.screenLayout(); // Not sure why we have no screens, but adding a new one should be // safe as there is nothing to conflict with... @@ -1077,8 +1077,8 @@ void DesktopWindow::remoteResize(int width, int height) sy -= viewport_rect.tl.y; // Look for perfectly matching existing screen... - for (iter = cc->cp.screenLayout.begin(); - iter != cc->cp.screenLayout.end(); ++iter) { + for (iter = cc->server.screenLayout().begin(); + iter != cc->server.screenLayout().end(); ++iter) { if ((iter->dimensions.tl.x == sx) && (iter->dimensions.tl.y == sy) && (iter->dimensions.width() == sw) && @@ -1087,7 +1087,7 @@ void DesktopWindow::remoteResize(int width, int height) } // Found it? - if (iter != cc->cp.screenLayout.end()) { + if (iter != cc->server.screenLayout().end()) { layout.add_screen(*iter); continue; } @@ -1095,13 +1095,13 @@ void DesktopWindow::remoteResize(int width, int height) // Need to add a new one, which means we need to find an unused id while (true) { id = rand(); - for (iter = cc->cp.screenLayout.begin(); - iter != cc->cp.screenLayout.end(); ++iter) { + for (iter = cc->server.screenLayout().begin(); + iter != cc->server.screenLayout().end(); ++iter) { if (iter->id == id) break; } - if (iter == cc->cp.screenLayout.end()) + if (iter == cc->server.screenLayout().end()) break; } @@ -1115,14 +1115,14 @@ void DesktopWindow::remoteResize(int width, int height) } // Do we actually change anything? - if ((width == cc->cp.width) && - (height == cc->cp.height) && - (layout == cc->cp.screenLayout)) + if ((width == cc->server.width()) && + (height == cc->server.height()) && + (layout == cc->server.screenLayout())) return; char buffer[2048]; vlog.debug("Requesting framebuffer resize from %dx%d to %dx%d", - cc->cp.width, cc->cp.height, width, height); + cc->server.width(), cc->server.height(), width, height); layout.print(buffer, sizeof(buffer)); vlog.debug("%s", buffer); diff --git a/vncviewer/Viewport.cxx b/vncviewer/Viewport.cxx index 18ed69e7..425cb9f2 100644 --- a/vncviewer/Viewport.cxx +++ b/vncviewer/Viewport.cxx @@ -425,7 +425,7 @@ void Viewport::pushLEDState() unsigned int state; // Server support? - if (cc->cp.ledState() == ledUnknown) + if (cc->server.ledState() == ledUnknown) return; state = 0; @@ -458,7 +458,7 @@ void Viewport::pushLEDState() state |= ledNumLock; // No support for Scroll Lock // - state |= (cc->cp.ledState() & ledScrollLock); + state |= (cc->server.ledState() & ledScrollLock); #else unsigned int mask; @@ -484,17 +484,17 @@ void Viewport::pushLEDState() state |= ledScrollLock; #endif - if ((state & ledCapsLock) != (cc->cp.ledState() & ledCapsLock)) { + if ((state & ledCapsLock) != (cc->server.ledState() & ledCapsLock)) { vlog.debug("Inserting fake CapsLock to get in sync with server"); handleKeyPress(0x3a, XK_Caps_Lock); handleKeyRelease(0x3a); } - if ((state & ledNumLock) != (cc->cp.ledState() & ledNumLock)) { + if ((state & ledNumLock) != (cc->server.ledState() & ledNumLock)) { vlog.debug("Inserting fake NumLock to get in sync with server"); handleKeyPress(0x45, XK_Num_Lock); handleKeyRelease(0x45); } - if ((state & ledScrollLock) != (cc->cp.ledState() & ledScrollLock)) { + if ((state & ledScrollLock) != (cc->server.ledState() & ledScrollLock)) { vlog.debug("Inserting fake ScrollLock to get in sync with server"); handleKeyPress(0x46, XK_Scroll_Lock); handleKeyRelease(0x46); |