Browse Source

Merge branch 'x0-xdesktop-initial-cursor' of https://github.com/x11clone/x11clone

tags/v1.8.90
Pierre Ossman 6 years ago
parent
commit
bf003e5b1e

+ 1
- 0
README.txt View File

@@ -34,6 +34,7 @@ Incomplete and generally out of date copyright list:
Copyright (C) 2009-2011 D. R. Commander
Copyright (C) 2009-2011 Pierre Ossman for Cendio AB
Copyright (C) 2004, 2009-2011 Red Hat, Inc.
Copyright (C) 2017 Peter Astrand for Cendio AB
Copyright (C) 2009-2017 TigerVNC Team
All Rights Reserved.


+ 1
- 0
common/network/Socket.h View File

@@ -50,6 +50,7 @@ namespace network {
// if shutdown() is overridden then the override MUST call on to here
virtual void shutdown() {isShutdown_ = true;}
bool isShutdown() const {return isShutdown_;}
virtual bool cork(bool enable) = 0;

// information about this end of the socket
virtual int getMyPort() = 0;

+ 2
- 2
common/network/TcpSocket.cxx View File

@@ -349,12 +349,12 @@ bool TcpSocket::enableNagles(int sock, bool enable) {
return true;
}

bool TcpSocket::cork(int sock, bool enable) {
bool TcpSocket::cork(bool enable) {
#ifndef TCP_CORK
return false;
#else
int one = enable ? 1 : 0;
if (setsockopt(sock, IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
if (setsockopt(getFd(), IPPROTO_TCP, TCP_CORK, (char *)&one, sizeof(one)) < 0)
return false;
return true;
#endif

+ 1
- 1
common/network/TcpSocket.h View File

@@ -62,9 +62,9 @@ namespace network {
virtual bool sameMachine();

virtual void shutdown();
virtual bool cork(bool enable);

static bool enableNagles(int sock, bool enable);
static bool cork(int sock, bool enable);
static bool isListening(int sock);
static int getSockPort(int sock);
private:

+ 10
- 1
common/rdr/FdOutStream.cxx View File

@@ -1,5 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman for Cendio AB
* Copyright 2017 Peter Astrand <astrand@cendio.se> 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
@@ -34,6 +35,7 @@
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/socket.h>
#endif

/* Old systems have select() in sys/time.h */
@@ -193,7 +195,14 @@ int FdOutStream::writeWithTimeout(const void* data, int length, int timeoutms)
return 0;

do {
n = ::write(fd, data, length);
// select only guarantees that you can write SO_SNDLOWAT without
// blocking, which is normally 1. Use MSG_DONTWAIT to avoid
// blocking, when possible.
#ifndef MSG_DONTWAIT
n = ::send(fd, (const char*)data, length, 0);
#else
n = ::send(fd, (const char*)data, length, MSG_DONTWAIT);
#endif
} while (n < 0 && (errno == EINTR));

if (n < 0)

+ 18
- 0
common/rfb/Configuration.cxx View File

@@ -1,5 +1,6 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2004-2005 Cendio AB.
* Copyright 2017 Peter Astrand <astrand@cendio.se> 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
@@ -166,6 +167,23 @@ void Configuration::list(int width, int nameWidth) {
}


bool Configuration::remove(const char* param) {
VoidParameter *current = head;
VoidParameter **prevnext = &head;

while (current) {
if (strcasecmp(current->getName(), param) == 0) {
*prevnext = current->_next;
return true;
}
prevnext = &current->_next;
current = current->_next;
}

return false;
}


// -=- VoidParameter

VoidParameter::VoidParameter(const char* name_, const char* desc_,

+ 6
- 0
common/rfb/Configuration.h View File

@@ -80,6 +80,9 @@ namespace rfb {
// - List the parameters of this Configuration group
void list(int width=79, int nameWidth=10);

// - Remove a parameter from this Configuration group
bool remove(const char* param);

// - readFromFile
// Read configuration parameters from the specified file.
void readFromFile(const char* filename);
@@ -116,6 +119,9 @@ namespace rfb {
static void listParams(int width=79, int nameWidth=10) {
global()->list(width, nameWidth);
}
static bool removeParam(const char* param) {
return global()->remove(param);
}

private:
friend class VoidParameter;

+ 0
- 5
common/rfb/Timer.cxx View File

@@ -26,11 +26,6 @@
#include <rfb/util.h>
#include <rfb/LogWriter.h>

// XXX Lynx/OS 2.3: proto for gettimeofday()
#ifdef Lynx
#include <sys/proto.h>
#endif

using namespace rfb;

#ifndef __NO_DEFINE_VLOG__

+ 4
- 4
common/rfb/VNCSConnectionST.cxx View File

@@ -168,7 +168,7 @@ void VNCSConnectionST::processMessages()

// Get the underlying TCP layer to build large packets if we send
// multiple small responses.
network::TcpSocket::cork(sock->getFd(), true);
sock->cork(true);

while (getInStream()->checkNoWait(1)) {
if (pendingSyncFence) {
@@ -185,7 +185,7 @@ void VNCSConnectionST::processMessages()
}

// Flush out everything in case we go idle after this.
network::TcpSocket::cork(sock->getFd(), false);
sock->cork(false);

inProcessMessages = false;

@@ -1094,7 +1094,7 @@ void VNCSConnectionST::writeFramebufferUpdate()
// mode, we will also have small fence messages around the update. We
// need to aggregate these in order to not clog up TCP's congestion
// window.
network::TcpSocket::cork(sock->getFd(), true);
sock->cork(true);

// First take care of any updates that cannot contain framebuffer data
// changes.
@@ -1103,7 +1103,7 @@ void VNCSConnectionST::writeFramebufferUpdate()
// Then real data (if possible)
writeDataUpdate();

network::TcpSocket::cork(sock->getFd(), false);
sock->cork(false);
}

void VNCSConnectionST::writeNoDataUpdate()

+ 0
- 5
unix/tx/TXDialog.h View File

@@ -31,11 +31,6 @@
#include "TXWindow.h"
#include <errno.h>

// XXX Lynx/OS 2.3: protos for bzero(), select()
#ifdef Lynx
#include <sys/proto.h>
#endif

class TXDialog : public TXWindow, public TXDeleteWindowCallback {
public:
TXDialog(Display* dpy, int width, int height, const char* name,

+ 1
- 0
unix/x0vncserver/CMakeLists.txt View File

@@ -14,6 +14,7 @@ add_executable(x0vncserver
qnum_to_xorgkbd.c
x0vncserver.cxx
XPixelBuffer.cxx
XDesktop.cxx
../vncconfig/QueryConnectDialog.cxx
)


+ 2
- 0
unix/x0vncserver/Geometry.cxx View File

@@ -23,6 +23,8 @@
#include <rfb/LogWriter.h>
#include <x0vncserver/Geometry.h>

using namespace rfb;

static LogWriter vlog("Geometry");

StringParameter Geometry::m_geometryParam("Geometry",

+ 4
- 6
unix/x0vncserver/Geometry.h View File

@@ -26,8 +26,6 @@
#include <rfb/Rect.h>
#include <rfb/Configuration.h>

using namespace rfb;

class Geometry
{
public:
@@ -43,18 +41,18 @@ public:
int offsetTop() const { return m_rect.tl.y; }

// Return the same information as a Rect structure.
const Rect& getRect() const { return m_rect; }
const rfb::Rect& getRect() const { return m_rect; }

protected:
// Parse a string, extract size and coordinates,
// and return that rectangle clipped to m_rect.
Rect parseString(const char *arg) const;
rfb::Rect parseString(const char *arg) const;

static StringParameter m_geometryParam;
static rfb::StringParameter m_geometryParam;

int m_fullWidth;
int m_fullHeight;
Rect m_rect;
rfb::Rect m_rect;
};

#endif // __GEOMETRY_H__

+ 2
- 200
unix/x0vncserver/Image.cxx View File

@@ -24,10 +24,8 @@
#include <stdlib.h>
#include <sys/types.h>

#ifdef HAVE_MITSHM
#include <sys/ipc.h>
#include <sys/shm.h>
#endif

#include <rfb/LogWriter.h>
#include <x0vncserver/Image.h>
@@ -196,8 +194,6 @@ void Image::updateRect(Image *src, int dst_x, int dst_y,
updateRect(src->xim, dst_x, dst_y, src_x, src_y, w, h);
}

#ifdef HAVE_MITSHM

//
// ShmImage class implementation.
//
@@ -323,182 +319,14 @@ void ShmImage::get(Window wnd, int x, int y, int w, int h,
XGetSubImage(dpy, wnd, x, y, w, h, AllPlanes, ZPixmap, xim, dst_x, dst_y);
}

#ifdef HAVE_READDISPLAY

//
// IrixOverlayShmImage class implementation.
//

IrixOverlayShmImage::IrixOverlayShmImage(Display *d)
: ShmImage(d), readDisplayBuf(NULL)
{
}

IrixOverlayShmImage::IrixOverlayShmImage(Display *d, int width, int height)
: ShmImage(d), readDisplayBuf(NULL)
{
Init(width, height);
}

void IrixOverlayShmImage::Init(int width, int height)
{
// First determine the pixel format used by XReadDisplay.
XVisualInfo vinfo;
if (!getOverlayVisualInfo(&vinfo))
return;

// Create an SHM image of the same format.
ShmImage::Init(width, height, &vinfo);
if (xim == NULL)
return;

// FIXME: Check if the extension is available at run time.
readDisplayBuf = XShmCreateReadDisplayBuf(dpy, NULL, shminfo, width, height);
}

bool IrixOverlayShmImage::getOverlayVisualInfo(XVisualInfo *vinfo_ret)
{
// First, get an image in the format returned by XReadDisplay.
unsigned long hints = 0, hints_ret;
XImage *testImage = XReadDisplay(dpy, DefaultRootWindow(dpy),
0, 0, 8, 8, hints, &hints_ret);
if (testImage == NULL)
return false;

// Fill in a template for matching visuals.
XVisualInfo tmpl;
tmpl.c_class = TrueColor;
tmpl.depth = 24;
tmpl.red_mask = testImage->red_mask;
tmpl.green_mask = testImage->green_mask;
tmpl.blue_mask = testImage->blue_mask;

// List fields in template that make sense.
long mask = (VisualClassMask |
VisualRedMaskMask |
VisualGreenMaskMask |
VisualBlueMaskMask);

// We don't need that image any more.
XDestroyImage(testImage);

// Now, get a list of matching visuals available.
int nVisuals;
XVisualInfo *vinfo = XGetVisualInfo(dpy, mask, &tmpl, &nVisuals);
if (vinfo == NULL || nVisuals <= 0) {
if (vinfo != NULL) {
XFree(vinfo);
}
return false;
}

// Use first visual from the list.
*vinfo_ret = vinfo[0];

XFree(vinfo);

return true;
}

IrixOverlayShmImage::~IrixOverlayShmImage()
{
if (readDisplayBuf != NULL)
XShmDestroyReadDisplayBuf(readDisplayBuf);
}

void IrixOverlayShmImage::get(Window wnd, int x, int y)
{
get(wnd, x, y, xim->width, xim->height);
}

void IrixOverlayShmImage::get(Window wnd, int x, int y, int w, int h,
int dst_x, int dst_y)
{
XRectangle rect;
unsigned long hints = XRD_TRANSPARENT | XRD_READ_POINTER;

rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;

XShmReadDisplayRects(dpy, wnd,
&rect, 1, readDisplayBuf,
dst_x - x, dst_y - y,
hints, &hints);
}

#endif // HAVE_READDISPLAY
#endif // HAVE_MITSHM

#ifdef HAVE_SUN_OVL

//
// SolarisOverlayImage class implementation
//

SolarisOverlayImage::SolarisOverlayImage(Display *d)
: Image(d)
{
}

SolarisOverlayImage::SolarisOverlayImage(Display *d, int width, int height)
: Image(d)
{
Init(width, height);
}

void SolarisOverlayImage::Init(int width, int height)
{
// FIXME: Check if the extension is available at run time.
// FIXME: Maybe just read a small (e.g. 8x8) screen area then
// reallocate xim->data[] and correct width and height?
xim = XReadScreen(dpy, DefaultRootWindow(dpy), 0, 0, width, height, True);
if (xim == NULL) {
vlog.error("XReadScreen() failed");
return;
}
}

SolarisOverlayImage::~SolarisOverlayImage()
{
}

void SolarisOverlayImage::get(Window wnd, int x, int y)
{
get(wnd, x, y, xim->width, xim->height);
}

void SolarisOverlayImage::get(Window wnd, int x, int y, int w, int h,
int dst_x, int dst_y)
{
XImage *tmp_xim = XReadScreen(dpy, wnd, x, y, w, h, True);
if (tmp_xim == NULL)
return;

updateRect(tmp_xim, dst_x, dst_y);

XDestroyImage(tmp_xim);
}

#endif // HAVE_SUN_OVL

//
// ImageFactory class implementation
//
// FIXME: Make ImageFactory always create images of the same class?
//

// Prepare useful shortcuts for compile-time options.
#if defined(HAVE_READDISPLAY) && defined(HAVE_MITSHM)
#define HAVE_SHM_READDISPLAY
#endif
#if defined(HAVE_SHM_READDISPLAY) || defined(HAVE_SUN_OVL)
#define HAVE_OVERLAY_EXT
#endif

ImageFactory::ImageFactory(bool allowShm, bool allowOverlay)
: mayUseShm(allowShm), mayUseOverlay(allowOverlay)
ImageFactory::ImageFactory(bool allowShm)
: mayUseShm(allowShm)
{
}

@@ -510,33 +338,8 @@ Image *ImageFactory::newImage(Display *d, int width, int height)
{
Image *image = NULL;

// First, try to create an image with overlay support.

#ifdef HAVE_OVERLAY_EXT
if (mayUseOverlay) {
#if defined(HAVE_SHM_READDISPLAY)
if (mayUseShm) {
image = new IrixOverlayShmImage(d, width, height);
if (image->xim != NULL) {
return image;
}
}
#elif defined(HAVE_SUN_OVL)
image = new SolarisOverlayImage(d, width, height);
if (image->xim != NULL) {
return image;
}
#endif
if (image != NULL) {
delete image;
vlog.error("Failed to create overlay image, trying other options");
}
}
#endif // HAVE_OVERLAY_EXT

// Now, try to use shared memory image.

#ifdef HAVE_MITSHM
if (mayUseShm) {
image = new ShmImage(d, width, height);
if (image->xim != NULL) {
@@ -546,7 +349,6 @@ Image *ImageFactory::newImage(Display *d, int width, int height)
delete image;
vlog.error("Failed to create SHM image, falling back to Xlib image");
}
#endif // HAVE_MITSHM

// Fall back to Xlib image.


+ 1
- 88
unix/x0vncserver/Image.h View File

@@ -92,8 +92,6 @@ protected:
// ShmImage uses MIT-SHM extension of an X server to get image data.
//

#ifdef HAVE_MITSHM

#include <X11/extensions/XShm.h>

class ShmImage : public Image {
@@ -123,89 +121,6 @@ protected:

};

//
// IrixOverlayShmImage uses ReadDisplay extension of an X server to
// get truecolor image data, regardless of the default X visual type.
// This method is available on Irix only.
//

#ifdef HAVE_READDISPLAY

#include <X11/extensions/readdisplay.h>

class IrixOverlayShmImage : public ShmImage {

public:

IrixOverlayShmImage(Display *d);
IrixOverlayShmImage(Display *d, int width, int height);
virtual ~IrixOverlayShmImage();

virtual const char *className() const {
return "IrixOverlayShmImage";
}
virtual const char *classDesc() const {
return "IRIX-specific SHM-aware overlay image";
}

virtual void get(Window wnd, int x = 0, int y = 0);
virtual void get(Window wnd, int x, int y, int w, int h,
int dst_x = 0, int dst_y = 0);

protected:

void Init(int width, int height);

// This method searches available X visuals for one that matches
// actual pixel format returned by XReadDisplay(). Returns true on
// success, false if there is no matching visual. On success, visual
// information is placed into the structure pointed by vinfo_ret.
bool getOverlayVisualInfo(XVisualInfo *vinfo_ret);

ShmReadDisplayBuf *readDisplayBuf;

};

#endif // HAVE_READDISPLAY
#endif // HAVE_MITSHM

//
// SolarisOverlayImage uses SUN_OVL extension of an X server to get
// truecolor image data, regardless of the default X visual type. This
// method is available on Solaris only.
//

#ifdef HAVE_SUN_OVL

#include <X11/extensions/transovl.h>

class SolarisOverlayImage : public Image {

public:

SolarisOverlayImage(Display *d);
SolarisOverlayImage(Display *d, int width, int height);
virtual ~SolarisOverlayImage();

virtual const char *className() const {
return "SolarisOverlayImage";
}
virtual const char *classDesc() const {
return "Solaris-specific non-SHM overlay image";
}

virtual void get(Window wnd, int x = 0, int y = 0);
virtual void get(Window wnd, int x, int y, int w, int h,
int dst_x = 0, int dst_y = 0);

protected:

void Init(int width, int height);

};

#endif // HAVE_SUN_OVL

//
// ImageFactory class is used to produce instances of Image-derived
// objects that are most appropriate for current X server and user
@@ -216,18 +131,16 @@ class ImageFactory {

public:

ImageFactory(bool allowShm, bool allowOverlay);
ImageFactory(bool allowShm);
virtual ~ImageFactory();

bool isShmAllowed() { return mayUseShm; }
bool isOverlayAllowed() { return mayUseOverlay; }

virtual Image *newImage(Display *d, int width, int height);

protected:

bool mayUseShm;
bool mayUseOverlay;

};


+ 2
- 0
unix/x0vncserver/PollingManager.cxx View File

@@ -31,6 +31,8 @@

#include <x0vncserver/PollingManager.h>

using namespace rfb;

static LogWriter vlog("PollingMgr");

const int PollingManager::m_pollingOrder[32] = {

+ 3
- 5
unix/x0vncserver/PollingManager.h View File

@@ -32,8 +32,6 @@
#include <x0vncserver/TimeMillis.h>
#endif

using namespace rfb;

class PollingManager {

public:
@@ -42,12 +40,12 @@ public:
int offsetLeft = 0, int offsetTop = 0);
virtual ~PollingManager();

void poll(VNCServer *server);
void poll(rfb::VNCServer *server);

protected:

// Screen polling. Returns true if some changes were detected.
bool pollScreen(VNCServer *server);
bool pollScreen(rfb::VNCServer *server);

Display *m_dpy;

@@ -85,7 +83,7 @@ private:

int checkRow(int x, int y, int w);
int checkColumn(int x, int y, int h, bool *pChangeFlags);
int sendChanges(VNCServer *server) const;
int sendChanges(rfb::VNCServer *server) const;

// Check neighboring tiles and update m_changeFlags[].
void checkNeighbors();

+ 0
- 5
unix/x0vncserver/TimeMillis.cxx View File

@@ -22,11 +22,6 @@

#include <x0vncserver/TimeMillis.h>

// XXX Lynx/OS 2.3: get proto for gettimeofday()
#ifdef Lynx
#include <sys/proto.h>
#endif

TimeMillis::TimeMillis()
{
update();

+ 427
- 0
unix/x0vncserver/XDesktop.cxx View File

@@ -0,0 +1,427 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2004-2008 Constantin Kaplinsky. All Rights Reserved.
* Copyright 2017 Peter Astrand <astrand@cendio.se> 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.
*/

#include <x0vncserver/XDesktop.h>

#include <X11/XKBlib.h>
#ifdef HAVE_XTEST
#include <X11/extensions/XTest.h>
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif

#include <x0vncserver/Geometry.h>
#include <x0vncserver/XPixelBuffer.h>

using namespace rfb;

extern const unsigned short code_map_qnum_to_xorgevdev[];
extern const unsigned int code_map_qnum_to_xorgevdev_len;

extern const unsigned short code_map_qnum_to_xorgkbd[];
extern const unsigned int code_map_qnum_to_xorgkbd_len;

extern rfb::BoolParameter useShm;
extern rfb::BoolParameter rawKeyboard;

static rfb::LogWriter vlog("XDesktop");

// order is important as it must match RFB extension
static const char * ledNames[XDESKTOP_N_LEDS] = {
"Scroll Lock", "Num Lock", "Caps Lock"
};

XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
: dpy(dpy_), geometry(geometry_), pb(0), server(0),
oldButtonMask(0), haveXtest(false), haveDamage(false),
maxButtons(0), running(false), ledMasks(), ledState(0),
codeMap(0), codeMapLen(0)
{
int major, minor;

int xkbOpcode, xkbErrorBase;

major = XkbMajorVersion;
minor = XkbMinorVersion;
if (!XkbQueryExtension(dpy, &xkbOpcode, &xkbEventBase,
&xkbErrorBase, &major, &minor)) {
vlog.error("XKEYBOARD extension not present");
throw Exception();
}

XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
XkbIndicatorStateNotifyMask);

// figure out bit masks for the indicators we are interested in
for (int i = 0; i < XDESKTOP_N_LEDS; i++) {
Atom a;
int shift;
Bool on;

a = XInternAtom(dpy, ledNames[i], True);
if (!a || !XkbGetNamedIndicator(dpy, a, &shift, &on, NULL, NULL))
continue;

ledMasks[i] = 1u << shift;
vlog.debug("Mask for '%s' is 0x%x", ledNames[i], ledMasks[i]);
if (on)
ledState |= 1u << i;
}

// X11 unfortunately uses keyboard driver specific keycodes and provides no
// direct way to query this, so guess based on the keyboard mapping
XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
if (desc && desc->names) {
char *keycodes = XGetAtomName(dpy, desc->names->keycodes);

if (keycodes) {
if (strncmp("evdev", keycodes, strlen("evdev")) == 0) {
codeMap = code_map_qnum_to_xorgevdev;
codeMapLen = code_map_qnum_to_xorgevdev_len;
vlog.info("Using evdev codemap\n");
} else if (strncmp("xfree86", keycodes, strlen("xfree86")) == 0) {
codeMap = code_map_qnum_to_xorgkbd;
codeMapLen = code_map_qnum_to_xorgkbd_len;
vlog.info("Using xorgkbd codemap\n");
} else {
vlog.info("Unknown keycode '%s', no codemap\n", keycodes);
}
XFree(keycodes);
} else {
vlog.debug("Unable to get keycode map\n");
}

XkbFreeKeyboard(desc, XkbAllComponentsMask, True);
}

#ifdef HAVE_XTEST
int xtestEventBase;
int xtestErrorBase;

if (XTestQueryExtension(dpy, &xtestEventBase,
&xtestErrorBase, &major, &minor)) {
XTestGrabControl(dpy, True);
vlog.info("XTest extension present - version %d.%d",major,minor);
haveXtest = true;
} else {
#endif
vlog.info("XTest extension not present");
vlog.info("Unable to inject events or display while server is grabbed");
#ifdef HAVE_XTEST
}
#endif

#ifdef HAVE_XDAMAGE
int xdamageErrorBase;

if (XDamageQueryExtension(dpy, &xdamageEventBase, &xdamageErrorBase)) {
haveDamage = true;
} else {
#endif
vlog.info("DAMAGE extension not present");
vlog.info("Will have to poll screen for changes");
#ifdef HAVE_XDAMAGE
}
#endif

#ifdef HAVE_XFIXES
int xfixesErrorBase;

if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) {
XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy),
XFixesDisplayCursorNotifyMask);
} else {
#endif
vlog.info("XFIXES extension not present");
vlog.info("Will not be able to display cursors");
#ifdef HAVE_XFIXES
}
#endif

TXWindow::setGlobalEventHandler(this);
}

XDesktop::~XDesktop() {
stop();
}


void XDesktop::poll() {
if (pb and not haveDamage)
pb->poll(server);
if (running) {
Window root, child;
int x, y, wx, wy;
unsigned int mask;
XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
&x, &y, &wx, &wy, &mask);
server->setCursorPos(rfb::Point(x, y));
}
}


void XDesktop::start(VNCServer* vs) {

// Determine actual number of buttons of the X pointer device.
unsigned char btnMap[8];
int numButtons = XGetPointerMapping(dpy, btnMap, 8);
maxButtons = (numButtons > 8) ? 8 : numButtons;
vlog.info("Enabling %d button%s of X pointer device",
maxButtons, (maxButtons != 1) ? "s" : "");

// Create an ImageFactory instance for producing Image objects.
ImageFactory factory((bool)useShm);

// Create pixel buffer and provide it to the server object.
pb = new XPixelBuffer(dpy, factory, geometry->getRect());
vlog.info("Allocated %s", pb->getImage()->classDesc());

server = (VNCServerST *)vs;
server->setPixelBuffer(pb);

#ifdef HAVE_XDAMAGE
if (haveDamage) {
damage = XDamageCreate(dpy, DefaultRootWindow(dpy),
XDamageReportRawRectangles);
}
#endif

#ifdef HAVE_XFIXES
setCursor();
#endif

server->setLEDState(ledState);

running = true;
}

void XDesktop::stop() {
running = false;

#ifdef HAVE_XDAMAGE
if (haveDamage)
XDamageDestroy(dpy, damage);
#endif

delete pb;
pb = 0;
}

bool XDesktop::isRunning() {
return running;
}

void XDesktop::pointerEvent(const Point& pos, int buttonMask) {
#ifdef HAVE_XTEST
if (!haveXtest) return;
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)) {
if (buttonMask & (1<<i)) {
XTestFakeButtonEvent(dpy, i+1, True, CurrentTime);
} else {
XTestFakeButtonEvent(dpy, i+1, False, CurrentTime);
}
}
}
}
oldButtonMask = buttonMask;
#endif
}

#ifdef HAVE_XTEST
KeyCode XDesktop::XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
XkbDescPtr xkb;
XkbStateRec state;
unsigned keycode;

xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
if (!xkb)
return 0;

XkbGetState(dpy, XkbUseCoreKbd, &state);

for (keycode = xkb->min_key_code;
keycode <= xkb->max_key_code;
keycode++) {
KeySym cursym;
unsigned int mods, out_mods;
// XkbStateFieldFromRec() doesn't work properly because
// state.lookup_mods isn't properly updated, so we do this manually
mods = XkbBuildCoreState(XkbStateMods(&state), state.group);
XkbTranslateKeyCode(xkb, keycode, mods, &out_mods, &cursym);
if (cursym == keysym)
break;
}

if (keycode > xkb->max_key_code)
keycode = 0;

XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);

return keycode;
}
#endif

void XDesktop::keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
#ifdef HAVE_XTEST
int keycode = 0;

if (!haveXtest)
return;

// Use scan code if provided and mapping exists
if (codeMap && rawKeyboard && xtcode < codeMapLen)
keycode = codeMap[xtcode];

if (!keycode) {
if (pressedKeys.find(keysym) != pressedKeys.end())
keycode = pressedKeys[keysym];
else {
// XKeysymToKeycode() doesn't respect state, so we have to use
// something slightly more complex
keycode = XkbKeysymToKeycode(dpy, keysym);
}
}

if (!keycode)
return;

if (down)
pressedKeys[keysym] = keycode;
else
pressedKeys.erase(keysym);

XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
#endif
}

void XDesktop::clientCutText(const char* str, int len) {
}


bool XDesktop::handleGlobalEvent(XEvent* ev) {
if (ev->type == xkbEventBase + XkbEventCode) {
XkbEvent *kb = (XkbEvent *)ev;

if (kb->any.xkb_type != XkbIndicatorStateNotify)
return false;

vlog.debug("Got indicator update, mask is now 0x%x", kb->indicators.state);

ledState = 0;
for (int i = 0; i < XDESKTOP_N_LEDS; i++) {
if (kb->indicators.state & ledMasks[i])
ledState |= 1u << i;
}

if (running)
server->setLEDState(ledState);

return true;
#ifdef HAVE_XDAMAGE
} else if (ev->type == xdamageEventBase) {
XDamageNotifyEvent* dev;
Rect rect;

if (!running)
return true;

dev = (XDamageNotifyEvent*)ev;
rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
server->add_changed(rect);

return true;
#endif
#ifdef HAVE_XFIXES
} else if (ev->type == xfixesEventBase + XFixesCursorNotify) {
XFixesCursorNotifyEvent* cev;

if (!running)
return true;

cev = (XFixesCursorNotifyEvent*)ev;

if (cev->subtype != XFixesDisplayCursorNotify)
return false;

return setCursor();
#endif
}

return false;
}

bool XDesktop::setCursor()
{
XFixesCursorImage *cim;

cim = XFixesGetCursorImage(dpy);
if (cim == NULL)
return false;

// Copied from XserverDesktop::setCursor() in
// unix/xserver/hw/vnc/XserverDesktop.cc and adapted to
// handle long -> U32 conversion for 64-bit Xlib
rdr::U8* cursorData;
rdr::U8 *out;
const unsigned long *pixels;

cursorData = new rdr::U8[cim->width * cim->height * 4];

// Un-premultiply alpha
pixels = cim->pixels;
out = cursorData;
for (int y = 0; y < cim->height; y++) {
for (int x = 0; x < cim->width; x++) {
rdr::U8 alpha;
rdr::U32 pixel = *pixels++;
rdr::U8 *in = (rdr::U8 *) &pixel;

alpha = in[3];
if (alpha == 0)
alpha = 1; // Avoid division by zero

*out++ = (unsigned)*in++ * 255/alpha;
*out++ = (unsigned)*in++ * 255/alpha;
*out++ = (unsigned)*in++ * 255/alpha;
*out++ = *in++;
}
}

try {
server->setCursor(cim->width, cim->height, Point(cim->xhot, cim->yhot),
cursorData);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::setCursor: %s",e.str());
}

delete [] cursorData;
XFree(cim);
return true;
}

+ 81
- 0
unix/x0vncserver/XDesktop.h View File

@@ -0,0 +1,81 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2004-2008 Constantin Kaplinsky. All Rights Reserved.
* Copyright 2017 Peter Astrand <astrand@cendio.se> 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 __XDESKTOP_H__
#define __XDESKTOP_H__

#include <rfb/VNCServerST.h>
#include <tx/TXWindow.h>

#include <X11/XKBlib.h>
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif

class Geometry;
class XPixelBuffer;

// number of XKb indicator leds to handle
#define XDESKTOP_N_LEDS 3

class XDesktop : public rfb::SDesktop, public TXGlobalEventHandler
{
public:
XDesktop(Display* dpy_, Geometry *geometry);
virtual ~XDesktop();
void poll();
// -=- SDesktop interface
virtual void start(rfb::VNCServer* vs);
virtual void stop();
bool isRunning();
virtual void pointerEvent(const rfb::Point& pos, int buttonMask);
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym);
virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down);
virtual void clientCutText(const char* str, int len);
// -=- TXGlobalEventHandler interface
virtual bool handleGlobalEvent(XEvent* ev);

protected:
Display* dpy;
Geometry* geometry;
XPixelBuffer* pb;
rfb::VNCServerST* server;
int oldButtonMask;
bool haveXtest;
bool haveDamage;
int maxButtons;
std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE
Damage damage;
int xdamageEventBase;
#endif
int xkbEventBase;
#ifdef HAVE_XFIXES
int xfixesEventBase;
#endif
int ledMasks[XDESKTOP_N_LEDS];
unsigned ledState;
const unsigned short *codeMap;
unsigned codeMapLen;
bool setCursor();
};

#endif // __XDESKTOP_H__

+ 4
- 6
unix/x0vncserver/XPixelBuffer.h View File

@@ -28,23 +28,21 @@
#include <x0vncserver/Image.h>
#include <x0vncserver/PollingManager.h>

using namespace rfb;

//
// XPixelBuffer is an Image-based implementation of FullFramePixelBuffer.
//

class XPixelBuffer : public FullFramePixelBuffer
class XPixelBuffer : public rfb::FullFramePixelBuffer
{
public:
XPixelBuffer(Display *dpy, ImageFactory &factory, const Rect &rect);
XPixelBuffer(Display *dpy, ImageFactory &factory, const rfb::Rect &rect);
virtual ~XPixelBuffer();

// Provide access to the underlying Image object.
const Image *getImage() const { return m_image; }

// Detect changed pixels, notify the server.
inline void poll(VNCServer *server) { m_poller->poll(server); }
inline void poll(rfb::VNCServer *server) { m_poller->poll(server); }

// Override PixelBuffer::grabRegion().
virtual void grabRegion(const rfb::Region& region);
@@ -59,7 +57,7 @@ protected:

// Copy pixels from the screen to the pixel buffer,
// for the specified rectangular area of the buffer.
inline void grabRect(const Rect &r) {
inline void grabRect(const rfb::Rect &r) {
m_image->get(DefaultRootWindow(m_dpy),
m_offsetLeft + r.tl.x, m_offsetTop + r.tl.y,
r.width(), r.height(), r.tl.x, r.tl.y);

+ 4
- 426
unix/x0vncserver/x0vncserver.cxx View File

@@ -31,7 +31,6 @@
#include <rfb/Configuration.h>
#include <rfb/Timer.h>
#include <network/TcpSocket.h>
#include <tx/TXWindow.h>

#include <vncconfig/QueryConnectDialog.h>

@@ -39,46 +38,17 @@
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#ifdef HAVE_XTEST
#include <X11/extensions/XTest.h>
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif

#include <x0vncserver/XDesktop.h>
#include <x0vncserver/Geometry.h>
#include <x0vncserver/Image.h>
#include <x0vncserver/XPixelBuffer.h>
#include <x0vncserver/PollingScheduler.h>

extern const unsigned short code_map_qnum_to_xorgevdev[];
extern const unsigned int code_map_qnum_to_xorgevdev_len;

extern const unsigned short code_map_qnum_to_xorgkbd[];
extern const unsigned int code_map_qnum_to_xorgkbd_len;

// XXX Lynx/OS 2.3: protos for select(), bzero()
#ifdef Lynx
#include <sys/proto.h>
#endif

extern char buildtime[];

using namespace rfb;
using namespace network;

// number of XKb indicator leds to handle
static const int N_LEDS = 3;

// order is important as it must match RFB extension
static const char * ledNames[N_LEDS] = {
"Scroll Lock", "Num Lock", "Caps Lock"
};

static LogWriter vlog("Main");

IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
@@ -87,8 +57,6 @@ IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of "
"CPU time to be consumed", 35);
BoolParameter useShm("UseSHM", "Use MIT-SHM extension if available", true);
BoolParameter useOverlay("OverlayMode", "Use overlay mode under "
"IRIX or Solaris", true);
StringParameter displayname("display", "The X display", "");
IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
IntParameter queryConnectTimeout("QueryConnectTimeout",
@@ -157,399 +125,6 @@ private:
};


class XDesktop : public SDesktop, public TXGlobalEventHandler
{
public:
XDesktop(Display* dpy_, Geometry *geometry_)
: dpy(dpy_), geometry(geometry_), pb(0), server(0),
oldButtonMask(0), haveXtest(false), haveDamage(false),
maxButtons(0), running(false), ledMasks(), ledState(0),
codeMap(0), codeMapLen(0)
{
int major, minor;

int xkbOpcode, xkbErrorBase;

major = XkbMajorVersion;
minor = XkbMinorVersion;
if (!XkbQueryExtension(dpy, &xkbOpcode, &xkbEventBase,
&xkbErrorBase, &major, &minor)) {
vlog.error("XKEYBOARD extension not present");
throw Exception();
}

XkbSelectEvents(dpy, XkbUseCoreKbd, XkbIndicatorStateNotifyMask,
XkbIndicatorStateNotifyMask);

// figure out bit masks for the indicators we are interested in
for (int i = 0; i < N_LEDS; i++) {
Atom a;
int shift;
Bool on;

a = XInternAtom(dpy, ledNames[i], True);
if (!a || !XkbGetNamedIndicator(dpy, a, &shift, &on, NULL, NULL))
continue;

ledMasks[i] = 1u << shift;
vlog.debug("Mask for '%s' is 0x%x", ledNames[i], ledMasks[i]);
if (on)
ledState |= 1u << i;
}

// X11 unfortunately uses keyboard driver specific keycodes and provides no
// direct way to query this, so guess based on the keyboard mapping
XkbDescPtr desc = XkbGetKeyboard(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
if (desc && desc->names) {
char *keycodes = XGetAtomName(dpy, desc->names->keycodes);

if (keycodes) {
if (strncmp("evdev", keycodes, strlen("evdev")) == 0) {
codeMap = code_map_qnum_to_xorgevdev;
codeMapLen = code_map_qnum_to_xorgevdev_len;
vlog.info("Using evdev codemap\n");
} else if (strncmp("xfree86", keycodes, strlen("xfree86")) == 0) {
codeMap = code_map_qnum_to_xorgkbd;
codeMapLen = code_map_qnum_to_xorgkbd_len;
vlog.info("Using xorgkbd codemap\n");
} else {
vlog.info("Unknown keycode '%s', no codemap\n", keycodes);
}
XFree(keycodes);
} else {
vlog.debug("Unable to get keycode map\n");
}

XkbFreeKeyboard(desc, XkbAllComponentsMask, True);
}

#ifdef HAVE_XTEST
int xtestEventBase;
int xtestErrorBase;

if (XTestQueryExtension(dpy, &xtestEventBase,
&xtestErrorBase, &major, &minor)) {
XTestGrabControl(dpy, True);
vlog.info("XTest extension present - version %d.%d",major,minor);
haveXtest = true;
} else {
#endif
vlog.info("XTest extension not present");
vlog.info("Unable to inject events or display while server is grabbed");
#ifdef HAVE_XTEST
}
#endif

#ifdef HAVE_XDAMAGE
int xdamageErrorBase;

if (XDamageQueryExtension(dpy, &xdamageEventBase, &xdamageErrorBase)) {
haveDamage = true;
} else {
#endif
vlog.info("DAMAGE extension not present");
vlog.info("Will have to poll screen for changes");
#ifdef HAVE_XDAMAGE
}
#endif

#ifdef HAVE_XFIXES
int xfixesErrorBase;

if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) {
XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy),
XFixesDisplayCursorNotifyMask);
} else {
#endif
vlog.info("XFIXES extension not present");
vlog.info("Will not be able to display cursors");
#ifdef HAVE_XFIXES
}
#endif

TXWindow::setGlobalEventHandler(this);
}
virtual ~XDesktop() {
stop();
}

inline void poll() {
if (pb and not haveDamage)
pb->poll(server);
if (running) {
Window root, child;
int x, y, wx, wy;
unsigned int mask;
XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
&x, &y, &wx, &wy, &mask);
server->setCursorPos(rfb::Point(x, y));
}
}

// -=- SDesktop interface

virtual void start(VNCServer* vs) {

// Determine actual number of buttons of the X pointer device.
unsigned char btnMap[8];
int numButtons = XGetPointerMapping(dpy, btnMap, 8);
maxButtons = (numButtons > 8) ? 8 : numButtons;
vlog.info("Enabling %d button%s of X pointer device",
maxButtons, (maxButtons != 1) ? "s" : "");

// Create an ImageFactory instance for producing Image objects.
ImageFactory factory((bool)useShm, (bool)useOverlay);

// Create pixel buffer and provide it to the server object.
pb = new XPixelBuffer(dpy, factory, geometry->getRect());
vlog.info("Allocated %s", pb->getImage()->classDesc());

server = (VNCServerST *)vs;
server->setPixelBuffer(pb);

#ifdef HAVE_XDAMAGE
if (haveDamage) {
damage = XDamageCreate(dpy, DefaultRootWindow(dpy),
XDamageReportRawRectangles);
}
#endif

server->setLEDState(ledState);

running = true;
}

virtual void stop() {
running = false;

#ifdef HAVE_XDAMAGE
if (haveDamage)
XDamageDestroy(dpy, damage);
#endif

delete pb;
pb = 0;
}

inline bool isRunning() {
return running;
}

virtual void pointerEvent(const Point& pos, int buttonMask) {
#ifdef HAVE_XTEST
if (!haveXtest) return;
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)) {
if (buttonMask & (1<<i)) {
XTestFakeButtonEvent(dpy, i+1, True, CurrentTime);
} else {
XTestFakeButtonEvent(dpy, i+1, False, CurrentTime);
}
}
}
}
oldButtonMask = buttonMask;
#endif
}

#ifdef HAVE_XTEST
KeyCode XkbKeysymToKeycode(Display* dpy, KeySym keysym) {
XkbDescPtr xkb;
XkbStateRec state;
unsigned keycode;

xkb = XkbGetMap(dpy, XkbAllComponentsMask, XkbUseCoreKbd);
if (!xkb)
return 0;

XkbGetState(dpy, XkbUseCoreKbd, &state);

for (keycode = xkb->min_key_code;
keycode <= xkb->max_key_code;
keycode++) {
KeySym cursym;
unsigned int mods, out_mods;
// XkbStateFieldFromRec() doesn't work properly because
// state.lookup_mods isn't properly updated, so we do this manually
mods = XkbBuildCoreState(XkbStateMods(&state), state.group);
XkbTranslateKeyCode(xkb, keycode, mods, &out_mods, &cursym);
if (cursym == keysym)
break;
}

if (keycode > xkb->max_key_code)
keycode = 0;

XkbFreeKeyboard(xkb, XkbAllComponentsMask, True);

return keycode;
}
#endif

virtual void keyEvent(rdr::U32 keysym, rdr::U32 xtcode, bool down) {
#ifdef HAVE_XTEST
int keycode = 0;

if (!haveXtest)
return;

// Use scan code if provided and mapping exists
if (codeMap && rawKeyboard && xtcode < codeMapLen)
keycode = codeMap[xtcode];

if (!keycode) {
if (pressedKeys.find(keysym) != pressedKeys.end())
keycode = pressedKeys[keysym];
else {
// XKeysymToKeycode() doesn't respect state, so we have to use
// something slightly more complex
keycode = XkbKeysymToKeycode(dpy, keysym);
}
}

if (!keycode)
return;

if (down)
pressedKeys[keysym] = keycode;
else
pressedKeys.erase(keysym);

XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
#endif
}

virtual void clientCutText(const char* str, int len) {
}

// -=- TXGlobalEventHandler interface

virtual bool handleGlobalEvent(XEvent* ev) {
if (ev->type == xkbEventBase + XkbEventCode) {
XkbEvent *kb = (XkbEvent *)ev;

if (kb->any.xkb_type != XkbIndicatorStateNotify)
return false;

vlog.debug("Got indicator update, mask is now 0x%x", kb->indicators.state);

ledState = 0;
for (int i = 0; i < N_LEDS; i++) {
if (kb->indicators.state & ledMasks[i])
ledState |= 1u << i;
}

if (running)
server->setLEDState(ledState);

return true;
#ifdef HAVE_XDAMAGE
} else if (ev->type == xdamageEventBase) {
XDamageNotifyEvent* dev;
Rect rect;

if (!running)
return true;

dev = (XDamageNotifyEvent*)ev;
rect.setXYWH(dev->area.x, dev->area.y, dev->area.width, dev->area.height);
server->add_changed(rect);

return true;
#endif
#ifdef HAVE_XFIXES
} else if (ev->type == xfixesEventBase + XFixesCursorNotify) {
XFixesCursorNotifyEvent* cev;
XFixesCursorImage *cim;

if (!running)
return true;

cev = (XFixesCursorNotifyEvent*)ev;

if (cev->subtype != XFixesDisplayCursorNotify)
return false;

cim = XFixesGetCursorImage(dpy);
if (cim == NULL)
return false;

// Copied from XserverDesktop::setCursor() in
// unix/xserver/hw/vnc/XserverDesktop.cc and adapted to
// handle long -> U32 conversion for 64-bit Xlib
rdr::U8* cursorData;
rdr::U8 *out;
const unsigned long *pixels;

cursorData = new rdr::U8[cim->width * cim->height * 4];

// Un-premultiply alpha
pixels = cim->pixels;
out = cursorData;
for (int y = 0; y < cim->height; y++) {
for (int x = 0; x < cim->width; x++) {
rdr::U8 alpha;
rdr::U32 pixel = *pixels++;
rdr::U8 *in = (rdr::U8 *) &pixel;

alpha = in[3];
if (alpha == 0)
alpha = 1; // Avoid division by zero

*out++ = (unsigned)*in++ * 255/alpha;
*out++ = (unsigned)*in++ * 255/alpha;
*out++ = (unsigned)*in++ * 255/alpha;
*out++ = *in++;
}
}

try {
server->setCursor(cim->width, cim->height, Point(cim->xhot, cim->yhot),
cursorData);
} catch (rdr::Exception& e) {
vlog.error("XserverDesktop::setCursor: %s",e.str());
}

delete [] cursorData;
XFree(cim);
return true;
#endif
}

return false;
}

protected:
Display* dpy;
Geometry* geometry;
XPixelBuffer* pb;
VNCServerST* server;
int oldButtonMask;
bool haveXtest;
bool haveDamage;
int maxButtons;
std::map<KeySym, KeyCode> pressedKeys;
bool running;
#ifdef HAVE_XDAMAGE
Damage damage;
int xdamageEventBase;
#endif
int xkbEventBase;
#ifdef HAVE_XFIXES
int xfixesEventBase;
#endif
int ledMasks[N_LEDS];
unsigned ledState;
const unsigned short *codeMap;
unsigned codeMapLen;
};


class FileTcpFilter : public TcpFilter
{

@@ -683,6 +258,9 @@ int main(int argc, char** argv)

Configuration::enableServerParams();

// Disable configuration parameters which we do not support
Configuration::removeParam("AcceptSetDesktopSize");

for (int i = 1; i < argc; i++) {
if (Configuration::setParam(argv[i]))
continue;

+ 0
- 7
unix/x0vncserver/x0vncserver.man View File

@@ -227,13 +227,6 @@ Use MIT-SHM extension if available. Using that extension accelerates reading
the screen. Default is on.
.
.TP
.B OverlayMode
Use overlay mode in IRIX or Solaris (does not have effect in other systems).
This enables system-specific access to complete full-color version of the
screen (the default X visual often provides 256 colors). Also, in overlay
mode, \fBx0vncserver\fP can show correct mouse cursor. Default is on.
.
.TP
.B ZlibLevel
Zlib compression level for ZRLE encoding (it does not affect Tight encoding).
Acceptable values are between 0 and 9. Default is to use the standard

+ 1
- 1
win/winvnc/winvnc.cxx View File

@@ -78,7 +78,7 @@ static void programUsage() {
printf("\nLog destinations:\n");
Logger::listLoggers();
printf("\nAvailable configuration parameters:\n");
Configuration::listParams(ConfServer);
Configuration::listParams(79, 14);
}

static void MsgBoxOrLog(const char* msg, bool isError=false) {

Loading…
Cancel
Save