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;