diff options
Diffstat (limited to 'vncviewer/DesktopWindow.cxx')
-rw-r--r-- | vncviewer/DesktopWindow.cxx | 57 |
1 files changed, 48 insertions, 9 deletions
diff --git a/vncviewer/DesktopWindow.cxx b/vncviewer/DesktopWindow.cxx index e86e90e6..e8750b4e 100644 --- a/vncviewer/DesktopWindow.cxx +++ b/vncviewer/DesktopWindow.cxx @@ -684,23 +684,18 @@ int DesktopWindow::fltkHandle(int event, Fl_Window *win) if (dw) { 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: if (fullscreenSystemKeys) { - // 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: if (fullscreenSystemKeys) { - // 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; @@ -766,6 +761,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 @@ -793,6 +805,11 @@ void DesktopWindow::grabKeyboard() #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) { @@ -806,6 +823,16 @@ void DesktopWindow::grabKeyboard() } return; } + + // 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 keyboardGrabbed = true; @@ -832,7 +859,19 @@ void DesktopWindow::ungrabKeyboard() if (Fl::grab()) return; + XEvent xev; + unsigned long serial; + + serial = XNextRequest(fl_display); + XUngrabKeyboard(fl_display, CurrentTime); + + // 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 } |