]> source.dussan.org Git - tigervnc.git/commitdiff
Release pointer grab when cursor leaves window
authorPierre Ossman <ossman@cendio.se>
Mon, 18 Sep 2017 14:05:48 +0000 (16:05 +0200)
committerPierre Ossman <ossman@cendio.se>
Mon, 18 Sep 2017 14:05:48 +0000 (16:05 +0200)
We don't need the grab any more if the pointer cannot click on our
window. This makes it possible to shift focus to another application
when we aren't covering all monitors.

vncviewer/DesktopWindow.cxx
vncviewer/DesktopWindow.h

index 897f9557382b3ef679d462563d9051404c0a43f5..d026b9027faa987143c7f25c5027f3d119672dd9 100644 (file)
@@ -65,6 +65,7 @@ DesktopWindow::DesktopWindow(int w, int h, const char *name,
   : Fl_Window(w, h), cc(cc_), offscreen(NULL), overlay(NULL),
     firstUpdate(true),
     delayedFullscreen(false), delayedDesktopSize(false),
+    keyboardGrabbed(false), mouseGrabbed(false),
     statsLastFrame(0), statsLastPixels(0), statsLastPosition(0),
     statsGraph(NULL)
 {
@@ -633,9 +634,18 @@ int DesktopWindow::handle(int event)
     break;
 
   case FL_ENTER:
+      if (keyboardGrabbed)
+          grabPointer();
   case FL_LEAVE:
   case FL_DRAG:
   case FL_MOVE:
+    // We don't get FL_LEAVE with a grabbed pointer, so check manually
+    if (mouseGrabbed) {
+      if ((Fl::event_x() < 0) || (Fl::event_x() >= w()) ||
+          (Fl::event_y() < 0) || (Fl::event_y() >= h())) {
+        ungrabPointer();
+      }
+    }
     if (fullscreen_active()) {
       if (((viewport->x() < 0) && (Fl::event_x() < EDGE_SCROLL_SIZE)) ||
           ((viewport->x() + viewport->w() > w()) && (Fl::event_x() > w() - EDGE_SCROLL_SIZE)) ||
@@ -692,6 +702,16 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
         dw->ungrabKeyboard();
       }
       break;
+
+    case FL_RELEASE:
+      // We usually fail to grab the mouse if a mouse button was
+      // pressed when we gained focus (e.g. clicking on our window),
+      // so we may need to try again when the button is released.
+      // (We do it here rather than handle() because a window does not
+      // see FL_RELEASE events if a child widget grabs it first)
+      if (dw->keyboardGrabbed && !dw->mouseGrabbed)
+        dw->grabPointer();
+      break;
     }
   }
 
@@ -755,14 +775,18 @@ void DesktopWindow::grabKeyboard()
   int ret;
   
   ret = win32_enable_lowlevel_keyboard(fl_xid(this));
-  if (ret != 0)
+  if (ret != 0) {
     vlog.error(_("Failure grabbing keyboard"));
+    return;
+  }
 #elif defined(__APPLE__)
   int ret;
   
   ret = cocoa_capture_display(this, fullScreenAllMonitors);
-  if (ret != 0)
+  if (ret != 0) {
     vlog.error(_("Failure grabbing keyboard"));
+    return;
+  }
 #else
   int ret;
 
@@ -777,18 +801,14 @@ void DesktopWindow::grabKeyboard()
     } else {
       vlog.error(_("Failure grabbing keyboard"));
     }
+    return;
   }
-
-  // We also need to grab the pointer as some WMs like to grab buttons
-  // combined with modifies (e.g. Alt+Button0 in metacity).
-  ret = XGrabPointer(fl_display, fl_xid(this), True,
-                     ButtonPressMask|ButtonReleaseMask|
-                     ButtonMotionMask|PointerMotionMask,
-                     GrabModeAsync, GrabModeAsync,
-                     None, None, CurrentTime);
-  if (ret)
-    vlog.error(_("Failure grabbing mouse"));
 #endif
+
+  keyboardGrabbed = true;
+
+  if (contains(Fl::belowmouse()))
+    grabPointer();
 }
 
 
@@ -796,6 +816,10 @@ void DesktopWindow::ungrabKeyboard()
 {
   Fl::remove_timeout(handleGrab, this);
 
+  keyboardGrabbed = false;
+
+  ungrabPointer();
+
 #if defined(WIN32)
   win32_disable_lowlevel_keyboard(fl_xid(this));
 #elif defined(__APPLE__)
@@ -805,12 +829,47 @@ void DesktopWindow::ungrabKeyboard()
   if (Fl::grab())
     return;
 
-  XUngrabPointer(fl_display, fl_event_time);
   XUngrabKeyboard(fl_display, fl_event_time);
 #endif
 }
 
 
+void DesktopWindow::grabPointer()
+{
+#if !defined(WIN32) && !defined(__APPLE__)
+  int ret;
+
+  // We also need to grab the pointer as some WMs like to grab buttons
+  // combined with modifies (e.g. Alt+Button0 in metacity).
+  ret = XGrabPointer(fl_display, fl_xid(this), True,
+                     ButtonPressMask|ButtonReleaseMask|
+                     ButtonMotionMask|PointerMotionMask,
+                     GrabModeAsync, GrabModeAsync,
+                     None, None, CurrentTime);
+  if (ret) {
+    // Having a button pressed prevents us from grabbing, we make
+    // a new attempt in fltkHandle()
+    if (ret == AlreadyGrabbed)
+      return;
+    vlog.error(_("Failure grabbing mouse"));
+    return;
+  }
+#endif
+
+  mouseGrabbed = true;
+}
+
+
+void DesktopWindow::ungrabPointer()
+{
+  vlog.info("ungrabPointer");
+  mouseGrabbed = false;
+#if !defined(WIN32) && !defined(__APPLE__)
+  XUngrabPointer(fl_display, fl_event_time);
+#endif
+}
+
+
 void DesktopWindow::handleGrab(void *data)
 {
   DesktopWindow *self = (DesktopWindow*)data;
index f1bf312ff366852b58d9c50b380f125d6429d375..9700044ac79f12c743b334f0d920e170221421d2 100644 (file)
@@ -87,6 +87,8 @@ private:
 
   void grabKeyboard();
   void ungrabKeyboard();
+  void grabPointer();
+  void ungrabPointer();
 
   static void handleGrab(void *data);
 
@@ -123,6 +125,9 @@ private:
   bool delayedFullscreen;
   bool delayedDesktopSize;
 
+  bool keyboardGrabbed;
+  bool mouseGrabbed;
+
   struct statsEntry {
     unsigned fps;
     unsigned pps;