aboutsummaryrefslogtreecommitdiffstats
path: root/common/rfb/SMsgWriterV3.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'common/rfb/SMsgWriterV3.cxx')
-rw-r--r--common/rfb/SMsgWriterV3.cxx197
1 files changed, 197 insertions, 0 deletions
diff --git a/common/rfb/SMsgWriterV3.cxx b/common/rfb/SMsgWriterV3.cxx
new file mode 100644
index 00000000..a85f85ea
--- /dev/null
+++ b/common/rfb/SMsgWriterV3.cxx
@@ -0,0 +1,197 @@
+/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+#include <rdr/OutStream.h>
+#include <rdr/MemOutStream.h>
+#include <rfb/msgTypes.h>
+#include <rfb/Exception.h>
+#include <rfb/ConnParams.h>
+#include <rfb/SMsgWriterV3.h>
+
+using namespace rfb;
+
+SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
+ : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0),
+ nRectsInHeader(0), wsccb(0),
+ needSetDesktopSize(false)
+{
+}
+
+SMsgWriterV3::~SMsgWriterV3()
+{
+ delete updateOS;
+}
+
+void SMsgWriterV3::writeServerInit()
+{
+ os->writeU16(cp->width);
+ os->writeU16(cp->height);
+ cp->pf().write(os);
+ os->writeString(cp->name());
+ endMsg();
+}
+
+void SMsgWriterV3::startMsg(int type)
+{
+ if (os != realOS)
+ throw Exception("startMsg called while writing an update?");
+
+ os->writeU8(type);
+}
+
+void SMsgWriterV3::endMsg()
+{
+ os->flush();
+}
+
+bool SMsgWriterV3::writeSetDesktopSize() {
+ if (!cp->supportsDesktopResize) return false;
+ needSetDesktopSize = true;
+ return true;
+}
+
+void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
+{
+ wsccb = cb;
+}
+
+void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot,
+ void* data, void* mask)
+{
+ if (!wsccb) return;
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
+ 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);
+}
+
+void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
+ int hotspotY, void* data, void* mask)
+{
+ if (!wsccb) return;
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
+ 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);
+ }
+}
+
+void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
+{
+ startMsg(msgTypeFramebufferUpdate);
+ os->pad(1);
+ if (wsccb) nRects++;
+ if (needSetDesktopSize) nRects++;
+ os->writeU16(nRects);
+ nRectsInUpdate = 0;
+ nRectsInHeader = nRects;
+ if (wsccb) {
+ wsccb->writeSetCursorCallback();
+ wsccb = 0;
+ }
+}
+
+void SMsgWriterV3::writeFramebufferUpdateStart()
+{
+ nRectsInUpdate = nRectsInHeader = 0;
+ if (!updateOS)
+ updateOS = new rdr::MemOutStream;
+ os = updateOS;
+}
+
+void SMsgWriterV3::writeFramebufferUpdateEnd()
+{
+ if (needSetDesktopSize) {
+ if (!cp->supportsDesktopResize)
+ throw Exception("Client does not support desktop resize");
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
+ os->writeS16(0);
+ os->writeS16(0);
+ os->writeU16(cp->width);
+ os->writeU16(cp->height);
+ os->writeU32(pseudoEncodingDesktopSize);
+ needSetDesktopSize = false;
+ }
+
+ if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
+ "nRects out of sync");
+ if (os == updateOS) {
+ os = realOS;
+ startMsg(msgTypeFramebufferUpdate);
+ os->pad(1);
+ os->writeU16(nRectsInUpdate);
+ os->writeBytes(updateOS->data(), updateOS->length());
+ updateOS->clear();
+ }
+
+ updatesSent++;
+ endMsg();
+}
+
+bool SMsgWriterV3::needFakeUpdate()
+{
+ return wsccb || needSetDesktopSize;
+}
+
+void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
+{
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3::startRect: nRects out of sync");
+
+ currentEncoding = encoding;
+ lenBeforeRect = os->length();
+ if (encoding != encodingCopyRect)
+ rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
+
+ os->writeS16(r.tl.x);
+ os->writeS16(r.tl.y);
+ os->writeU16(r.width());
+ os->writeU16(r.height());
+ os->writeU32(encoding);
+}
+
+void SMsgWriterV3::endRect()
+{
+ if (currentEncoding <= encodingMax) {
+ bytesSent[currentEncoding] += os->length() - lenBeforeRect;
+ rectsSent[currentEncoding]++;
+ }
+}