]> source.dussan.org Git - tigervnc.git/commitdiff
Added support for new `Geometry' option which allows serving an arbitrary
authorConstantin Kaplinsky <const@tightvnc.com>
Sat, 20 May 2006 12:58:38 +0000 (12:58 +0000)
committerConstantin Kaplinsky <const@tightvnc.com>
Sat, 20 May 2006 12:58:38 +0000 (12:58 +0000)
regtangular screen area instead of the whole screen.

git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@569 3789f03b-4d11-0410-bbf8-ca57d06f2519

x0vncserver/Geometry.cxx [new file with mode: 0644]
x0vncserver/Geometry.h [new file with mode: 0644]
x0vncserver/Makefile.in
x0vncserver/PollingManager.cxx
x0vncserver/PollingManager.h
x0vncserver/x0vncserver.cxx

diff --git a/x0vncserver/Geometry.cxx b/x0vncserver/Geometry.cxx
new file mode 100644 (file)
index 0000000..f232170
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (C) 2006 Constantin Kaplinsky.  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.
+ */
+
+//
+// Geometry.cxx
+//
+
+#include <stdio.h>
+
+#include <rfb/Rect.h>
+#include <rfb/LogWriter.h>
+#include <x0vncserver/Geometry.h>
+
+static LogWriter vlog("Geometry");
+
+StringParameter Geometry::m_geometryParam("Geometry",
+  "Screen area shown to VNC clients. "
+  "Format is <width>x<height>+<offset_x>+<offset_y>, "
+  "more information in man X, section GEOMETRY SPECIFICATIONS. "
+  "If the argument is empty, full screen is shown to VNC clients.",
+  "");
+
+Geometry::Geometry(int fullWidth, int fullHeight)
+  : m_width(fullWidth), m_height(fullHeight),
+    m_offsetLeft(0), m_offsetTop(0)
+{
+  const char *param = m_geometryParam.getData();
+  if (strlen(param) != 0) {
+    int w, h;
+    int x = 0, y = 0;
+    char sign_x[2] = "+";
+    char sign_y[2] = "+";
+    int n = sscanf(param, "%dx%d%1[+-]%d%1[+-]%d",
+                   &w, &h, sign_x, &x, sign_y, &y);
+    if ((n == 2 || n == 6) && w > 0 && h > 0 && x >= 0 && y >= 0) {
+      if (sign_x[0] == '-')
+        x = fullWidth - w - x;
+      if (sign_y[0] == '-')
+        y = fullHeight - h - y;
+      Rect fullRect(0, 0, fullWidth, fullHeight);
+      Rect partRect(x, y, x + w, y + h);
+      Rect r = partRect.intersect(fullRect);
+      if (r.area() > 0) {
+        m_width = r.width();
+        m_height = r.height();
+        m_offsetLeft = r.tl.x;
+        m_offsetTop = r.tl.y;
+      } else {
+        vlog.error("Requested area is out of the desktop boundaries");
+      }
+    } else {
+      vlog.error("Wrong argument format");
+    }
+  }
+  vlog.info("Desktop geometry is %dx%d+%d+%d",
+            m_width, m_height, m_offsetLeft, m_offsetTop);
+}
+
diff --git a/x0vncserver/Geometry.h b/x0vncserver/Geometry.h
new file mode 100644 (file)
index 0000000..95059e7
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (C) 2006 Constantin Kaplinsky.  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.
+ */
+
+//
+// Geometry.h
+//
+
+#ifndef __GEOMETRY_H__
+#define __GEOMETRY_H__
+
+#include <rfb/Configuration.h>
+
+using namespace rfb;
+
+class Geometry
+{
+public:
+  Geometry(int fullWidth, int fullHeight);
+
+  int width() const { return m_width; }
+  int height() const { return m_height; }
+  int offsetLeft() const { return m_offsetLeft; }
+  int offsetTop() const { return m_offsetTop; }
+
+protected:
+  static StringParameter m_geometryParam;
+
+  int m_width;
+  int m_height;
+  int m_offsetLeft;
+  int m_offsetTop;
+};
+
+#endif // __GEOMETRY_H__
+
index e69b89ad541ce818149a0d76f73ba66f88b7d6e9..cbb9fed69dee3ca932cb3260c9753e0a9c7d9b36 100644 (file)
@@ -1,5 +1,6 @@
 
 SRCS = Image.cxx TimeMillis.cxx PollingScheduler.cxx PollingManager.cxx \
+       Geometry.cxx \
        x0vncserver.cxx ../vncconfig_unix/QueryConnectDialog.cxx
 
 OBJS = $(SRCS:.cxx=.o)
index c0670107414340718e057e0f2bfc35add4627c86..3c6be4f8ac765e50a7d9268ce1dcf621e35e287f 100644 (file)
@@ -58,9 +58,11 @@ const int PollingManager::m_pollingOrder[32] = {
 //
 
 PollingManager::PollingManager(Display *dpy, Image *image,
-                               ImageFactory *factory)
-  : m_dpy(dpy), m_server(0), m_image(image), m_pointerPosKnown(false),
-    m_pollingStep(0)
+                               ImageFactory *factory,
+                               int offsetLeft, int offsetTop)
+  : m_dpy(dpy), m_server(0), m_image(image),
+    m_offsetLeft(offsetLeft), m_offsetTop(offsetTop),
+    m_pointerPosKnown(false), m_pollingStep(0)
 {
   // Save width and height of the screen (and the image).
   m_width = m_image->xim->width;
@@ -241,7 +243,7 @@ bool PollingManager::poll_DetectVideo()
     if (scanLine >= tile_h)
       break;
     int scan_y = y * 32 + scanLine;
-    m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
+    getRow(scan_y);
     char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
     char *ptr_new = m_rowImage->xim->data;
     for (int x = 0; x * 32 < m_width; x++) {
@@ -262,12 +264,7 @@ bool PollingManager::poll_DetectVideo()
 
       m_changedFlags[idx] |= wasChanged;
       if ( m_changedFlags[idx] && (!m_videoFlags[idx] || grandStep) ) {
-        if (tile_w == 32 && tile_h == 32) {
-          m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
-        } else {
-          m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
-                           tile_w, tile_h);
-        }
+        getTile32(x, y, tile_w, tile_h);
         m_image->updateRect(m_tileImage, x * 32, y * 32);
         rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
         m_server->add_changed(rect);
@@ -311,7 +308,7 @@ bool PollingManager::poll_SkipCycles()
     if (scanLine >= tile_h)
       scanLine %= tile_h;
     int scan_y = y * 32 + scanLine;
-    m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
+    getRow(scan_y);
     char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
     char *ptr_new = m_rowImage->xim->data;
     for (int x = 0; x * 32 < m_width; x++) {
@@ -323,12 +320,7 @@ bool PollingManager::poll_SkipCycles()
           true : (memcmp(ptr_old, ptr_new, nBytes) != 0);
         if (wasChanged) {
           if (grandStep || *pstatus == NOT_CHANGED) {
-            if (tile_w == 32 && tile_h == 32) {
-              m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
-            } else {
-              m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
-                               tile_w, tile_h);
-            }
+            getTile32(x, y, tile_w, tile_h);
             m_image->updateRect(m_tileImage, x * 32, y * 32);
             rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
             m_server->add_changed(rect);
@@ -367,19 +359,14 @@ bool PollingManager::poll_Traditional()
     if (scanLine >= tile_h)
       break;
     int scan_y = y * 32 + scanLine;
-    m_rowImage->get(DefaultRootWindow(m_dpy), 0, scan_y);
+    getRow(scan_y);
     char *ptr_old = m_image->xim->data + scan_y * bytesPerLine;
     char *ptr_new = m_rowImage->xim->data;
     for (int x = 0; x * 32 < m_width; x++) {
       int tile_w = (m_width - x * 32 >= 32) ? 32 : m_width - x * 32;
       int nBytes = tile_w * bytesPerPixel;
       if (memcmp(ptr_old, ptr_new, nBytes)) {
-        if (tile_w == 32 && tile_h == 32) {
-          m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32);
-        } else {
-          m_tileImage->get(DefaultRootWindow(m_dpy), x * 32, y * 32,
-                           tile_w, tile_h);
-        }
+        getTile32(x, y, tile_w, tile_h);
         m_image->updateRect(m_tileImage, x * 32, y * 32);
         rect.setXYWH(x * 32, y * 32, tile_w, tile_h);
         m_server->add_changed(rect);
@@ -402,7 +389,7 @@ bool PollingManager::poll_Dumb()
   if (!m_server)
     return false;
 
-  m_image->get(DefaultRootWindow(m_dpy));
+  getScreen();
   Rect rect(0, 0, m_width, m_height);
   m_server->add_changed(rect);
 
@@ -456,11 +443,7 @@ bool PollingManager::pollPointerArea()
   int w = r.width(), h = r.height();
 
   // Get new pixels.
-  if (w == 128 && h == 128) {
-    m_areaImage->get(DefaultRootWindow(m_dpy), x, y);
-  } else {
-    m_areaImage->get(DefaultRootWindow(m_dpy), x, y, w, h);
-  }
+  getArea128(x, y, w, h);
 
   // Now, try to minimize the rectangle by cutting out unchanged
   // borders (at top and bottom).
index 797f3f683664fe5ef62c488fcb6e1527b980d300..b8eef509ef520425e15bb1245f390f130e4d4aac 100644 (file)
@@ -38,7 +38,8 @@ class PollingManager {
 
 public:
 
-  PollingManager(Display *dpy, Image *image, ImageFactory *factory);
+  PollingManager(Display *dpy, Image *image, ImageFactory *factory,
+                 int offsetLeft = 0, int offsetTop = 0);
   virtual ~PollingManager();
 
   void setVNCServer(VNCServer *s);
@@ -71,6 +72,8 @@ protected:
   VNCServer *m_server;
 
   Image *m_image;
+  int m_offsetLeft;
+  int m_offsetTop;
   int m_width;
   int m_height;
   int m_widthTiles;
@@ -83,6 +86,38 @@ protected:
 
 private:
 
+  inline void getScreen() {
+    m_image->get(DefaultRootWindow(m_dpy), m_offsetLeft, m_offsetTop);
+  }
+
+  inline void getRow(int y) {
+    m_rowImage->get(DefaultRootWindow(m_dpy), m_offsetLeft, m_offsetTop + y);
+  }
+
+  inline void getTile32(int tx, int ty, int w, int h) {
+    if (w == 32 && h == 32) {
+      // This version of get() may be better optimized.
+      m_tileImage->get(DefaultRootWindow(m_dpy),
+                       m_offsetLeft + tx * 32, m_offsetTop + ty * 32);
+    } else {
+      // Generic version of get() for arbitrary width and height.
+      m_tileImage->get(DefaultRootWindow(m_dpy),
+                       m_offsetLeft + tx * 32, m_offsetTop + ty * 32, w, h);
+    }
+  }
+
+  inline void getArea128(int x, int y, int w, int h) {
+    if (w == 128 && h == 128) {
+      // This version of get() may be better optimized.
+      m_areaImage->get(DefaultRootWindow(m_dpy),
+                       m_offsetLeft + x, m_offsetTop + y);
+    } else {
+      // Generic version of get() for arbitrary width and height.
+      m_areaImage->get(DefaultRootWindow(m_dpy),
+                       m_offsetLeft + x, m_offsetTop + y, w, h);
+    }
+  }
+
   void adjustVideoArea();
 
   // Additional images used in polling algorithms.
index 4ee44e0440a4dac964d8932054366546b1834963..70a5361b7cc5f43d827bd441fee0acc61e25af1a 100644 (file)
@@ -44,6 +44,7 @@
 #include <X11/extensions/XTest.h>
 #endif
 
+#include <x0vncserver/Geometry.h>
 #include <x0vncserver/Image.h>
 #include <x0vncserver/PollingManager.h>
 #include <x0vncserver/PollingScheduler.h>
@@ -130,8 +131,8 @@ private:
 class XDesktop : public SDesktop, public ColourMap
 {
 public:
-  XDesktop(Display* dpy_)
-    : dpy(dpy_), pb(0), server(0), image(0), pollmgr(0),
+  XDesktop(Display* dpy_, Geometry *geometry_)
+    : dpy(dpy_), geometry(geometry_), pb(0), server(0), image(0), pollmgr(0),
       oldButtonMask(0), haveXtest(false), maxButtons(0), running(false)
   {
 #ifdef HAVE_XTEST
@@ -168,14 +169,15 @@ public:
     vlog.info("Enabling %d button%s of X pointer device",
               maxButtons, (maxButtons != 1) ? "s" : "");
 
-    int dpyWidth = DisplayWidth(dpy, DefaultScreen(dpy));
-    int dpyHeight = DisplayHeight(dpy, DefaultScreen(dpy));
-
     ImageFactory factory((bool)useShm, (bool)useOverlay);
-    image = factory.newImage(dpy, dpyWidth, dpyHeight);
-    image->get(DefaultRootWindow(dpy));
-
-    pollmgr = new PollingManager(dpy, image, &factory);
+    image = factory.newImage(dpy, geometry->width(), geometry->height());
+    image->get(DefaultRootWindow(dpy),
+               geometry->offsetLeft(), geometry->offsetTop());
+
+    // FIXME: Duplication in using offsets above and here:
+    pollmgr = new PollingManager(dpy, image, &factory,
+                                 geometry->offsetLeft(),
+                                 geometry->offsetTop());
     pollmgr->setVNCServer(vs);
 
     pf.bpp = image->xim->bits_per_pixel;
@@ -189,7 +191,7 @@ public:
     pf.greenMax   = image->xim->green_mask >> pf.greenShift;
     pf.blueMax    = image->xim->blue_mask  >> pf.blueShift;
 
-    pb = new FullFramePixelBuffer(pf, dpyWidth, dpyHeight,
+    pb = new FullFramePixelBuffer(pf, geometry->width(), geometry->height(),
                                   (rdr::U8*)image->xim->data, this);
     server = vs;
     server->setPixelBuffer(pb);
@@ -222,7 +224,10 @@ public:
     pollmgr->setPointerPos(pos);
 #ifdef HAVE_XTEST
     if (!haveXtest) return;
-    XTestFakeMotionEvent(dpy, DefaultScreen(dpy), pos.x, pos.y, CurrentTime);
+    XTestFakeMotionEvent(dpy, DefaultScreen(dpy),
+                         geometry->offsetLeft() + pos.x,
+                         geometry->offsetTop() + pos.y,
+                         CurrentTime);
     if (buttonMask != oldButtonMask) {
       for (int i = 0; i < maxButtons; i++) {
        if ((buttonMask ^ oldButtonMask) & (1<<i)) {
@@ -270,6 +275,7 @@ public:
 
 protected:
   Display* dpy;
+  Geometry* geometry;
   PixelFormat pf;
   PixelBuffer* pb;
   VNCServer* server;
@@ -435,7 +441,9 @@ int main(int argc, char** argv)
 
   try {
     TXWindow::init(dpy,"x0vncserver");
-    XDesktop desktop(dpy);
+    Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)),
+                 DisplayHeight(dpy, DefaultScreen(dpy)));
+    XDesktop desktop(dpy, &geo);
     VNCServerST server("x0vncserver", &desktop);
     QueryConnHandler qcHandler(dpy, &server);
     server.setQueryConnectionHandler(&qcHandler);