if (supportsLocalCursor) {
encodings.push_back(pseudoEncodingCursorWithAlpha);
+ encodings.push_back(pseudoEncodingVMwareCursor);
encodings.push_back(pseudoEncodingCursor);
encodings.push_back(pseudoEncodingXCursor);
}
case pseudoEncodingCursorWithAlpha:
readSetCursorWithAlpha(w, h, Point(x,y));
break;
+ case pseudoEncodingVMwareCursor:
+ readSetVMwareCursor(w, h, Point(x,y));
+ break;
case pseudoEncodingDesktopName:
readSetDesktopName(x, y, w, h);
break;
pb.getBuffer(pb.getRect(), &stride));
}
+void CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot)
+{
+ if (width > maxCursorSize || height > maxCursorSize)
+ throw Exception("Too big cursor");
+
+ rdr::U8 type;
+
+ type = is->readU8();
+ is->skip(1);
+
+ if (type == 0) {
+ int len = width * height * (handler->server.pf().bpp/8);
+ rdr::U8Array andMask(len);
+ rdr::U8Array xorMask(len);
+
+ rdr::U8Array data(width*height*4);
+
+ rdr::U8* andIn;
+ rdr::U8* xorIn;
+ rdr::U8* out;
+ int Bpp;
+
+ is->readBytes(andMask.buf, len);
+ is->readBytes(xorMask.buf, len);
+
+ andIn = andMask.buf;
+ xorIn = xorMask.buf;
+ out = data.buf;
+ Bpp = handler->server.pf().bpp/8;
+ for (int y = 0;y < height;y++) {
+ for (int x = 0;x < width;x++) {
+ Pixel andPixel, xorPixel;
+
+ andPixel = handler->server.pf().pixelFromBuffer(andIn);
+ xorPixel = handler->server.pf().pixelFromBuffer(xorIn);
+ andIn += Bpp;
+ xorIn += Bpp;
+
+ if (andPixel == 0) {
+ rdr::U8 r, g, b;
+
+ // Opaque pixel
+
+ handler->server.pf().rgbFromPixel(xorPixel, &r, &g, &b);
+ *out++ = r;
+ *out++ = g;
+ *out++ = b;
+ *out++ = 0xff;
+ } else if (xorPixel == 0) {
+ // Fully transparent pixel
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ } else if (andPixel == xorPixel) {
+ // Inverted pixel
+
+ // We don't really support this, so just turn the pixel black
+ // FIXME: Do an outline like WinVNC does?
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0xff;
+ } else {
+ // Partially transparent/inverted pixel
+
+ // We _really_ can't handle this, just make it black
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0;
+ *out++ = 0xff;
+ }
+ }
+ }
+
+ handler->setCursor(width, height, hotspot, data.buf);
+ } else if (type == 1) {
+ rdr::U8Array data(width*height*4);
+
+ // FIXME: Is alpha premultiplied?
+ is->readBytes(data.buf, width*height*4);
+
+ handler->setCursor(width, height, hotspot, data.buf);
+ } else {
+ throw Exception("Unknown cursor type");
+ }
+}
+
void CMsgReader::readSetDesktopName(int x, int y, int w, int h)
{
char* name = is->readString();
void readSetXCursor(int width, int height, const Point& hotspot);
void readSetCursor(int width, int height, const Point& hotspot);
void readSetCursorWithAlpha(int width, int height, const Point& hotspot);
+ void readSetVMwareCursor(int width, int height, const Point& hotspot);
void readSetDesktopName(int x, int y, int w, int h);
void readExtendedDesktopSize(int x, int y, int w, int h);
void readLEDState();
{
if (supportsEncoding(pseudoEncodingCursorWithAlpha))
return true;
+ if (supportsEncoding(pseudoEncodingVMwareCursor))
+ return true;
if (supportsEncoding(pseudoEncodingCursor))
return true;
if (supportsEncoding(pseudoEncodingXCursor))
{
if (!client->supportsEncoding(pseudoEncodingCursor) &&
!client->supportsEncoding(pseudoEncodingXCursor) &&
- !client->supportsEncoding(pseudoEncodingCursorWithAlpha))
+ !client->supportsEncoding(pseudoEncodingCursorWithAlpha) &&
+ !client->supportsEncoding(pseudoEncodingVMwareCursor))
throw Exception("Client does not support local cursor");
needCursor = true;
writeSetCursorWithAlphaRect(cursor.width(), cursor.height(),
cursor.hotspot().x, cursor.hotspot().y,
cursor.getBuffer());
+ } else if (client->supportsEncoding(pseudoEncodingVMwareCursor)) {
+ writeSetVMwareCursorRect(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());
}
}
+void SMsgWriter::writeSetVMwareCursorRect(int width, int height,
+ int hotspotX, int hotspotY,
+ const rdr::U8* data)
+{
+ if (!client->supportsEncoding(pseudoEncodingVMwareCursor))
+ throw Exception("Client does not support local cursors");
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriter::writeSetVMwareCursorRect: nRects out of sync");
+
+ os->writeS16(hotspotX);
+ os->writeS16(hotspotY);
+ os->writeU16(width);
+ os->writeU16(height);
+ os->writeU32(pseudoEncodingVMwareCursor);
+
+ os->writeU8(1); // Alpha cursor
+ os->pad(1);
+
+ // FIXME: Should alpha be premultiplied?
+ os->writeBytes(data, width*height*4);
+}
+
void SMsgWriter::writeLEDStateRect(rdr::U8 state)
{
if (!client->supportsEncoding(pseudoEncodingLEDState))
void writeSetCursorWithAlphaRect(int width, int height,
int hotspotX, int hotspotY,
const rdr::U8* data);
+ void writeSetVMwareCursorRect(int width, int height,
+ int hotspotX, int hotspotY,
+ const rdr::U8* data);
void writeLEDStateRect(rdr::U8 state);
void writeQEMUKeyEventRect();
const int pseudoEncodingSubsamp8X = -764;
const int pseudoEncodingSubsamp16X = -763;
+ // VMware-specific
+ const int pseudoEncodingVMwareCursor = 0x574d5664;
+
int encodingNum(const char* name);
const char* encodingName(int num);
}