Minimal server side implementation of the extended desktop size protocol.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3698 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
index b328a1f..10b60fb 100644
--- a/common/rfb/ConnParams.cxx
+++ b/common/rfb/ConnParams.cxx
@@ -29,8 +29,10 @@
ConnParams::ConnParams()
: majorVersion(0), minorVersion(0), tightExtensionsEnabled(false),
width(0), height(0), useCopyRect(false),
- supportsLocalCursor(false), supportsLocalXCursor(false), supportsDesktopResize(true), supportsDesktopRename(false),
- supportsLastRect(false), customCompressLevel(false), compressLevel(6),
+ supportsLocalCursor(false), supportsLocalXCursor(false),
+ supportsDesktopResize(false), supportsExtendedDesktopSize(false),
+ supportsDesktopRename(false), supportsLastRect(false),
+ customCompressLevel(false), compressLevel(6),
noJpeg(false), qualityLevel(-1),
name_(0), nEncodings_(0), encodings_(0),
currentEncoding_(encodingRaw), verStrPos(0)
@@ -92,6 +94,7 @@
useCopyRect = false;
supportsLocalCursor = false;
supportsDesktopResize = false;
+ supportsExtendedDesktopSize = false;
supportsLocalXCursor = false;
supportsLastRect = false;
customCompressLevel = false;
@@ -111,6 +114,8 @@
supportsLocalXCursor = true;
else if (encodings[i] == pseudoEncodingDesktopSize)
supportsDesktopResize = true;
+ else if (encodings[i] == pseudoEncodingExtendedDesktopSize)
+ supportsExtendedDesktopSize = true;
else if (encodings[i] == pseudoEncodingDesktopName)
supportsDesktopRename = true;
else if (encodings[i] == pseudoEncodingLastRect)
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
index f00b1d6..bdd9cf2 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ConnParams.h
@@ -73,6 +73,7 @@
bool supportsLocalCursor;
bool supportsLocalXCursor;
bool supportsDesktopResize;
+ bool supportsExtendedDesktopSize;
bool supportsDesktopRename;
bool supportsLastRect;
diff --git a/common/rfb/SMsgHandler.cxx b/common/rfb/SMsgHandler.cxx
index c55a8b7..0c74f0f 100644
--- a/common/rfb/SMsgHandler.cxx
+++ b/common/rfb/SMsgHandler.cxx
@@ -43,11 +43,13 @@
supportsLocalCursor();
}
-void SMsgHandler::framebufferUpdateRequest(const Rect& r, bool incremental)
+void SMsgHandler::supportsLocalCursor()
{
}
-void SMsgHandler::supportsLocalCursor()
+void SMsgHandler::setDesktopSize(int fb_width, int fb_height)
{
+ cp.width = fb_width;
+ cp.height = fb_height;
}
diff --git a/common/rfb/SMsgHandler.h b/common/rfb/SMsgHandler.h
index 50a2dc4..78cff2f 100644
--- a/common/rfb/SMsgHandler.h
+++ b/common/rfb/SMsgHandler.h
@@ -38,14 +38,15 @@
// The following methods are called as corresponding messages are read. A
// derived class should override these methods as desired. Note that for
- // the setPixelFormat() and setEncodings() methods, a derived class must
- // call on to SMsgHandler's methods.
+ // the setPixelFormat(), setEncodings() and setDesktopSize() methods, a
+ // derived class must call on to SMsgHandler's methods.
virtual void clientInit(bool shared);
virtual void setPixelFormat(const PixelFormat& pf);
virtual void setEncodings(int nEncodings, rdr::U32* encodings);
- virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+ virtual void framebufferUpdateRequest(const Rect& r, bool incremental) = 0;
+ virtual void setDesktopSize(int fb_width, int fb_height) = 0;
// InputHandler interface
// The InputHandler methods will be called for the corresponding messages.
diff --git a/common/rfb/SMsgReaderV3.cxx b/common/rfb/SMsgReaderV3.cxx
index 8e870cd..1408fe6 100644
--- a/common/rfb/SMsgReaderV3.cxx
+++ b/common/rfb/SMsgReaderV3.cxx
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,9 +52,30 @@
case msgTypeKeyEvent: readKeyEvent(); break;
case msgTypePointerEvent: readPointerEvent(); break;
case msgTypeClientCutText: readClientCutText(); break;
+ case msgTypeSetDesktopSize: readSetDesktopSize(); break;
default:
fprintf(stderr, "unknown message type %d\n", msgType);
throw Exception("unknown message type");
}
}
+
+void SMsgReaderV3::readSetDesktopSize()
+{
+ int width, height;
+ int screens, i;
+
+ is->skip(1);
+
+ width = is->readU16();
+ height = is->readU16();
+
+ screens = is->readU8();
+ is->skip(1);
+
+ // XXX: We don't support this command properly yet
+ is->skip(screens * 16);
+
+ handler->setDesktopSize(width, height);
+}
+
diff --git a/common/rfb/SMsgReaderV3.h b/common/rfb/SMsgReaderV3.h
index c6b7bf4..8b52632 100644
--- a/common/rfb/SMsgReaderV3.h
+++ b/common/rfb/SMsgReaderV3.h
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +28,8 @@
virtual ~SMsgReaderV3();
virtual void readClientInit();
virtual void readMsg();
+ protected:
+ virtual void readSetDesktopSize();
};
}
#endif
diff --git a/common/rfb/SMsgWriter.h b/common/rfb/SMsgWriter.h
index bab9a1a..3c6da95 100644
--- a/common/rfb/SMsgWriter.h
+++ b/common/rfb/SMsgWriter.h
@@ -24,6 +24,7 @@
#include <rdr/types.h>
#include <rfb/encodings.h>
+#include <rfb/screenTypes.h>
#include <rfb/Encoder.h>
#include <rfb/PixelBuffer.h>
@@ -74,6 +75,8 @@
// writeSetDesktopSize() on a V3 writer won't actually write immediately,
// but will write the relevant pseudo-rectangle as part of the next update.
virtual bool writeSetDesktopSize()=0;
+ // Same thing for the extended version
+ virtual bool writeExtendedDesktopSize(rdr::U16 error = resultUnsolicited)=0;
virtual bool writeSetDesktopName()=0;
diff --git a/common/rfb/SMsgWriterV3.cxx b/common/rfb/SMsgWriterV3.cxx
index 1271619..ca6f3f0 100644
--- a/common/rfb/SMsgWriterV3.cxx
+++ b/common/rfb/SMsgWriterV3.cxx
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +19,7 @@
#include <rdr/OutStream.h>
#include <rdr/MemOutStream.h>
#include <rfb/msgTypes.h>
+#include <rfb/screenTypes.h>
#include <rfb/Exception.h>
#include <rfb/ConnParams.h>
#include <rfb/SMsgWriterV3.h>
@@ -64,6 +66,15 @@
return true;
}
+bool SMsgWriterV3::writeExtendedDesktopSize(rdr::U16 error) {
+ if (!cp->supportsExtendedDesktopSize) return false;
+ if (error == resultUnsolicited)
+ needExtendedDesktopSize = true;
+ else
+ edsErrors.push_back(error);
+ return true;
+}
+
bool SMsgWriterV3::writeSetDesktopName() {
if (!cp->supportsDesktopRename) return false;
needSetDesktopName = true;
@@ -124,6 +135,8 @@
os->pad(1);
if (wsccb) nRects++;
if (needSetDesktopSize) nRects++;
+ if (needExtendedDesktopSize) nRects++;
+ if (!edsErrors.empty()) nRects += edsErrors.size();
if (needSetDesktopName) nRects++;
os->writeU16(nRects);
nRectsInUpdate = 0;
@@ -144,6 +157,50 @@
void SMsgWriterV3::writeFramebufferUpdateEnd()
{
+ /* Start with responses to SetDesktopSize messages */
+ if (!edsErrors.empty()) {
+ std::list<rdr::U16>::const_iterator iter;
+
+ if (!cp->supportsExtendedDesktopSize)
+ throw Exception("Client does not support extended desktop resize");
+ if ((nRectsInUpdate += edsErrors.size()) > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
+
+ for (iter = edsErrors.begin();iter != edsErrors.end();iter++) {
+ os->writeU16(1);
+ os->writeU16(*iter);
+ os->writeU16(0);
+ os->writeU16(0);
+ os->writeU32(pseudoEncodingExtendedDesktopSize);
+ os->writeU8(0); // # screens
+ os->pad(3);
+ }
+
+ edsErrors.clear();
+ }
+
+ /* Send this before SetDesktopSize to make life easier on the clients */
+ if (needExtendedDesktopSize) {
+ if (!cp->supportsExtendedDesktopSize)
+ throw Exception("Client does not support extended desktop resize");
+ if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
+ throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
+ os->writeU16(0);
+ os->writeU16(0);
+ os->writeU16(cp->width);
+ os->writeU16(cp->height);
+ os->writeU32(pseudoEncodingExtendedDesktopSize);
+ os->writeU8(1); // # screens
+ os->pad(3);
+ os->writeU32(1); // id
+ os->writeU16(0); // x-pos
+ os->writeU16(0); // y-pos
+ os->writeU16(cp->width); // width
+ os->writeU16(cp->height); // height
+ os->writeU32(0); // flags
+ needExtendedDesktopSize = false;
+ }
+
if (needSetDesktopSize) {
if (!cp->supportsDesktopResize)
throw Exception("Client does not support desktop resize");
diff --git a/common/rfb/SMsgWriterV3.h b/common/rfb/SMsgWriterV3.h
index d2c13df..509bfdc 100644
--- a/common/rfb/SMsgWriterV3.h
+++ b/common/rfb/SMsgWriterV3.h
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +19,8 @@
#ifndef __RFB_SMSGWRITERV3_H__
#define __RFB_SMSGWRITERV3_H__
+#include <list>
+
#include <rfb/SMsgWriter.h>
namespace rdr { class MemOutStream; }
@@ -32,6 +35,7 @@
virtual void startMsg(int type);
virtual void endMsg();
virtual bool writeSetDesktopSize();
+ virtual bool writeExtendedDesktopSize(rdr::U16 error);
virtual bool writeSetDesktopName();
virtual void cursorChange(WriteSetCursorCallback* cb);
virtual void writeSetCursor(int width, int height, const Point& hotspot,
@@ -52,6 +56,8 @@
int nRectsInHeader;
WriteSetCursorCallback* wsccb;
bool needSetDesktopSize;
+ bool needExtendedDesktopSize;
+ std::list<rdr::U16> edsErrors;
bool needSetDesktopName;
bool needLastRect;
};
diff --git a/common/rfb/VNCSConnectionST.cxx b/common/rfb/VNCSConnectionST.cxx
index e021aa6..3b4448b 100644
--- a/common/rfb/VNCSConnectionST.cxx
+++ b/common/rfb/VNCSConnectionST.cxx
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,6 +20,7 @@
#include <rfb/VNCSConnectionST.h>
#include <rfb/LogWriter.h>
#include <rfb/secTypes.h>
+#include <rfb/screenTypes.h>
#include <rfb/ServerCore.h>
#include <rfb/ComparingUpdateTracker.h>
#include <rfb/KeyRemapper.h>
@@ -168,7 +170,8 @@
cp.width = server->pb->width();
cp.height = server->pb->height();
if (state() == RFBSTATE_NORMAL) {
- if (!writer()->writeSetDesktopSize()) {
+ if (!writer()->writeSetDesktopSize() &&
+ !writer()->writeExtendedDesktopSize()) {
close("Client does not support desktop resize");
return;
}
@@ -490,9 +493,18 @@
// Non-incremental update - treat as if area requested has changed
updates.add_changed(reqRgn);
server->comparer->add_changed(reqRgn);
+ // And update the clients view of screen layout
+ writer()->writeSetDesktopSize();
+ writer()->writeExtendedDesktopSize();
}
}
+void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height)
+{
+ vlog.info("Rejecting client request to change desktop size");
+ writer()->writeExtendedDesktopSize(resultProhibited);
+}
+
void VNCSConnectionST::setInitialColourMap()
{
setColourMapEntries(0, 0);
diff --git a/common/rfb/VNCSConnectionST.h b/common/rfb/VNCSConnectionST.h
index 2121150..d5c7a36 100644
--- a/common/rfb/VNCSConnectionST.h
+++ b/common/rfb/VNCSConnectionST.h
@@ -1,4 +1,5 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
+ * Copyright 2009 Pierre Ossman for Cendio AB
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -124,6 +125,7 @@
virtual void keyEvent(rdr::U32 key, bool down);
virtual void clientCutText(const char* str, int len);
virtual void framebufferUpdateRequest(const Rect& r, bool incremental);
+ virtual void setDesktopSize(int fb_width, int fb_height);
virtual void setInitialColourMap();
virtual void supportsLocalCursor();
diff --git a/common/rfb/encodings.h b/common/rfb/encodings.h
index 1021be9..2f3b430 100644
--- a/common/rfb/encodings.h
+++ b/common/rfb/encodings.h
@@ -33,6 +33,7 @@
const unsigned int pseudoEncodingXCursor = 0xffffff10;
const unsigned int pseudoEncodingCursor = 0xffffff11;
const unsigned int pseudoEncodingDesktopSize = 0xffffff21;
+ const unsigned int pseudoEncodingExtendedDesktopSize = 0xfffffecb; // FIXME: Unofficial
const unsigned int pseudoEncodingDesktopName = 0xfffffecdl;
// TightVNC-specific
diff --git a/common/rfb/msgTypes.h b/common/rfb/msgTypes.h
index 2b24f3c..6bda345 100644
--- a/common/rfb/msgTypes.h
+++ b/common/rfb/msgTypes.h
@@ -39,5 +39,7 @@
const int msgTypeClientCutText = 6;
const int msgTypeEnableContinuousUpdates = 150;
+
+ const int msgTypeSetDesktopSize = 251; // FIXME: Unofficial
}
#endif
diff --git a/common/rfb/screenTypes.h b/common/rfb/screenTypes.h
new file mode 100644
index 0000000..70971e4
--- /dev/null
+++ b/common/rfb/screenTypes.h
@@ -0,0 +1,37 @@
+/* Copyright 2009 Pierre Ossman for Cendio AB
+ *
+ * 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.
+ */
+#ifndef __RFB_SCREENTYPES_H__
+#define __RFB_SCREENTYPES_H__
+
+namespace rfb {
+
+ // Reasons
+ const unsigned int reasonServer = 0;
+ const unsigned int reasonClient = 1;
+ const unsigned int reasonOtherClient = 2;
+
+ // Result codes
+ const unsigned int resultSuccess = 0;
+ const unsigned int resultProhibited = 1;
+ const unsigned int resultNoResources = 2;
+ const unsigned int resultInvalid = 3;
+
+ const int resultUnsolicited = 0xffff; // internal code used for server changes
+
+}
+#endif