From 846961bfaec98ba88a2a34c5408bfd22cf109dd3 Mon Sep 17 00:00:00 2001 From: Roman Gilg Date: Thu, 6 Jun 2019 23:17:01 +0200 Subject: [PATCH] Delayed focus updates for Toplevels without surface Summary: XWayland clients have a surface associated with them asynchronously. In this case we don't directly want to set focus on this Toplevel, but wait until the surface is set. This patch aims in conjunction with an unrelated fix to SDL at improving Steam Big Picture Mode in our Wayland session. Test Plan: Steam BPM regains focus on game close. Reviewers: #kwin, zzag Reviewed By: #kwin, zzag Subscribers: anthonyfieroni, davidedmundson, zzag, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D19262 --- input.cpp | 27 +++++++++++++++++++++------ input.h | 8 ++++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/input.cpp b/input.cpp index 5013cb2869..253200795d 100644 --- a/input.cpp +++ b/input.cpp @@ -2249,11 +2249,14 @@ void InputDeviceHandler::init() bool InputDeviceHandler::setAt(Toplevel *toplevel) { - if (m_at == toplevel) { + if (m_at.at == toplevel) { return false; } - auto old = m_at; - m_at = toplevel; + auto old = m_at.at; + disconnect(m_at.surfaceCreatedConnection); + m_at.surfaceCreatedConnection = QMetaObject::Connection(); + + m_at.at = toplevel; emit atChanged(old, toplevel); return true; } @@ -2281,7 +2284,19 @@ void InputDeviceHandler::setInternalWindow(QWindow *window) void InputDeviceHandler::updateFocus() { auto oldFocus = m_focus.focus; - m_focus.focus = m_at; + + if (m_at.at && !m_at.at->surface()) { + // The surface has not yet been created (special XWayland case). + // Therefore listen for its creation. + if (!m_at.surfaceCreatedConnection) { + m_at.surfaceCreatedConnection = connect(m_at.at, &Toplevel::surfaceChanged, + this, &InputDeviceHandler::update); + } + m_focus.focus = nullptr; + } else { + m_focus.focus = m_at.at; + } + focusUpdate(oldFocus, m_focus.focus); } @@ -2290,7 +2305,7 @@ bool InputDeviceHandler::updateDecoration() const auto oldDeco = m_focus.decoration; m_focus.decoration = nullptr; - auto *ac = qobject_cast(m_at); + auto *ac = qobject_cast(m_at.at); if (ac && ac->decoratedClient()) { const QRect clientRect = QRect(ac->clientPos(), ac->clientSize()).translated(ac->pos()); if (!clientRect.contains(position().toPoint())) { @@ -2358,7 +2373,7 @@ void InputDeviceHandler::update() } updateInternalWindow(nullptr); - if (m_focus.focus != m_at) { + if (m_focus.focus != m_at.at) { // focus change updateDecoration(); updateFocus(); diff --git a/input.h b/input.h index 588674d79e..fd1fbdfc21 100644 --- a/input.h +++ b/input.h @@ -389,7 +389,7 @@ public: * @return Toplevel* at device position. **/ QPointer at() const { - return m_at; + return m_at.at; } /** * @brief Toplevel currently having pointer input focus (this might @@ -459,7 +459,11 @@ private: QWindow* findInternalWindow(const QPoint &pos) const; - QPointer m_at; + struct { + QPointer at; + QMetaObject::Connection surfaceCreatedConnection; + } m_at; + struct { QPointer focus; QPointer decoration;