Merge branch 'cursor' of https://github.com/alanc/tigervnc
diff --git a/unix/x0vncserver/x0vncserver.cxx b/unix/x0vncserver/x0vncserver.cxx
index 025a095..d3042db 100644
--- a/unix/x0vncserver/x0vncserver.cxx
+++ b/unix/x0vncserver/x0vncserver.cxx
@@ -46,6 +46,9 @@
 #ifdef HAVE_XDAMAGE
 #include <X11/extensions/Xdamage.h>
 #endif
+#ifdef HAVE_XFIXES
+#include <X11/extensions/Xfixes.h>
+#endif
 
 #include <x0vncserver/Geometry.h>
 #include <x0vncserver/Image.h>
@@ -160,8 +163,8 @@
   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)
+      haveXfixes(false),  maxButtons(0), running(false),
+      ledMasks(), ledState(0), codeMap(0), codeMapLen(0)
   {
     int major, minor;
 
@@ -250,6 +253,19 @@
     }
 #endif
 
+#ifdef HAVE_XFIXES
+    int xfixesErrorBase;
+
+    if (XFixesQueryExtension(dpy, &xfixesEventBase, &xfixesErrorBase)) {
+      haveXfixes = true;
+    } 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() {
@@ -289,6 +305,13 @@
     }
 #endif
 
+#ifdef HAVE_XFIXES
+    if (haveXfixes) {
+      XFixesSelectCursorInput(dpy, DefaultRootWindow(dpy),
+                              XFixesDisplayCursorNotifyMask);
+    }
+#endif
+
     server->setLEDState(ledState);
 
     running = true;
@@ -438,6 +461,63 @@
 
       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;
@@ -451,6 +531,7 @@
   int oldButtonMask;
   bool haveXtest;
   bool haveDamage;
+  bool haveXfixes;
   int maxButtons;
   std::map<KeySym, KeyCode> pressedKeys;
   bool running;
@@ -459,6 +540,9 @@
   int xdamageEventBase;
 #endif
   int xkbEventBase;
+#ifdef HAVE_XFIXES
+  int xfixesEventBase;
+#endif
   int ledMasks[N_LEDS];
   unsigned ledState;
   const unsigned short *codeMap;