From 126e56420e47d72cc950d03976ee57d1efda436e Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Thu, 13 Feb 2014 14:40:25 +0100 Subject: [PATCH] Store the mouse cursor in the ConnParams object Like we do for everything else. This also gets rid of the callback, which is a bit out of place compared to everything else. --- common/rfb/ConnParams.cxx | 15 +++ common/rfb/ConnParams.h | 5 + common/rfb/SMsgWriter.cxx | 165 +++++++++++++++++++++----------- common/rfb/SMsgWriter.h | 30 +++--- common/rfb/VNCSConnectionST.cxx | 52 ++-------- common/rfb/VNCSConnectionST.h | 4 - 6 files changed, 153 insertions(+), 118 deletions(-) diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx index 6fd6668e..36f6daa6 100644 --- a/common/rfb/ConnParams.cxx +++ b/common/rfb/ConnParams.cxx @@ -86,6 +86,21 @@ void ConnParams::setName(const char* name) name_ = strDup(name); } +void ConnParams::setCursor(const Cursor& other) +{ + const rdr::U8* data; + int stride; + + cursor_.hotspot = other.hotspot; + cursor_.setPF(other.getPF()); + cursor_.setSize(other.width(), other.height()); + + data = other.getBuffer(other.getRect(), &stride); + cursor_.imageRect(cursor_.getRect(), data, stride); + + memcpy(cursor_.mask.buf, other.mask.buf, cursor_.maskLen()); +} + void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings) { useCopyRect = false; diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h index 43267ffd..7a6d60cc 100644 --- a/common/rfb/ConnParams.h +++ b/common/rfb/ConnParams.h @@ -24,6 +24,7 @@ #define __RFB_CONNPARAMS_H__ #include +#include #include #include @@ -74,6 +75,9 @@ namespace rfb { const char* name() { return name_; } void setName(const char* name); + const Cursor& cursor() { return cursor_; } + void setCursor(const Cursor& cursor); + rdr::S32 currentEncoding() { return currentEncoding_; } void setEncodings(int nEncodings, const rdr::S32* encodings); @@ -100,6 +104,7 @@ namespace rfb { PixelFormat pf_; char* name_; + Cursor cursor_; int currentEncoding_; char verStr[13]; int verStrPos; diff --git a/common/rfb/SMsgWriter.cxx b/common/rfb/SMsgWriter.cxx index 40e6d7f6..46c41388 100644 --- a/common/rfb/SMsgWriter.cxx +++ b/common/rfb/SMsgWriter.cxx @@ -36,8 +36,8 @@ static LogWriter vlog("SMsgWriter"); SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_) : imageBufIdealSize(0), cp(cp_), os(os_), currentEncoding(0), nRectsInUpdate(0), nRectsInHeader(0), - wsccb(0), needSetDesktopSize(false), - needExtendedDesktopSize(false), needSetDesktopName(false), + needSetDesktopSize(false), needExtendedDesktopSize(false), + needSetDesktopName(false), needSetCursor(false), needSetXCursor(false), lenBeforeRect(0), updatesSent(0), rawBytesEquivalent(0), imageBuf(0), imageBufSize(0) { @@ -179,69 +179,46 @@ bool SMsgWriter::writeSetDesktopName() { return true; } -void SMsgWriter::cursorChange(WriteSetCursorCallback* cb) +bool SMsgWriter::writeSetCursor() { - wsccb = cb; -} - -void SMsgWriter::writeSetCursor(int width, int height, const Point& hotspot, - void* data, void* mask) -{ - if (!wsccb) - return; + if (!cp->supportsLocalCursor) + return false; - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetCursor: nRects out of sync"); + needSetCursor = true; - os->writeS16(hotspot.x); - os->writeS16(hotspot.y); - os->writeU16(width); - os->writeU16(height); - os->writeU32(pseudoEncodingCursor); - os->writeBytes(data, width * height * (cp->pf().bpp/8)); - os->writeBytes(mask, (width+7)/8 * height); + return true; } -void SMsgWriter::writeSetXCursor(int width, int height, int hotspotX, - int hotspotY, void* data, void* mask) +bool SMsgWriter::writeSetXCursor() { - if (!wsccb) - return; + if (!cp->supportsLocalXCursor) + return false; - if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) - throw Exception("SMsgWriter::writeSetXCursor: nRects out of sync"); + needSetXCursor = true; - os->writeS16(hotspotX); - os->writeS16(hotspotY); - os->writeU16(width); - os->writeU16(height); - os->writeU32(pseudoEncodingXCursor); - // FIXME: We only support black and white cursors, currently. We - // could pass the correct color by using the pix0/pix1 values - // returned from getBitmap, in writeSetCursorCallback. However, we - // would then need to undo the conversion from rgb to Pixel that is - // done by FakeAllocColor. - if (width * height) { - os->writeU8(0); - os->writeU8(0); - os->writeU8(0); - os->writeU8(255); - os->writeU8(255); - os->writeU8(255); - os->writeBytes(data, (width+7)/8 * height); - os->writeBytes(mask, (width+7)/8 * height); - } + return true; } bool SMsgWriter::needFakeUpdate() { - return wsccb || needSetDesktopName || needNoDataUpdate(); + if (needSetDesktopName) + return true; + if (needSetCursor || needSetXCursor) + return true; + if (needNoDataUpdate()) + return true; + + return false; } bool SMsgWriter::needNoDataUpdate() { - return needSetDesktopSize || needExtendedDesktopSize || - !extendedDesktopSizeMsgs.empty(); + if (needSetDesktopSize) + return true; + if (needExtendedDesktopSize || !extendedDesktopSizeMsgs.empty()) + return true; + + return false; } void SMsgWriter::writeNoDataUpdate() @@ -268,10 +245,12 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects) os->pad(1); if (nRects != 0xFFFF) { - if (wsccb) - nRects++; if (needSetDesktopName) nRects++; + if (needSetCursor) + nRects++; + if (needSetXCursor) + nRects++; } os->writeU16(nRects); @@ -369,9 +348,41 @@ void SMsgWriter::endMsg() void SMsgWriter::writePseudoRects() { - if (wsccb) { - wsccb->writeSetCursorCallback(); - wsccb = 0; + if (needSetCursor) { + rdr::U8* data; + int stride; + + const Cursor& cursor = cp->cursor(); + + data = new rdr::U8[cursor.area() * cp->pf().bpp/8]; + cursor.getImage(cp->pf(), data, cursor.getRect()); + + writeSetCursorRect(cursor.width(), cursor.height(), + cursor.hotspot.x, cursor.hotspot.y, + data, cursor.mask.buf); + needSetCursor = false; + + delete [] data; + } + + if (needSetXCursor) { + const Cursor& cursor = cp->cursor(); + Pixel pix0, pix1; + rdr::U8 rgb0[3], rgb1[3]; + rdr::U8Array bitmap(cursor.getBitmap(&pix0, &pix1)); + + if (!bitmap.buf) { + // FIXME: We could reduce to two colors. + throw Exception("SMsgWriter::writePseudoRects: Unable to send multicolor cursor: RichCursor not supported by client"); + } + + cp->pf().rgbFromPixel(pix0, &rgb0[0], &rgb0[1], &rgb0[2]); + cp->pf().rgbFromPixel(pix1, &rgb1[0], &rgb1[1], &rgb1[2]); + + writeSetXCursorRect(cursor.width(), cursor.height(), + cursor.hotspot.x, cursor.hotspot.y, + rgb0, rgb1, bitmap.buf, cursor.mask.buf); + needSetXCursor = false; } if (needSetDesktopName) { @@ -469,3 +480,49 @@ void SMsgWriter::writeSetDesktopNameRect(const char *name) os->writeU32(pseudoEncodingDesktopName); os->writeString(name); } + +void SMsgWriter::writeSetCursorRect(int width, int height, + int hotspotX, int hotspotY, + const void* data, const void* mask) +{ + if (!cp->supportsLocalCursor) + throw Exception("Client does not support local cursors"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeSetCursorRect: nRects out of sync"); + + os->writeS16(hotspotX); + os->writeS16(hotspotY); + os->writeU16(width); + os->writeU16(height); + os->writeU32(pseudoEncodingCursor); + os->writeBytes(data, width * height * (cp->pf().bpp/8)); + os->writeBytes(mask, (width+7)/8 * height); +} + +void SMsgWriter::writeSetXCursorRect(int width, int height, + int hotspotX, int hotspotY, + const rdr::U8 pix0[], + const rdr::U8 pix1[], + const void* data, const void* mask) +{ + if (!cp->supportsLocalXCursor) + throw Exception("Client does not support local cursors"); + if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader) + throw Exception("SMsgWriter::writeSetXCursorRect: nRects out of sync"); + + os->writeS16(hotspotX); + os->writeS16(hotspotY); + os->writeU16(width); + os->writeU16(height); + os->writeU32(pseudoEncodingXCursor); + if (width * height) { + os->writeU8(pix0[0]); + os->writeU8(pix0[1]); + os->writeU8(pix0[2]); + os->writeU8(pix1[0]); + os->writeU8(pix1[1]); + os->writeU8(pix1[2]); + os->writeBytes(data, (width+7)/8 * height); + os->writeBytes(mask, (width+7)/8 * height); + } +} diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h index c3ee4577..e9fc5a47 100644 --- a/common/rfb/SMsgWriter.h +++ b/common/rfb/SMsgWriter.h @@ -34,11 +34,6 @@ namespace rfb { class ConnParams; class ScreenSet; - class WriteSetCursorCallback { - public: - virtual void writeSetCursorCallback() = 0; - }; - class SMsgWriter { public: SMsgWriter(ConnParams* cp, rdr::OutStream* os); @@ -81,16 +76,10 @@ namespace rfb { bool writeSetDesktopName(); - // Like setDesktopSize, we can't just write out a setCursor message - // immediately. Instead of calling writeSetCursor() directly, - // you must call cursorChange(), and then invoke writeSetCursor() - // in response to the writeSetCursorCallback() callback. This will - // happen when the next update is sent. - void cursorChange(WriteSetCursorCallback* cb); - void writeSetCursor(int width, int height, const Point& hotspot, - void* data, void* mask); - void writeSetXCursor(int width, int height, int hotspotX, int hotspotY, - void* data, void* mask); + // Like setDesktopSize, we can't just write out a cursor message + // immediately. + bool writeSetCursor(); + bool writeSetXCursor(); // needFakeUpdate() returns true when an immediate update is needed in // order to flush out pseudo-rectangles to the client. @@ -141,6 +130,13 @@ namespace rfb { int fb_width, int fb_height, const ScreenSet& layout); void writeSetDesktopNameRect(const char *name); + void writeSetCursorRect(int width, int height, + int hotspotX, int hotspotY, + const void* data, const void* mask); + void writeSetXCursorRect(int width, int height, + int hotspotX, int hotspotY, + const rdr::U8 pix0[], const rdr::U8 pix1[], + const void* data, const void* mask); ConnParams* cp; rdr::OutStream* os; @@ -150,12 +146,12 @@ namespace rfb { int nRectsInUpdate; int nRectsInHeader; - WriteSetCursorCallback* wsccb; - bool needSetDesktopSize; bool needExtendedDesktopSize; bool needSetDesktopName; bool needLastRect; + bool needSetCursor; + bool needSetXCursor; int lenBeforeRect; int updatesSent; diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx index f8674dea..e7123000 100644 --- a/common/rfb/VNCSConnectionST.cxx +++ b/common/rfb/VNCSConnectionST.cxx @@ -712,46 +712,6 @@ void VNCSConnectionST::supportsContinuousUpdates() writer()->writeEndOfContinuousUpdates(); } -void VNCSConnectionST::writeSetCursorCallback() -{ - if (cp.supportsLocalXCursor) { - Pixel pix0, pix1; - rdr::U8Array bitmap(server->cursor.getBitmap(&pix0, &pix1)); - if (bitmap.buf) { - // The client supports XCursor and the cursor only has two - // colors. Use the XCursor encoding. - writer()->writeSetXCursor(server->cursor.width(), - server->cursor.height(), - server->cursor.hotspot.x, - server->cursor.hotspot.y, - bitmap.buf, server->cursor.mask.buf); - return; - } else { - // More than two colors - if (!cp.supportsLocalCursor) { - // FIXME: We could reduce to two colors. - vlog.info("Unable to send multicolor cursor: RichCursor not supported by client"); - return; - } - } - } - - // Use RichCursor - rdr::U8* transBuffer; - int stride; - const rdr::U8* buffer; - - transBuffer = writer()->getImageBuf(server->cursor.area()); - - buffer = server->cursor.getBuffer(server->cursor.getRect(), &stride); - image_getter.translatePixels(buffer, transBuffer, server->cursor.area()); - - writer()->writeSetCursor(server->cursor.width(), - server->cursor.height(), - server->cursor.hotspot, - transBuffer, server->cursor.mask.buf); -} - bool VNCSConnectionST::handleTimeout(Timer* t) { @@ -1166,10 +1126,16 @@ void VNCSConnectionST::setCursor() { if (state() != RFBSTATE_NORMAL) return; - if (!cp.supportsLocalCursor) - return; - writer()->cursorChange(this); + cp.setCursor(server->cursor); + + if (!writer()->writeSetCursor()) { + if (!writer()->writeSetXCursor()) { + // No client support + return; + } + } + writeFramebufferUpdate(); } diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h index ca5c4f01..c918c599 100644 --- a/common/rfb/VNCSConnectionST.h +++ b/common/rfb/VNCSConnectionST.h @@ -40,7 +40,6 @@ namespace rfb { class Encoder; class VNCSConnectionST : public SConnection, - public WriteSetCursorCallback, public Timer::Callback { public: VNCSConnectionST(VNCServerST* server_, network::Socket* s, bool reverse); @@ -152,9 +151,6 @@ namespace rfb { // default access settings and the connection's access settings. virtual void setAccessRights(AccessRights ar) {accessRights=ar;} - // WriteSetCursorCallback - virtual void writeSetCursorCallback(); - // Timer callbacks virtual bool handleTimeout(Timer* t); -- 2.39.5