diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index b6fa6af..1cbd32d 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -423,9 +423,6 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, nRects++; } - if (watermarkData) - packWatermark(changed); - conn->writer()->writeFramebufferUpdateStart(nRects); writeCopyRects(copied, copyDelta); @@ -443,7 +440,7 @@ void EncodeManager::doUpdate(bool allowLossy, const Region& changed_, if (!videoDetected) // In case detection happened between the calls writeRects(cursorRegion, renderedCursor); - if (watermarkData) { + if (watermarkData && conn->sendWatermark()) { beforeLength = conn->getOutStream(conn->cp.supportsUdp)->length(); const Rect rect(0, 0, pb->width(), pb->height()); diff --git a/common/rfb/SConnection.h b/common/rfb/SConnection.h index bfecb0d..33b399f 100644 --- a/common/rfb/SConnection.h +++ b/common/rfb/SConnection.h @@ -198,6 +198,10 @@ namespace rfb { std::vector data; }; + virtual bool sendWatermark() const { + return false; + } + protected: void setState(stateEnum s) { state_ = s; } diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index 24d1863..9416b2d 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -215,6 +215,10 @@ namespace rfb { virtual void sendUnixRelayData(const char name[], const unsigned char *buf, const unsigned len); + bool sendWatermark() const { + return server->sendWatermark; + } + private: // SConnection callbacks diff --git a/common/rfb/VNCServerST.cxx b/common/rfb/VNCServerST.cxx index ffd186a..a84ebc9 100644 --- a/common/rfb/VNCServerST.cxx +++ b/common/rfb/VNCServerST.cxx @@ -135,7 +135,7 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance), lastConnectionTime(0), disableclients(false), frameTimer(this), apimessager(NULL), trackingFrameStats(0), - clipboardId(0) + clipboardId(0), sendWatermark(false) { lastUserInputTime = lastDisconnectTime = time(0); slog.debug("creating single-threaded server %s", name.buf); @@ -223,6 +223,9 @@ VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_) trackingClient[0] = 0; + if (watermarkData) + sendWatermark = true; + if (Server::selfBench) SelfBench(); } @@ -279,6 +282,9 @@ void VNCServerST::addSocket(network::Socket* sock, bool outgoing) VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing); client->init(); + + if (watermarkData) + sendWatermark = true; } void VNCServerST::removeSocket(network::Socket* sock) { @@ -975,8 +981,8 @@ void VNCServerST::writeUpdate() } if (watermarkData && Server::DLP_WatermarkText[0] && watermarkTextNeedsUpdate(true)) { - // If using a text watermark, we have to mark everything as changed... - refreshClients(); + // The text may have changed + sendWatermark = true; } comparer->getUpdateInfo(&ui, pb->getRect()); @@ -1104,6 +1110,8 @@ void VNCServerST::writeUpdate() } } + sendWatermark = false; // the client now caches it, only send once + if (trackingFrameStats) { if (enctime) { const unsigned totalMs = msSince(&start); diff --git a/common/rfb/VNCServerST.h b/common/rfb/VNCServerST.h index 2bb61b3..721e028 100644 --- a/common/rfb/VNCServerST.h +++ b/common/rfb/VNCServerST.h @@ -290,6 +290,8 @@ namespace rfb { void checkAPIMessages(network::GetAPIMessager *apimessager, rdr::U8 &trackingFrameStats, char trackingClient[]); + + bool sendWatermark; }; }; diff --git a/common/rfb/Watermark.cxx b/common/rfb/Watermark.cxx index 8e51aa4..acee33c 100644 --- a/common/rfb/Watermark.cxx +++ b/common/rfb/Watermark.cxx @@ -279,6 +279,31 @@ bool watermarkInit() { return true; } +static void packWatermark() { + // Take the expanded 4-bit data, filter it by the changed rects, pack + // to shared bytes, and compress with zlib + + uint16_t x, y; + uint8_t pix[2], cur = 0; + uint8_t *dst = watermarkTmp; + + for (y = 0; y < rh; y++) { + for (x = 0; x < rw; x++) { + pix[cur] = watermarkUnpacked[y * rw + x]; + if (cur || (y == rh - 1 && x == rw - 1)) + *dst++ = pix[0] | (pix[1] << 4); + + cur ^= 1; + } + } + + uLong destLen = MAXW * MAXH / 2; + if (compress2(watermarkData, &destLen, watermarkTmp, rw * rh / 2 + 1, 1) != Z_OK) + vlog.error("Zlib compression error"); + + watermarkDataLen = destLen; +} + // update the screen-size rendered watermark whenever the screen is resized // or if using text, every frame void VNCServerST::updateWatermark() { @@ -359,48 +384,10 @@ void VNCServerST::updateWatermark() { rw - sx); } } -} -void packWatermark(const Region &changed) { - // Take the expanded 4-bit data, filter it by the changed rects, pack - // to shared bytes, and compress with zlib + packWatermark(); - uint16_t x, y; - uint8_t pix[2], cur = 0; - uint8_t *dst = watermarkTmp; - - const Rect &bounding = changed.get_bounding_rect(); - - for (y = 0; y < rh; y++) { - // Is the entire line outside the changed area? - if (bounding.tl.y > y || bounding.br.y < y) { - for (x = 0; x < rw; x++) { - pix[cur] = 0; - - if (cur || (y == rh - 1 && x == rw - 1)) - *dst++ = pix[0] | (pix[1] << 4); - - cur ^= 1; - } - } else { - for (x = 0; x < rw; x++) { - pix[cur] = 0; - if (bounding.contains(Point(x, y)) && changed.contains(x, y)) - pix[cur] = watermarkUnpacked[y * rw + x]; - - if (cur || (y == rh - 1 && x == rw - 1)) - *dst++ = pix[0] | (pix[1] << 4); - - cur ^= 1; - } - } - } - - uLong destLen = MAXW * MAXH / 2; - if (compress2(watermarkData, &destLen, watermarkTmp, rw * rh / 2 + 1, 1) != Z_OK) - vlog.error("Zlib compression error"); - - watermarkDataLen = destLen; + sendWatermark = true; } // Limit changes to once per second @@ -412,5 +399,5 @@ bool watermarkTextNeedsUpdate(const bool early) { if (early) now = time(NULL); - return now != lastUpdate; + return now != lastUpdate && strchr(Server::DLP_WatermarkText, '%'); } diff --git a/common/rfb/Watermark.h b/common/rfb/Watermark.h index 2d8c077..a695f89 100644 --- a/common/rfb/Watermark.h +++ b/common/rfb/Watermark.h @@ -35,7 +35,6 @@ struct watermarkInfo_t { extern watermarkInfo_t watermarkInfo; bool watermarkInit(); -void packWatermark(const rfb::Region &changed); // filter and pack the watermark for sending bool watermarkTextNeedsUpdate(const bool early); extern uint8_t *watermarkData;