Blame SOURCES/tigervnc-release-pointer-grab-when-cursor-leaves-window.patch

b0f0da
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
b0f0da
index f5ae425..cec8a68 100644
b0f0da
--- a/vncviewer/DesktopWindow.cxx
b0f0da
+++ b/vncviewer/DesktopWindow.cxx
b0f0da
@@ -65,6 +65,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
b0f0da
   : Fl_Window(w, h), cc(cc_), offscreen(NULL), overlay(NULL),
b0f0da
     firstUpdate(true),
b0f0da
     delayedFullscreen(false), delayedDesktopSize(false),
b0f0da
+    keyboardGrabbed(false), mouseGrabbed(false),
b0f0da
     statsLastFrame(0), statsLastPixels(0), statsLastPosition(0),
b0f0da
     statsGraph(NULL)
b0f0da
 {
b0f0da
@@ -630,9 +631,18 @@ int DesktopWindow::handle(int event)
b0f0da
     break;
b0f0da
 
b0f0da
   case FL_ENTER:
b0f0da
+      if (keyboardGrabbed)
b0f0da
+          grabPointer();
b0f0da
   case FL_LEAVE:
b0f0da
   case FL_DRAG:
b0f0da
   case FL_MOVE:
b0f0da
+    // We don't get FL_LEAVE with a grabbed pointer, so check manually
b0f0da
+    if (mouseGrabbed) {
b0f0da
+      if ((Fl::event_x() < 0) || (Fl::event_x() >= w()) ||
b0f0da
+          (Fl::event_y() < 0) || (Fl::event_y() >= h())) {
b0f0da
+        ungrabPointer();
b0f0da
+      }
b0f0da
+    }
b0f0da
     if (fullscreen_active()) {
b0f0da
       if (((viewport->x() < 0) && (Fl::event_x() < EDGE_SCROLL_SIZE)) ||
b0f0da
           ((viewport->x() + viewport->w() > w()) && (Fl::event_x() > w() - EDGE_SCROLL_SIZE)) ||
b0f0da
@@ -677,6 +687,16 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
b0f0da
     case FL_UNFOCUS:
b0f0da
       dw->ungrabKeyboard();
b0f0da
       break;
b0f0da
+
b0f0da
+    case FL_RELEASE:
b0f0da
+      // We usually fail to grab the mouse if a mouse button was
b0f0da
+      // pressed when we gained focus (e.g. clicking on our window),
b0f0da
+      // so we may need to try again when the button is released.
b0f0da
+      // (We do it here rather than handle() because a window does not
b0f0da
+      // see FL_RELEASE events if a child widget grabs it first)
b0f0da
+      if (dw->keyboardGrabbed && !dw->mouseGrabbed)
b0f0da
+        dw->grabPointer();
b0f0da
+      break;
b0f0da
     }
b0f0da
   }
b0f0da
 
b0f0da
@@ -757,14 +777,18 @@ void DesktopWindow::grabKeyboard()
b0f0da
   int ret;
b0f0da
 
b0f0da
   ret = win32_enable_lowlevel_keyboard(fl_xid(this));
b0f0da
-  if (ret != 0)
b0f0da
+  if (ret != 0) {
b0f0da
     vlog.error(_("Failure grabbing keyboard"));
b0f0da
+    return;
b0f0da
+  }
b0f0da
 #elif defined(__APPLE__)
b0f0da
   int ret;
b0f0da
 
b0f0da
   ret = cocoa_capture_display(this, fullScreenAllMonitors);
b0f0da
-  if (ret != 0)
b0f0da
+  if (ret != 0) {
b0f0da
     vlog.error(_("Failure grabbing keyboard"));
b0f0da
+    return;
b0f0da
+  }
b0f0da
 #else
b0f0da
   int ret;
b0f0da
 
b0f0da
@@ -784,18 +808,9 @@ void DesktopWindow::grabKeyboard()
b0f0da
     } else {
b0f0da
       vlog.error(_("Failure grabbing keyboard"));
b0f0da
     }
b0f0da
+    return;
b0f0da
   }
b0f0da
 
b0f0da
-  // We also need to grab the pointer as some WMs like to grab buttons
b0f0da
-  // combined with modifies (e.g. Alt+Button0 in metacity).
b0f0da
-  ret = XGrabPointer(fl_display, fl_xid(this), True,
b0f0da
-                     ButtonPressMask|ButtonReleaseMask|
b0f0da
-                     ButtonMotionMask|PointerMotionMask,
b0f0da
-                     GrabModeAsync, GrabModeAsync,
b0f0da
-                     None, None, CurrentTime);
b0f0da
-  if (ret)
b0f0da
-    vlog.error(_("Failure grabbing mouse"));
b0f0da
-
b0f0da
   // Xorg 1.20+ generates FocusIn/FocusOut even when there is no actual
b0f0da
   // change of focus. This causes us to get stuck in an endless loop
b0f0da
   // grabbing and ungrabbing the keyboard. Avoid this by filtering out
b0f0da
@@ -806,6 +821,11 @@ void DesktopWindow::grabKeyboard()
b0f0da
     vlog.debug("Ignored synthetic focus event cause by grab change");
b0f0da
   }
b0f0da
 #endif
b0f0da
+
b0f0da
+  keyboardGrabbed = true;
b0f0da
+
b0f0da
+  if (contains(Fl::belowmouse()))
b0f0da
+    grabPointer();
b0f0da
 }
b0f0da
 
b0f0da
 
b0f0da
@@ -813,6 +833,10 @@ void DesktopWindow::ungrabKeyboard()
b0f0da
 {
b0f0da
   Fl::remove_timeout(handleGrab, this);
b0f0da
 
b0f0da
+  keyboardGrabbed = false;
b0f0da
+
b0f0da
+  ungrabPointer();
b0f0da
+
b0f0da
 #if defined(WIN32)
b0f0da
   win32_disable_lowlevel_keyboard(fl_xid(this));
b0f0da
 #elif defined(__APPLE__)
b0f0da
@@ -827,7 +851,6 @@ void DesktopWindow::ungrabKeyboard()
b0f0da
 
b0f0da
   serial = XNextRequest(fl_display);
b0f0da
 
b0f0da
-  XUngrabPointer(fl_display, CurrentTime);
b0f0da
   XUngrabKeyboard(fl_display, CurrentTime);
b0f0da
 
b0f0da
   // See grabKeyboard()
b0f0da
@@ -839,6 +862,38 @@ void DesktopWindow::ungrabKeyboard()
b0f0da
 #endif
b0f0da
 }
b0f0da
 
b0f0da
+void DesktopWindow::grabPointer()
b0f0da
+{
b0f0da
+#if !defined(WIN32) && !defined(__APPLE__)
b0f0da
+  int ret;
b0f0da
+
b0f0da
+  // We also need to grab the pointer as some WMs like to grab buttons
b0f0da
+  // combined with modifies (e.g. Alt+Button0 in metacity).
b0f0da
+  ret = XGrabPointer(fl_display, fl_xid(this), True,
b0f0da
+                     ButtonPressMask|ButtonReleaseMask|
b0f0da
+                     ButtonMotionMask|PointerMotionMask,
b0f0da
+                     GrabModeAsync, GrabModeAsync,
b0f0da
+                     None, None, CurrentTime);
b0f0da
+  if (ret) {
b0f0da
+    // Having a button pressed prevents us from grabbing, we make
b0f0da
+    // a new attempt in fltkHandle()
b0f0da
+    if (ret == AlreadyGrabbed)
b0f0da
+      return;
b0f0da
+    vlog.error(_("Failure grabbing mouse"));
b0f0da
+    return;
b0f0da
+  }
b0f0da
+#endif
b0f0da
+
b0f0da
+  mouseGrabbed = true;
b0f0da
+}
b0f0da
+
b0f0da
+void DesktopWindow::ungrabPointer()
b0f0da
+{
b0f0da
+  mouseGrabbed = false;
b0f0da
+#if !defined(WIN32) && !defined(__APPLE__)
b0f0da
+  XUngrabPointer(fl_display, CurrentTime);
b0f0da
+#endif
b0f0da
+}
b0f0da
 
b0f0da
 void DesktopWindow::handleGrab(void *data)
b0f0da
 {
b0f0da
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
b0f0da
index 4224699..2135be8 100644
b0f0da
--- a/vncviewer/DesktopWindow.h
b0f0da
+++ b/vncviewer/DesktopWindow.h
b0f0da
@@ -84,6 +84,8 @@ private:
b0f0da
 
b0f0da
   void grabKeyboard();
b0f0da
   void ungrabKeyboard();
b0f0da
+  void grabPointer();
b0f0da
+  void ungrabPointer();
b0f0da
 
b0f0da
   static void handleGrab(void *data);
b0f0da
 
b0f0da
@@ -120,6 +122,9 @@ private:
b0f0da
   bool delayedFullscreen;
b0f0da
   bool delayedDesktopSize;
b0f0da
 
b0f0da
+  bool keyboardGrabbed;
b0f0da
+  bool mouseGrabbed;
b0f0da
+
b0f0da
   struct statsEntry {
b0f0da
     unsigned fps;
b0f0da
     unsigned pps;