summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2014-02-13 14:40:25 +0100
committerPierre Ossman <ossman@cendio.se>2014-07-14 16:03:35 +0200
commit126e56420e47d72cc950d03976ee57d1efda436e (patch)
tree81983d8f132c9ca381e50debbbdf1f66b797832a /common
parentd4f718ddd02d50cb538ccd1e356a545aca119c2f (diff)
downloadtigervnc-126e56420e47d72cc950d03976ee57d1efda436e.tar.gz
tigervnc-126e56420e47d72cc950d03976ee57d1efda436e.zip
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.
Diffstat (limited to 'common')
-rw-r--r--common/rfb/ConnParams.cxx15
-rw-r--r--common/rfb/ConnParams.h5
-rw-r--r--common/rfb/SMsgWriter.cxx165
-rw-r--r--common/rfb/SMsgWriter.h30
-rw-r--r--common/rfb/VNCSConnectionST.cxx52
-rw-r--r--common/rfb/VNCSConnectionST.h4
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 <rdr/types.h>
+#include <rfb/Cursor.h>
#include <rfb/PixelFormat.h>
#include <rfb/ScreenSet.h>
@@ -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);