Blob Blame History Raw
diff --git a/unix/x0vncserver/XDesktop.cxx b/unix/x0vncserver/XDesktop.cxx
index f2046e43..8805be51 100644
--- a/unix/x0vncserver/XDesktop.cxx
+++ b/unix/x0vncserver/XDesktop.cxx
@@ -80,7 +80,7 @@ XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
     queryConnectDialog(0), queryConnectSock(0),
     oldButtonMask(0), haveXtest(false), haveDamage(false),
     maxButtons(0), running(false), ledMasks(), ledState(0),
-    codeMap(0), codeMapLen(0)
+    codeMap(0), codeMapLen(0), isCursorVisibleOnScreen(false)
 {
   int major, minor;
 
@@ -192,7 +192,7 @@ XDesktop::XDesktop(Display* dpy_, Geometry *geometry_)
                    RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask);
     /* Override TXWindow::init input mask */
     XSelectInput(dpy, DefaultRootWindow(dpy),
-                 PropertyChangeMask | StructureNotifyMask | ExposureMask);
+                 PropertyChangeMask | StructureNotifyMask | ExposureMask | EnterWindowMask | LeaveWindowMask);
   } else {
 #endif
     vlog.info("RANDR extension not present");
@@ -217,11 +217,13 @@ void XDesktop::poll() {
     Window root, child;
     int x, y, wx, wy;
     unsigned int mask;
-    XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
-                  &x, &y, &wx, &wy, &mask);
-    x -= geometry->offsetLeft();
-    y -= geometry->offsetTop();
-    server->setCursorPos(rfb::Point(x, y), false);
+    isCursorVisibleOnScreen = XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
+                                            &x, &y, &wx, &wy, &mask);
+    if (isCursorVisibleOnScreen) {
+      x -= geometry->offsetLeft();
+      y -= geometry->offsetTop();
+      server->setCursorPos(rfb::Point(x, y), false);
+    }
   }
 }
 
@@ -253,7 +255,15 @@ void XDesktop::start(VNCServer* vs) {
 #endif
 
 #ifdef HAVE_XFIXES
-  setCursor();
+  Window root, child;
+  int x, y, wx, wy;
+  unsigned int mask;
+  // Check whether the cursor is initially on our screen
+  isCursorVisibleOnScreen = XQueryPointer(dpy, DefaultRootWindow(dpy), &root, &child,
+                                          &x, &y, &wx, &wy, &mask);
+  if (isCursorVisibleOnScreen)
+    setCursor();
+
 #endif
 
   server->setLEDState(ledState);
@@ -701,6 +711,9 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
     if (cev->subtype != XFixesDisplayCursorNotify)
       return false;
 
+    if (!isCursorVisibleOnScreen)
+      return false;
+
     return setCursor();
 #endif
 #ifdef HAVE_XRANDR
@@ -753,6 +766,20 @@ bool XDesktop::handleGlobalEvent(XEvent* ev) {
 
     return true;
 #endif
+  } else if (ev->type == EnterNotify || ev->type == LeaveNotify) {
+    XCrossingEvent* cev;
+
+    if (!running)
+      return true;
+
+    cev = (XCrossingEvent*)ev;
+
+    if (cev->window != cev->root)
+      return false;
+
+    setCursor();
+
+    return true;
   }
 
   return false;
diff --git a/unix/x0vncserver/XDesktop.h b/unix/x0vncserver/XDesktop.h
index 840d4331..f01c63f7 100644
--- a/unix/x0vncserver/XDesktop.h
+++ b/unix/x0vncserver/XDesktop.h
@@ -97,6 +97,7 @@ protected:
   unsigned ledState;
   const unsigned short *codeMap;
   unsigned codeMapLen;
+  bool isCursorVisibleOnScreen;
   bool setCursor();
   rfb::ScreenSet computeScreenLayout();
 };