瀏覽代碼

Move XDesktop to separate file

Define ledNames in XDesktop.cxx, rename N_LEDS to XDESKTOP_N_LEDS
tags/v1.8.90
Peter Åstrand (astrand) 6 年之前
父節點
當前提交
3112f50062
共有 4 個檔案被更改,包括 499 行新增419 行删除
  1. 1
    0
      unix/x0vncserver/CMakeLists.txt
  2. 418
    0
      unix/x0vncserver/XDesktop.cxx
  3. 79
    0
      unix/x0vncserver/XDesktop.h
  4. 1
    419
      unix/x0vncserver/x0vncserver.cxx

+ 1
- 0
unix/x0vncserver/CMakeLists.txt 查看文件

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


+ 418
- 0
unix/x0vncserver/XDesktop.cxx 查看文件

@@ -0,0 +1,418 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2004-2008 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.
*/

#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 useOverlay;
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, (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;
}

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;
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;
}


+ 79
- 0
unix/x0vncserver/XDesktop.h 查看文件

@@ -0,0 +1,79 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright (C) 2004-2008 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.
*/

#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;
};

#endif // __XDESKTOP_H__

+ 1
- 419
unix/x0vncserver/x0vncserver.cxx 查看文件

@@ -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,28 +38,12 @@
#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>
@@ -71,14 +54,6 @@ 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 "
@@ -157,399 +132,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
{


Loading…
取消
儲存