Add support for keyboard layout switching policy "winclass"
Summary: This is quite similar to the policy "window" - the main difference is that windows from the same application share the layout. So only switching to a window from another application changes the layout. This change is the last policy to add for support of all the policies we have on X11. Reviewers: #kwin, #plasma Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D5365
This commit is contained in:
parent
c8274dbe57
commit
b132fe7c24
3 changed files with 155 additions and 0 deletions
|
@ -59,6 +59,7 @@ private Q_SLOTS:
|
|||
void testDBusServiceExport();
|
||||
void testVirtualDesktopPolicy();
|
||||
void testWindowPolicy();
|
||||
void testApplicationPolicy();
|
||||
|
||||
private:
|
||||
void reconfigureLayouts();
|
||||
|
@ -394,5 +395,67 @@ void KeyboardLayoutTest::testWindowPolicy()
|
|||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
|
||||
}
|
||||
|
||||
void KeyboardLayoutTest::testApplicationPolicy()
|
||||
{
|
||||
KConfigGroup layoutGroup = kwinApp()->kxkbConfig()->group("Layout");
|
||||
layoutGroup.writeEntry("LayoutList", QStringLiteral("us,de,de(neo)"));
|
||||
layoutGroup.writeEntry("SwitchMode", QStringLiteral("WinClass"));
|
||||
layoutGroup.sync();
|
||||
reconfigureLayouts();
|
||||
auto xkb = input()->keyboard()->xkb();
|
||||
QTRY_COMPARE(xkb->numberOfLayouts(), 3u);
|
||||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("English (US)"));
|
||||
|
||||
// create a window
|
||||
using namespace KWayland::Client;
|
||||
QScopedPointer<Surface> surface(Test::createSurface());
|
||||
QScopedPointer<ShellSurface> shellSurface(Test::createShellSurface(surface.data()));
|
||||
auto c1 = Test::renderAndWaitForShown(surface.data(), QSize(100, 100), Qt::blue);
|
||||
QVERIFY(c1);
|
||||
|
||||
// now switch layout
|
||||
auto changeLayout = [] (const QString &layoutName) {
|
||||
QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.keyboard"), QStringLiteral("/Layouts"), QStringLiteral("org.kde.KeyboardLayouts"), QStringLiteral("setLayout"));
|
||||
msg << layoutName;
|
||||
return QDBusConnection::sessionBus().asyncCall(msg);
|
||||
};
|
||||
LayoutChangedSignalWrapper wrapper;
|
||||
QSignalSpy layoutChangedSpy(&wrapper, &LayoutChangedSignalWrapper::layoutChanged);
|
||||
QVERIFY(layoutChangedSpy.isValid());
|
||||
auto reply = changeLayout(QStringLiteral("German"));
|
||||
QVERIFY(layoutChangedSpy.wait());
|
||||
QCOMPARE(layoutChangedSpy.count(), 1);
|
||||
reply.waitForFinished();
|
||||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German"));
|
||||
|
||||
// create a second window
|
||||
QScopedPointer<Surface> surface2(Test::createSurface());
|
||||
QScopedPointer<ShellSurface> shellSurface2(Test::createShellSurface(surface2.data()));
|
||||
auto c2 = Test::renderAndWaitForShown(surface2.data(), QSize(100, 100), Qt::red);
|
||||
QVERIFY(c2);
|
||||
// it is the same application and should not switch the layout
|
||||
QVERIFY(!layoutChangedSpy.wait());
|
||||
QCOMPARE(layoutChangedSpy.count(), 1);
|
||||
// now change to another layout
|
||||
reply = changeLayout(QStringLiteral("German (Neo 2)"));
|
||||
QVERIFY(layoutChangedSpy.wait());
|
||||
QCOMPARE(layoutChangedSpy.count(), 2);
|
||||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
|
||||
|
||||
// activate other window
|
||||
workspace()->activateClient(c1);
|
||||
QVERIFY(!layoutChangedSpy.wait());
|
||||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
|
||||
workspace()->activateClient(c2);
|
||||
QVERIFY(!layoutChangedSpy.wait());
|
||||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
|
||||
|
||||
shellSurface2.reset();
|
||||
surface2.reset();
|
||||
QVERIFY(Test::waitForWindowDestroyed(c2));
|
||||
QVERIFY(!layoutChangedSpy.wait());
|
||||
QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
|
||||
}
|
||||
|
||||
WAYLANDTEST_MAIN(KeyboardLayoutTest)
|
||||
#include "keyboard_layout_test.moc"
|
||||
|
|
|
@ -60,6 +60,9 @@ Policy *Policy::create(Xkb *xkb, KeyboardLayout *layout, const QString &policy)
|
|||
if (policy.toLower() == QStringLiteral("window")) {
|
||||
return new WindowPolicy(xkb, layout);
|
||||
}
|
||||
if (policy.toLower() == QStringLiteral("winclass")) {
|
||||
return new ApplicationPolicy(xkb, layout);
|
||||
}
|
||||
return new GlobalPolicy(xkb, layout);
|
||||
}
|
||||
|
||||
|
@ -182,5 +185,74 @@ void WindowPolicy::layoutChanged()
|
|||
}
|
||||
}
|
||||
|
||||
ApplicationPolicy::ApplicationPolicy(KWin::Xkb* xkb, KWin::KeyboardLayout* layout)
|
||||
: Policy(xkb, layout)
|
||||
{
|
||||
connect(workspace(), &Workspace::clientActivated, this, &ApplicationPolicy::clientActivated);
|
||||
}
|
||||
|
||||
ApplicationPolicy::~ApplicationPolicy()
|
||||
{
|
||||
}
|
||||
|
||||
void ApplicationPolicy::clientActivated(AbstractClient *c)
|
||||
{
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
// ignore some special types
|
||||
if (c->isDesktop() || c->isDock()) {
|
||||
return;
|
||||
}
|
||||
quint32 layout = 0;
|
||||
for (auto it = m_layouts.constBegin(); it != m_layouts.constEnd(); it++) {
|
||||
if (AbstractClient::belongToSameApplication(c, it.key())) {
|
||||
layout = it.value();
|
||||
break;
|
||||
}
|
||||
}
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void ApplicationPolicy::clearCache()
|
||||
{
|
||||
m_layouts.clear();
|
||||
}
|
||||
|
||||
void ApplicationPolicy::layoutChanged()
|
||||
{
|
||||
auto c = workspace()->activeClient();
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
// ignore some special types
|
||||
if (c->isDesktop() || c->isDock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = m_layouts.find(c);
|
||||
const auto l = layout();
|
||||
if (it == m_layouts.constEnd()) {
|
||||
m_layouts.insert(c, l);
|
||||
connect(c, &AbstractClient::windowClosed, this,
|
||||
[this, c] {
|
||||
m_layouts.remove(c);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
if (it.value() == l) {
|
||||
return;
|
||||
}
|
||||
it.value() = l;
|
||||
}
|
||||
// update all layouts for the application
|
||||
for (it = m_layouts.begin(); it != m_layouts.end(); it++) {
|
||||
if (!AbstractClient::belongToSameApplication(it.key(), c)) {
|
||||
continue;
|
||||
}
|
||||
it.value() = l;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,6 +112,26 @@ private:
|
|||
QHash<AbstractClient*, quint32> m_layouts;
|
||||
};
|
||||
|
||||
class ApplicationPolicy : public Policy
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ApplicationPolicy(Xkb *xkb, KeyboardLayout *layout);
|
||||
~ApplicationPolicy() override;
|
||||
|
||||
QString name() const override {
|
||||
return QStringLiteral("WinClass");
|
||||
}
|
||||
|
||||
protected:
|
||||
void clearCache() override;
|
||||
void layoutChanged() override;
|
||||
|
||||
private:
|
||||
void clientActivated(AbstractClient *c);
|
||||
QHash<AbstractClient*, quint32> m_layouts;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue