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
This commit is contained in:
Martin Gräßlin 2016-06-26 15:57:38 +02:00
parent b487da02cd
commit 7adf69dece
5 changed files with 28 additions and 1 deletions

View file

@ -36,6 +36,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <KWayland/Client/shell.h>
#include <KWayland/Client/shm_pool.h>
#include <KWayland/Client/surface.h>
#include <KWayland/Server/seat_interface.h>
//screenlocker
#include <KScreenLocker/KsldApp>
@ -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());

View file

@ -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);
}

View file

@ -126,6 +126,7 @@ private:
bool m_inited = false;
QScopedPointer<Xkb> m_xkb;
QHash<quint32, QTimer*> m_repeatTimers;
QMetaObject::Connection m_activeClientSurfaceChangedConnection;
};
inline

View file

@ -478,6 +478,7 @@ void Toplevel::setSurface(KWayland::Server::SurfaceInterface *surface)
m_surface = nullptr;
}
);
emit surfaceChanged();
}
void Toplevel::addDamage(const QRegion &damage)

View file

@ -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.