From d7c2185f5c72209bfc820e7cd3c396f31b41fb7b Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Wed, 7 Sep 2022 00:50:06 +0400 Subject: [PATCH] Force ActivateWindowDelayed to use xcb_set_input_focus on X11 when activating a parent There's logic in Qt that uses xcb_set_input_focus to focus parent windows as some X11 window managers ignore such focus requests leaving the parent activated, but without input focus. By the time delayed activation happens, current focus window may no more exist and the logic in Qt won't work. X11BypassWindowManagerHint says Qt it should use xcb_set_input_focus on X11 that asks X11 directly to set input focus to that window. --- ui/delayed_activation.cpp | 46 +++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/ui/delayed_activation.cpp b/ui/delayed_activation.cpp index 63e373f..a7ae51e 100644 --- a/ui/delayed_activation.cpp +++ b/ui/delayed_activation.cpp @@ -9,9 +9,11 @@ #include "ui/ui_utility.h" #include "base/call_delayed.h" #include "base/invoke_queued.h" +#include "base/platform/base_platform_info.h" #include -#include +#include +#include namespace Ui { namespace { @@ -40,15 +42,41 @@ void ActivateWindowDelayed(not_null widget) { } else if (std::exchange(Window, widget.get())) { return; } - crl::on_main(Window, [=] { - if (const auto widget = base::take(Window)) { - if (const auto window = widget->window()) { - if (!window->isHidden()) { - window->raise(); - window->activateWindow(); - } - } + const auto focusAncestor = [&] { + const auto focusWindow = QGuiApplication::focusWindow(); + if (!focusWindow || !widget->window()) { + return false; } + const auto handle = widget->window()->windowHandle(); + if (!handle) { + return false; + } + return handle->isAncestorOf(focusWindow); + }(); + crl::on_main(Window, [=] { + const auto widget = base::take(Window); + if (!widget) { + return; + } + const auto window = widget->window(); + if (!window || window->isHidden()) { + return; + } + const auto guard = [&] { + if (!::Platform::IsX11() || !focusAncestor) { + return gsl::finally(Fn([] {})); + } + const auto handle = window->windowHandle(); + if (!(handle->flags() & Qt::X11BypassWindowManagerHint)) { + handle->setFlag(Qt::X11BypassWindowManagerHint); + return gsl::finally(Fn([&] { + handle->setFlag(Qt::X11BypassWindowManagerHint, false); + })); + } + return gsl::finally(Fn([] {})); + }(); + window->raise(); + window->activateWindow(); }); }