]> source.dussan.org Git - tigervnc.git/commitdiff
Server support for cursor with alpha
authorPierre Ossman <ossman@cendio.se>
Tue, 21 Feb 2017 11:59:04 +0000 (12:59 +0100)
committerPierre Ossman <ossman@cendio.se>
Wed, 22 Feb 2017 16:00:43 +0000 (17:00 +0100)
common/rfb/ConnParams.cxx
common/rfb/ConnParams.h
common/rfb/SMsgWriter.cxx
common/rfb/SMsgWriter.h
common/rfb/VNCSConnectionST.cxx

index dc9ebf58a4a2395efcbeec3e1c5385b897b02359..9ee1d9c0fda3739279cc2033292fa295c806457e 100644 (file)
@@ -31,6 +31,7 @@ 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),
     supportsSetDesktopSize(false), supportsFence(false),
@@ -101,6 +102,7 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
 {
   useCopyRect = false;
   supportsLocalCursor = false;
+  supportsLocalCursorWithAlpha = false;
   supportsDesktopResize = false;
   supportsExtendedDesktopSize = false;
   supportsLocalXCursor = false;
@@ -124,6 +126,9 @@ void ConnParams::setEncodings(int nEncodings, const rdr::S32* encodings)
     case pseudoEncodingXCursor:
       supportsLocalXCursor = true;
       break;
+    case pseudoEncodingCursorWithAlpha:
+      supportsLocalCursorWithAlpha = true;
+      break;
     case pseudoEncodingDesktopSize:
       supportsDesktopResize = true;
       break;
index 517e649045a3ceadb03c0f1fa8a3fe571f024e5a..5e538933d52141f424d4031d78988addbc59809d 100644 (file)
@@ -88,6 +88,7 @@ namespace rfb {
 
     bool supportsLocalCursor;
     bool supportsLocalXCursor;
+    bool supportsLocalCursorWithAlpha;
     bool supportsDesktopResize;
     bool supportsExtendedDesktopSize;
     bool supportsDesktopRename;
index 51e1105a5b9113a1237191733c309af3d51ffc9e..cf3264e8f0ddcbdecb5d9063a83935c69face29a 100644 (file)
@@ -36,7 +36,8 @@ SMsgWriter::SMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
   : cp(cp_), os(os_),
     nRectsInUpdate(0), nRectsInHeader(0),
     needSetDesktopSize(false), needExtendedDesktopSize(false),
-    needSetDesktopName(false), needSetCursor(false), needSetXCursor(false)
+    needSetDesktopName(false), needSetCursor(false),
+    needSetXCursor(false), needSetCursorWithAlpha(false)
 {
 }
 
@@ -180,11 +181,21 @@ bool SMsgWriter::writeSetXCursor()
   return true;
 }
 
+bool SMsgWriter::writeSetCursorWithAlpha()
+{
+  if (!cp->supportsLocalCursorWithAlpha)
+    return false;
+
+  needSetCursorWithAlpha = true;
+
+  return true;
+}
+
 bool SMsgWriter::needFakeUpdate()
 {
   if (needSetDesktopName)
     return true;
-  if (needSetCursor || needSetXCursor)
+  if (needSetCursor || needSetXCursor || needSetCursorWithAlpha)
     return true;
   if (needNoDataUpdate())
     return true;
@@ -232,6 +243,8 @@ void SMsgWriter::writeFramebufferUpdateStart(int nRects)
       nRects++;
     if (needSetXCursor)
       nRects++;
+    if (needSetCursorWithAlpha)
+      nRects++;
   }
 
   os->writeU16(nRects);
@@ -334,6 +347,15 @@ void SMsgWriter::writePseudoRects()
     needSetXCursor = false;
   }
 
+  if (needSetCursorWithAlpha) {
+    const Cursor& cursor = cp->cursor();
+
+    writeSetCursorWithAlphaRect(cursor.width(), cursor.height(),
+                                cursor.hotspot().x, cursor.hotspot().y,
+                                cursor.getBuffer());
+    needSetCursorWithAlpha = false;
+  }
+
   if (needSetDesktopName) {
     writeSetDesktopNameRect(cp->name());
     needSetDesktopName = false;
@@ -473,3 +495,31 @@ void SMsgWriter::writeSetXCursorRect(int width, int height,
     os->writeBytes(mask, (width+7)/8 * height);
   }
 }
+
+void SMsgWriter::writeSetCursorWithAlphaRect(int width, int height,
+                                             int hotspotX, int hotspotY,
+                                             const rdr::U8* data)
+{
+  if (!cp->supportsLocalCursorWithAlpha)
+    throw Exception("Client does not support local cursors");
+  if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+    throw Exception("SMsgWriter::writeSetCursorWithAlphaRect: nRects out of sync");
+
+  os->writeS16(hotspotX);
+  os->writeS16(hotspotY);
+  os->writeU16(width);
+  os->writeU16(height);
+  os->writeU32(pseudoEncodingCursorWithAlpha);
+
+  // FIXME: Use an encoder with compression?
+  os->writeU32(encodingRaw);
+
+  // Alpha needs to be pre-multiplied
+  for (int i = 0;i < width*height;i++) {
+    os->writeU8((unsigned)data[0] * data[3] / 255);
+    os->writeU8((unsigned)data[1] * data[3] / 255);
+    os->writeU8((unsigned)data[2] * data[3] / 255);
+    os->writeU8(data[3]);
+    data += 4;
+  }
+}
index a516e103cab764ddc5c33974e4a50dcc83a8aa9a..548b8e8e8e0bcf2540dcfc6a8e7d9bc5c1ebf500 100644 (file)
@@ -80,6 +80,7 @@ namespace rfb {
     // immediately. 
     bool writeSetCursor();
     bool writeSetXCursor();
+    bool writeSetCursorWithAlpha();
 
     // needFakeUpdate() returns true when an immediate update is needed in
     // order to flush out pseudo-rectangles to the client.
@@ -127,6 +128,9 @@ namespace rfb {
     void writeSetXCursorRect(int width, int height,
                              int hotspotX, int hotspotY,
                              const void* data, const void* mask);
+    void writeSetCursorWithAlphaRect(int width, int height,
+                                     int hotspotX, int hotspotY,
+                                     const rdr::U8* data);
 
     ConnParams* cp;
     rdr::OutStream* os;
@@ -140,6 +144,7 @@ namespace rfb {
     bool needLastRect;
     bool needSetCursor;
     bool needSetXCursor;
+    bool needSetCursorWithAlpha;
 
     typedef struct {
       rdr::U16 reason, result;
index e7a5dcf11d072f2f90926e41c571ff4cc6406ede..5ab1b4b2281e40b8c0911f157e95744bb1aa9476 100644 (file)
@@ -1121,10 +1121,12 @@ void VNCSConnectionST::setCursor()
 
   cp.setCursor(*server->cursor);
 
-  if (!writer()->writeSetCursor()) {
-    if (!writer()->writeSetXCursor()) {
-      // No client support
-      return;
+  if (!writer()->writeSetCursorWithAlpha()) {
+    if (!writer()->writeSetCursor()) {
+      if (!writer()->writeSetXCursor()) {
+        // No client support
+        return;
+      }
     }
   }