Properly parse the ExtendedDesktopSize rects in the client.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3702 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/CMsgHandler.cxx b/common/rfb/CMsgHandler.cxx
index fa675dc..f459d18 100644
--- a/common/rfb/CMsgHandler.cxx
+++ b/common/rfb/CMsgHandler.cxx
@@ -16,6 +16,8 @@
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
  * USA.
  */
+#include <stdio.h>
+
 #include <rfb/Exception.h>
 #include <rfb/CMsgHandler.h>
 #include <rfb/screenTypes.h>
@@ -36,13 +38,21 @@
   cp.height = height;
 }
 
-void CMsgHandler::setExtendedDesktopSize(int reason, int result, int width, int height)
+void CMsgHandler::setExtendedDesktopSize(int reason, int result,
+                                         int width, int height,
+                                         const ScreenSet& layout)
 {
+  cp.supportsSetDesktopSize = true;
+
   if ((reason == reasonClient) && (result != resultSuccess))
     return;
 
+  if (!layout.validate(width, height))
+    fprintf(stderr, "Server sent us an invalid screen layout\n");
+
   cp.width = width;
   cp.height = height;
+  cp.screenLayout = layout;
 }
 
 void CMsgHandler::setCursor(int w, int h, const Point& hotspot, void* data, void* mask)
diff --git a/common/rfb/CMsgHandler.h b/common/rfb/CMsgHandler.h
index 49d407a..36fc48e 100644
--- a/common/rfb/CMsgHandler.h
+++ b/common/rfb/CMsgHandler.h
@@ -27,6 +27,7 @@
 #include <rfb/Pixel.h>
 #include <rfb/ConnParams.h>
 #include <rfb/Rect.h>
+#include <rfb/ScreenSet.h>
 
 namespace rdr { class InStream; }
 
@@ -44,7 +45,9 @@
     // methods to set the members of cp appropriately.
 
     virtual void setDesktopSize(int w, int h);
-    virtual void setExtendedDesktopSize(int reason, int result, int w, int h);
+    virtual void setExtendedDesktopSize(int reason, int result,
+                                        int w, int h,
+                                        const ScreenSet& layout);
     virtual void setCursor(int width, int height, const Point& hotspot,
                            void* data, void* mask);
     virtual void setPixelFormat(const PixelFormat& pf);
diff --git a/common/rfb/CMsgReaderV3.cxx b/common/rfb/CMsgReaderV3.cxx
index 05fd948..5471593 100644
--- a/common/rfb/CMsgReaderV3.cxx
+++ b/common/rfb/CMsgReaderV3.cxx
@@ -23,6 +23,7 @@
 #include <rfb/CMsgReaderV3.h>
 #include <rfb/CMsgHandler.h>
 #include <rfb/util.h>
+#include <rfb/ScreenSet.h>
 #include <stdio.h>
 
 using namespace rfb;
@@ -121,14 +122,25 @@
 
 void CMsgReaderV3::readExtendedDesktopSize(int x, int y, int w, int h)
 {
-  unsigned int screens;
+  unsigned int screens, i;
+  rdr::U32 id, flags;
+  int sx, sy, sw, sh;
+  ScreenSet layout;
 
   screens = is->readU8();
   is->skip(3);
 
-  // XXX: We just ignore screen info right now
-  is->skip(16 * screens);
+  for (i = 0;i < screens;i++) {
+    id = is->readU32();
+    sx = is->readU16();
+    sy = is->readU16();
+    sw = is->readU16();
+    sh = is->readU16();
+    flags = is->readU32();
 
-  handler->setExtendedDesktopSize(x, y, w, h);
+    layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
+  }
+
+  handler->setExtendedDesktopSize(x, y, w, h, layout);
 }
 
diff --git a/common/rfb/ConnParams.cxx b/common/rfb/ConnParams.cxx
index 10b60fb..7b27a73 100644
--- a/common/rfb/ConnParams.cxx
+++ b/common/rfb/ConnParams.cxx
@@ -32,6 +32,7 @@
     supportsLocalCursor(false), supportsLocalXCursor(false),
     supportsDesktopResize(false), supportsExtendedDesktopSize(false),
     supportsDesktopRename(false), supportsLastRect(false),
+    supportsSetDesktopSize(false),
     customCompressLevel(false), compressLevel(6),
     noJpeg(false), qualityLevel(-1), 
     name_(0), nEncodings_(0), encodings_(0),
diff --git a/common/rfb/ConnParams.h b/common/rfb/ConnParams.h
index bdd9cf2..7779640 100644
--- a/common/rfb/ConnParams.h
+++ b/common/rfb/ConnParams.h
@@ -24,6 +24,7 @@
 
 #include <rdr/types.h>
 #include <rfb/PixelFormat.h>
+#include <rfb/ScreenSet.h>
 
 namespace rdr { class InStream; }
 
@@ -57,6 +58,7 @@
 
     int width;
     int height;
+    ScreenSet screenLayout;
 
     const PixelFormat& pf() { return pf_; }
     void setPF(const PixelFormat& pf);
@@ -77,6 +79,8 @@
     bool supportsDesktopRename;
     bool supportsLastRect;
 
+    bool supportsSetDesktopSize;
+
     bool customCompressLevel;
     int compressLevel;
     bool noJpeg;
diff --git a/common/rfb/Makefile.am b/common/rfb/Makefile.am
index 61f37bd..d3b7e76 100644
--- a/common/rfb/Makefile.am
+++ b/common/rfb/Makefile.am
@@ -12,8 +12,8 @@
 	Logger_stdio.h LogWriter.h msgTypes.h Password.h PixelBuffer.h \
 	PixelFormat.h PixelFormat.inl Pixel.h RawDecoder.h RawEncoder.h \
 	Rect.h Region.h rreDecode.h RREDecoder.h rreEncode.h RREEncoder.h \
-	ScaledPixelBuffer.h ScaleFilters.h SConnection.h screenTypes.h \
-	SDesktop.h secTypes.h ServerCore.h SMsgHandler.h \
+	ScaledPixelBuffer.h ScaleFilters.h SConnection.h ScreenSet.h \
+	screenTypes.h SDesktop.h secTypes.h ServerCore.h SMsgHandler.h \
 	SMsgReader.h SMsgReaderV3.h SMsgWriter.h SMsgWriterV3.h \
 	SSecurityFactoryStandard.h SSecurity.h SSecurityNone.h \
 	SSecurityVncAuth.h Threading.h tightDecode.h TightDecoder.h \
diff --git a/common/rfb/ScreenSet.h b/common/rfb/ScreenSet.h
new file mode 100644
index 0000000..0783871
--- /dev/null
+++ b/common/rfb/ScreenSet.h
@@ -0,0 +1,80 @@
+/* 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.
+ */
+
+// Management class for the RFB virtual screens
+
+#ifndef __RFB_SCREENSET_INCLUDED__
+#define __RFB_SCREENSET_INCLUDED__
+
+#include <rfb/Rect.h>
+#include <list>
+#include <set>
+
+namespace rfb {
+
+  // rfb::Screen
+  //
+  // Represents a single RFB virtual screen, which includes
+  // coordinates, an id and flags.
+
+  struct Screen {
+    Screen(void) : id(0), flags(0) {};
+    Screen(rdr::U32 id_, int x_, int y_, int w_, int h_, rdr::U32 flags_) :
+      id(id_), dimensions(x_, y_, x_+w_, y_+h_), flags(flags_) {};
+    rdr::U32 id;
+    Rect dimensions;
+    rdr::U32 flags;
+  };
+
+  // rfb::ScreenSet
+  //
+  // Represents a complete screen configuration, excluding framebuffer
+  // dimensions.
+
+  struct ScreenSet {
+    ScreenSet(void) {};
+    inline void add_screen(const Screen screen) { screens.push_back(screen); };
+    inline bool validate(int fb_width, int fb_height) const {
+      std::list<Screen>::const_iterator iter;
+      std::set<rdr::U32> seen_ids;
+      Rect fb_rect;
+
+      if (screens.empty())
+        return false;
+
+      fb_rect.setXYWH(0, 0, fb_width, fb_height);
+
+      for (iter = screens.begin();iter != screens.end();++iter) {
+        if (iter->dimensions.is_empty())
+          return false;
+        if (!iter->dimensions.enclosed_by(fb_rect))
+          return false;
+        if (seen_ids.find(iter->id) != seen_ids.end())
+          return false;
+        seen_ids.insert(iter->id);
+      }
+
+      return true;
+    };
+    std::list<Screen> screens;
+  };
+
+};
+
+#endif
+
diff --git a/common/rfb/rfb.dsp b/common/rfb/rfb.dsp
index fc1742e..321c4e6 100644
--- a/common/rfb/rfb.dsp
+++ b/common/rfb/rfb.dsp
@@ -576,6 +576,10 @@
 SOURCE=.\screenTypes.h

 # End Source File

 # Begin Source File

+
+SOURCE=.\ScreenSet.h

+# End Source File

+# Begin Source File

 

 SOURCE=.\SDesktop.h

 # End Source File

diff --git a/unix/vncviewer/CConn.cxx b/unix/vncviewer/CConn.cxx
index 79195a8..47ccbb2 100644
--- a/unix/vncviewer/CConn.cxx
+++ b/unix/vncviewer/CConn.cxx
@@ -273,8 +273,9 @@
 }
 
 // setExtendedDesktopSize() is a more advanced version of setDesktopSize()
-void CConn::setExtendedDesktopSize(int reason, int result, int w, int h) {
-  CConnection::setExtendedDesktopSize(reason, result, w,h);
+void CConn::setExtendedDesktopSize(int reason, int result, int w, int h,
+                                   const rfb::ScreenSet& layout) {
+  CConnection::setExtendedDesktopSize(reason, result, w, h, layout);
 
   if ((reason == reasonClient) && (result != resultSuccess))
     return;
diff --git a/unix/vncviewer/CConn.h b/unix/vncviewer/CConn.h
index 27ab8e3..10a12e4 100644
--- a/unix/vncviewer/CConn.h
+++ b/unix/vncviewer/CConn.h
@@ -75,7 +75,8 @@
   rfb::CSecurity* getCSecurity(int secType);
   void serverInit();
   void setDesktopSize(int w, int h);
-  void setExtendedDesktopSize(int reason, int result, int w, int h);
+  void setExtendedDesktopSize(int reason, int result, int w, int h,
+                              const rfb::ScreenSet& layout);
   void setName(const char* name);
   void setColourMapEntries(int firstColour, int nColours, rdr::U16* rgbs);
   void bell();