--- /dev/null
+/* 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);
+}
+
--- /dev/null
+/* 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__
+
SRCS = Image.cxx TimeMillis.cxx PollingScheduler.cxx PollingManager.cxx \
+ Geometry.cxx \
x0vncserver.cxx ../vncconfig_unix/QueryConnectDialog.cxx
OBJS = $(SRCS:.cxx=.o)
//
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;
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++) {
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);
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++) {
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);
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);
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);
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).
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);
VNCServer *m_server;
Image *m_image;
+ int m_offsetLeft;
+ int m_offsetTop;
int m_width;
int m_height;
int m_widthTiles;
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.
#include <X11/extensions/XTest.h>
#endif
+#include <x0vncserver/Geometry.h>
#include <x0vncserver/Image.h>
#include <x0vncserver/PollingManager.h>
#include <x0vncserver/PollingScheduler.h>
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
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;
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);
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)) {
protected:
Display* dpy;
+ Geometry* geometry;
PixelFormat pf;
PixelBuffer* pb;
VNCServer* server;
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);