From 3112f50062d57835148b5540cce1be5fa63a512b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Peter=20=C3=85strand=20=28astrand=29?= Date: Tue, 10 Oct 2017 12:27:38 +0200 Subject: [PATCH] Move XDesktop to separate file Define ledNames in XDesktop.cxx, rename N_LEDS to XDESKTOP_N_LEDS --- unix/x0vncserver/CMakeLists.txt | 1 + unix/x0vncserver/XDesktop.cxx | 418 ++++++++++++++++++++++++++++++ unix/x0vncserver/XDesktop.h | 79 ++++++ unix/x0vncserver/x0vncserver.cxx | 420 +------------------------------ 4 files changed, 499 insertions(+), 419 deletions(-) create mode 100644 unix/x0vncserver/XDesktop.cxx create mode 100644 unix/x0vncserver/XDesktop.h diff --git a/unix/x0vncserver/CMakeLists.txt b/unix/x0vncserver/CMakeLists.txt index 5831c4d5..5930e32a 100644 --- a/unix/x0vncserver/CMakeLists.txt +++ b/unix/x0vncserver/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(x0vncserver qnum_to_xorgkbd.c x0vncserver.cxx XPixelBuffer.cxx + XDesktop.cxx ../vncconfig/QueryConnectDialog.cxx ) diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx new file mode 100644 index 00000000..c60d0813 --- /dev/null +++ b/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 + +#include +#ifdef HAVE_XTEST +#include +#endif +#ifdef HAVE_XDAMAGE +#include +#endif +#ifdef HAVE_XFIXES +#include +#endif + +#include +#include + +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<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; +} + diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h new file mode 100644 index 00000000..cc513a03 --- /dev/null +++ b/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 +#include + +#include +#ifdef HAVE_XDAMAGE +#include +#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 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__ diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx index 6fd6bc3b..b21daae4 100644 --- a/unix/x0vncserver/x0vncserver.cxx +++ b/unix/x0vncserver/x0vncserver.cxx @@ -31,7 +31,6 @@ #include #include #include -#include #include @@ -39,28 +38,12 @@ #include #include #include -#include -#ifdef HAVE_XTEST -#include -#endif -#ifdef HAVE_XDAMAGE -#include -#endif -#ifdef HAVE_XFIXES -#include -#endif +#include #include #include -#include #include -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 @@ -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<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 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 { -- 2.39.5