diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx
index 47fe8f8..8f387dc 100644
--- a/vncviewer/DesktopWindow.cxx
+++ b/vncviewer/DesktopWindow.cxx
@@ -1,16 +1,16 @@
/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
- *
+ *
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
@@ -662,20 +662,16 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win)
if (dw && fullscreenSystemKeys) {
switch (event) {
+ // Focus might not stay with us just because we have grabbed the
+ // keyboard. E.g. we might have sub windows, or we're not using
+ // all monitors and the user clicked on another application.
+ // Make sure we update our grabs with the focus changes.
case FL_FOCUS:
- // FIXME: We reassert the keyboard grabbing on focus as FLTK there are
- // some issues we need to work around:
- // a) Fl::grab(0) on X11 will release the keyboard grab for us.
- // b) Gaining focus on the system level causes FLTK to switch
- // window level on OS X.
if (dw->fullscreen_active())
dw->grabKeyboard();
break;
case FL_UNFOCUS:
- // FIXME: We need to relinquish control when the entire window loses
- // focus as it is very tied to this specific window on some
- // platforms and we want to be able to open subwindows.
dw->ungrabKeyboard();
break;
}
@@ -729,6 +725,23 @@ void DesktopWindow::fullscreen_on()
fullscreen();
}
+#if !defined(WIN32) && !defined(__APPLE__)
+Bool eventIsFocusWithSerial(Display *display, XEvent *event, XPointer arg)
+{
+ unsigned long serial;
+
+ serial = *(unsigned long*)arg;
+
+ if (event->xany.serial != serial)
+ return False;
+
+ if ((event->type != FocusIn) && (event->type != FocusOut))
+ return False;
+
+ return True;
+}
+#endif
+
void DesktopWindow::grabKeyboard()
{
// Grabbing the keyboard is fairly safe as FLTK reroutes events to the
@@ -739,19 +752,24 @@ void DesktopWindow::grabKeyboard()
#if defined(WIN32)
int ret;
-
+
ret = win32_enable_lowlevel_keyboard(fl_xid(this));
if (ret != 0)
vlog.error(_("Failure grabbing keyboard"));
#elif defined(__APPLE__)
int ret;
-
+
ret = cocoa_capture_display(this, fullScreenAllMonitors);
if (ret != 0)
vlog.error(_("Failure grabbing keyboard"));
#else
int ret;
+ XEvent xev;
+ unsigned long serial;
+
+ serial = XNextRequest(fl_display);
+
ret = XGrabKeyboard(fl_display, fl_xid(this), True,
GrabModeAsync, GrabModeAsync, CurrentTime);
if (ret) {
@@ -774,6 +792,16 @@ void DesktopWindow::grabKeyboard()
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
+ // any focus events generated by XGrabKeyboard().
+ XSync(fl_display, False);
+ while (XCheckIfEvent(fl_display, &xev, &eventIsFocusWithSerial,
+ (XPointer)&serial) == True) {
+ vlog.debug("Ignored synthetic focus event cause by grab change");
+ }
#endif
}
@@ -791,8 +819,20 @@ void DesktopWindow::ungrabKeyboard()
if (Fl::grab())
return;
+ XEvent xev;
+ unsigned long serial;
+
+ serial = XNextRequest(fl_display);
+
XUngrabPointer(fl_display, fl_event_time);
XUngrabKeyboard(fl_display, fl_event_time);
+
+ // See grabKeyboard()
+ XSync(fl_display, False);
+ while (XCheckIfEvent(fl_display, &xev, &eventIsFocusWithSerial,
+ (XPointer)&serial) == True) {
+ vlog.debug("Ignored synthetic focus event cause by grab change");
+ }
#endif
}