Skip to content

Commit

Permalink
Better fix for fake focus grab events
Browse files Browse the repository at this point in the history
The fake ones have a special mode, so we can simply filter them before
they are passed on as FLTK events.
  • Loading branch information
CendioOssman committed Oct 2, 2024
1 parent 10b002f commit 6f1e961
Showing 1 changed file with 11 additions and 45 deletions.
56 changes: 11 additions & 45 deletions vncviewer/DesktopWindow.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,17 @@ int DesktopWindow::fltkDispatch(int event, Fl_Window *win)
if ((event == FL_MOVE) && (win == nullptr))
return 0;

#if !defined(WIN32) && !defined(__APPLE__)
// FLTK passes through the fake grab focus events that can cause us
// to end up in an infinite loop
// https://github.com/fltk/fltk/issues/295
if ((event == FL_FOCUS) || (event == FL_UNFOCUS)) {
const XFocusChangeEvent* xfocus = &fl_xevent->xfocus;
if ((xfocus->mode == NotifyGrab) || (xfocus->mode == NotifyUngrab))
return 0;
}
#endif

ret = Fl::handle_(event, win);

// This is hackish and the result of the dodgy focus handling in FLTK.
Expand Down Expand Up @@ -1040,24 +1051,6 @@ 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

bool DesktopWindow::hasFocus()
{
Fl_Widget* focus;
Expand Down Expand Up @@ -1105,11 +1098,6 @@ 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) {
Expand All @@ -1123,16 +1111,6 @@ 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;
Expand All @@ -1159,19 +1137,7 @@ 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
}

Expand Down

0 comments on commit 6f1e961

Please sign in to comment.