]> source.dussan.org Git - tigervnc.git/commitdiff
Move XDesktop to separate file
authorPeter Åstrand (astrand) <astrand@cendio.se>
Tue, 10 Oct 2017 10:27:38 +0000 (12:27 +0200)
committerPeter Åstrand (astrand) <astrand@cendio.se>
Wed, 8 Nov 2017 09:40:12 +0000 (10:40 +0100)
Define ledNames in XDesktop.cxx, rename N_LEDS to XDESKTOP_N_LEDS

unix/x0vncserver/CMakeLists.txt
unix/x0vncserver/XDesktop.cxx [new file with mode: 0644]
unix/x0vncserver/XDesktop.h [new file with mode: 0644]
unix/x0vncserver/x0vncserver.cxx

index 5831c4d59cffa6711668d2d8563f678907a0f101..5930e32ac549a9de10f1dda2c93951d83f169a10 100644 (file)
@@ -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 (file)
index 0000000..c60d081
--- /dev/null
@@ -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;
+}
+
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
new file mode 100644 (file)
index 0000000..cc513a0
--- /dev/null
@@ -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__
index 6fd6bc3b7e7b723c40a4bb8421e38d51c73c7391..b21daae468d2f9b37b39f5cb402e275a0b7b6064 100644 (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>
 
 #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
 {