From 7adf69decec2c20c792c71552770bc51d7821b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Sun, 26 Jun 2016 15:57:38 +0200 Subject: [PATCH] Update Keyboard focus when the Surface of the active client changes Summary: For XWayland windows the window might be activated before the Wayland Surface is set for it. Thus the keyboard focus is not passed to the window. Only on the next activate after the window got created the window got keyboard focus. This change addresses this problem by emitting a signal from Toplevel when the surface changes. The KeyboardInput listens to this signal for the active client and updates keyboard focus again if the surface changes. Thus keyboard focus is properly passed to XWayland windows. Test Plan: Test case which creates an X11 window is adjusted to verify the condition. Reviewers: #plasma_on_wayland, #kwin Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2009 --- autotests/wayland/plasmawindow_test.cpp | 10 ++++++++++ keyboard_input.cpp | 12 +++++++++++- keyboard_input.h | 1 + toplevel.cpp | 1 + toplevel.h | 5 +++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/autotests/wayland/plasmawindow_test.cpp b/autotests/wayland/plasmawindow_test.cpp index cd58d0e329..45f02d7eed 100644 --- a/autotests/wayland/plasmawindow_test.cpp +++ b/autotests/wayland/plasmawindow_test.cpp @@ -36,6 +36,7 @@ along with this program. If not, see . #include #include #include +#include //screenlocker #include @@ -211,6 +212,15 @@ void PlasmaWindowTest::testCreateDestroyX11PlasmaWindow() QCOMPARE(client->window(), w); QVERIFY(client->isDecorated()); QVERIFY(client->isActive()); + // verify that it gets the keyboard focus + QVERIFY(!client->surface()); + // we don't have a surface yet, so focused keyboard surface if set is not ours + QVERIFY(!waylandServer()->seat()->focusedKeyboardSurface()); + QSignalSpy surfaceChangedSpy(client, &Toplevel::surfaceChanged); + QVERIFY(surfaceChangedSpy.isValid()); + QVERIFY(surfaceChangedSpy.wait()); + QVERIFY(client->surface()); + QCOMPARE(waylandServer()->seat()->focusedKeyboardSurface(), client->surface()); // now that should also give it to us on client side QVERIFY(plasmaWindowCreatedSpy.wait()); diff --git a/keyboard_input.cpp b/keyboard_input.cpp index cf18a61370..98a0aba19d 100644 --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -374,7 +374,17 @@ void KeyboardInputRedirection::init() connect(workspace(), &QObject::destroyed, this, [this] { m_inited = false; }); connect(waylandServer(), &QObject::destroyed, this, [this] { m_inited = false; }); - connect(workspace(), &Workspace::clientActivated, this, &KeyboardInputRedirection::update); + connect(workspace(), &Workspace::clientActivated, this, + [this] { + disconnect(m_activeClientSurfaceChangedConnection); + if (auto c = workspace()->activeClient()) { + m_activeClientSurfaceChangedConnection = connect(c, &Toplevel::surfaceChanged, this, &KeyboardInputRedirection::update); + } else { + m_activeClientSurfaceChangedConnection = QMetaObject::Connection(); + } + update(); + } + ); if (waylandServer()->hasScreenLockerIntegration()) { connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &KeyboardInputRedirection::update); } diff --git a/keyboard_input.h b/keyboard_input.h index 8bac81cb92..1e79e9b108 100644 --- a/keyboard_input.h +++ b/keyboard_input.h @@ -126,6 +126,7 @@ private: bool m_inited = false; QScopedPointer m_xkb; QHash m_repeatTimers; + QMetaObject::Connection m_activeClientSurfaceChangedConnection; }; inline diff --git a/toplevel.cpp b/toplevel.cpp index 2a0e8bca01..1407aecb73 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -478,6 +478,7 @@ void Toplevel::setSurface(KWayland::Server::SurfaceInterface *surface) m_surface = nullptr; } ); + emit surfaceChanged(); } void Toplevel::addDamage(const QRegion &damage) diff --git a/toplevel.h b/toplevel.h index 57b30837b5..c80ffd3cfb 100644 --- a/toplevel.h +++ b/toplevel.h @@ -450,6 +450,11 @@ Q_SIGNALS: **/ void hasAlphaChanged(); + /** + * Emitted whenever the Surface for this Toplevel changes. + **/ + void surfaceChanged(); + protected Q_SLOTS: /** * Checks whether the screen number for this Toplevel changed and updates if needed.