diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index f5ae425..cec8a68 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -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)
{
@@ -630,9 +631,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)) ||
@@ -677,6 +687,16 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
case FL_UNFOCUS:
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;
}
}
@@ -757,14 +777,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;
@@ -784,18 +808,9 @@ 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"));
-
// Xorg 1.20+ generates FocusIn/FocusOut even when there is no actual
// change of focus. This causes us to get stuck in an endless loop
// grabbing and ungrabbing the keyboard. Avoid this by filtering out
@@ -806,6 +821,11 @@ void DesktopWindow::grabKeyboard()
vlog.debug("Ignored synthetic focus event cause by grab change");
}
#endif
+
+ keyboardGrabbed = true;
+
+ if (contains(Fl::belowmouse()))
+ grabPointer();
}
@@ -813,6 +833,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__)
@@ -827,7 +851,6 @@ void DesktopWindow::ungrabKeyboard()
serial = XNextRequest(fl_display);
- XUngrabPointer(fl_display, CurrentTime);
XUngrabKeyboard(fl_display, CurrentTime);
// See grabKeyboard()
@@ -839,6 +862,38 @@ void DesktopWindow::ungrabKeyboard()
#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()
+{
+ mouseGrabbed = false;
+#if !defined(WIN32) && !defined(__APPLE__)
+ XUngrabPointer(fl_display, CurrentTime);
+#endif
+}
void DesktopWindow::handleGrab(void *data)
{
diff --git a/vncviewer/DesktopWindow.h b/vncviewer/DesktopWindow.h
index 4224699..2135be8 100644
--- a/vncviewer/DesktopWindow.h
+++ b/vncviewer/DesktopWindow.h
@@ -84,6 +84,8 @@ private:
void grabKeyboard();
void ungrabKeyboard();
+ void grabPointer();
+ void ungrabPointer();
static void handleGrab(void *data);
@@ -120,6 +122,9 @@ private:
bool delayedFullscreen;
bool delayedDesktopSize;
+ bool keyboardGrabbed;
+ bool mouseGrabbed;
+
struct statsEntry {
unsigned fps;
unsigned pps;