From a3e264e8a3b1249ffd151bfea8cbf7ed26a39b1b Mon Sep 17 00:00:00 2001 From: ali kettab Date: Fri, 15 May 2020 22:25:40 +0100 Subject: [PATCH] Make wxSetInputFocusToXWindow a member instead of free function Also add a couple of workarounds for problems when using Xvfb. See https://github.com/wxWidgets/wxWidgets/pull/1845 --- src/unix/uiactionx11.cpp | 69 ++++++++++++++++++++++++++----------- tests/menu/menu.cpp | 4 +++ tests/validators/valnum.cpp | 10 ++++++ 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/src/unix/uiactionx11.cpp b/src/unix/uiactionx11.cpp index 8f603b6c3a..f1031d5133 100644 --- a/src/unix/uiactionx11.cpp +++ b/src/unix/uiactionx11.cpp @@ -25,33 +25,16 @@ #include #endif +#include "wx/log.h" +#include "wx/window.h" // for wxGetActiveWindow #include "wx/unix/utilsx11.h" #ifdef __WXGTK20__ -#include "wx/window.h" #include "wx/gtk/private/wrapgtk.h" #include GtkWidget* wxGetTopLevelGTK(); GdkWindow* wxGetTopLevelGDK(); - -// This helper function tries to set the input focus to the correct (top level) -// window, i.e.: the window to which keyboard events will be reported. -static inline void wxSetInputFocusToXWindow(wxX11Display& display) -{ - wxWindow* const win = wxGetActiveWindow(); - - GdkWindow* gdkwin; - - if ( win && win->IsTopLevel() ) - gdkwin = gtk_widget_get_window(win->GetHandle()); - else - gdkwin = wxGetTopLevelGDK(); - - XSetInputFocus(display, GDK_WINDOW_XID(gdkwin), RevertToPointerRoot, CurrentTime); -} -#else // !__WXGTK__ -#define wxSetInputFocusToXWindow(display) #endif // __WXGTK__ // Normally we fall back on "plain X" implementation if XTest is not available, @@ -147,7 +130,53 @@ protected: wxYield(); wxMilliSleep(50); - wxSetInputFocusToXWindow(m_display); + SetInputFocusToXWindow(); + } + + // This helper function tries to set the input focus to the active (top level) + // window, i.e.: the window to which keyboard events will be reported. + // + // Normally we would expect the input focus to be correctly set by the WM. + // But for some reasons, the input focus is set to PointerRoot under Xvfb, + // which means: all keyboard events are forewarded to whatever is underneath + // mouse pointer. and consequently, our fake events could be simply lost and + // do not reach the subject window at all. + void SetInputFocusToXWindow() + { + Window focus; + int revert_to; // dummy + + XGetInputFocus(m_display, &focus, &revert_to); + + if ( focus != PointerRoot && focus != None ) + return; + + wxWindow* win = wxGetActiveWindow(); + + #if defined(__WXGTK__) + if ( win && !win->IsTopLevel() ) + { + win = wxGetTopLevelParent(win); + } + + GdkWindow* gdkwin; + + if ( win ) + gdkwin = gtk_widget_get_window(win->GetHandle()); + else + gdkwin = wxGetTopLevelGDK(); + + focus = GDK_WINDOW_XID(gdkwin); + #elif defined(__WXX11__) + if ( !win ) + return; + + focus = (Window)(win->GetHandle()); + #endif // __WXGTK__ + + wxLogTrace("focus", "SetInputFocusToXWindow on Window 0x%ul.", focus); + + XSetInputFocus(m_display, focus, RevertToPointerRoot, CurrentTime); } wxX11Display m_display; diff --git a/tests/menu/menu.cpp b/tests/menu/menu.cpp index ef957e4f18..d9026f4aae 100644 --- a/tests/menu/menu.cpp +++ b/tests/menu/menu.cpp @@ -584,6 +584,10 @@ void MenuTestCase::Events() // Invoke the accelerator. m_frame->Show(); m_frame->SetFocus(); +#ifdef __WXGTK__ + // Without this, test fails when run with other tests under Xvfb. + m_frame->Raise(); +#endif wxYield(); wxUIActionSimulator sim; diff --git a/tests/validators/valnum.cpp b/tests/validators/valnum.cpp index 400011a232..0d4e579c68 100644 --- a/tests/validators/valnum.cpp +++ b/tests/validators/valnum.cpp @@ -211,6 +211,16 @@ void NumValidatorTestCase::Interactive() return; #endif // __WXMSW__ +#ifdef __WXGTK20__ + // Travis CI fails without this! + if ( IsAutomaticTest() ) + { + wxFrame* frame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); + frame->SetFocus(); + frame->Raise(); + } +#endif // __WXGTK20__ + // Set a locale using comma as thousands separator character. wxLocale loc(wxLANGUAGE_ENGLISH_UK, wxLOCALE_DONT_LOAD_DEFAULT);