aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Gräßlin <[email protected]>2017-04-06 07:13:44 +0200
committerMartin Gräßlin <[email protected]>2017-04-22 08:15:45 +0200
commitc8274dbe5798fa143b5025874de8c899477d8eca (patch)
tree93abb4ad8b32ab98e9206057d4360b1a5492e71f
parentbf99d9ffdd91bc7a99dcace2672af839fa53e5fb (diff)
Add support for keyboard layout switching policy "window"
Summary: This policy stores the layout for each window which becomes active and restores the layout once it gets activated again. Test Plan: Added test case Reviewers: #kwin, #plasma Subscribers: plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D5315
-rw-r--r--autotests/integration/keyboard_layout_test.cpp57
-rw-r--r--keyboard_layout_switching.cpp81
-rw-r--r--keyboard_layout_switching.h20
3 files changed, 151 insertions, 7 deletions
diff --git a/autotests/integration/keyboard_layout_test.cpp b/autotests/integration/keyboard_layout_test.cpp
index db7232c..7ef3796 100644
--- a/autotests/integration/keyboard_layout_test.cpp
+++ b/autotests/integration/keyboard_layout_test.cpp
@@ -21,12 +21,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "keyboard_input.h"
#include "keyboard_layout.h"
#include "platform.h"
+#include "shell_client.h"
#include "virtualdesktops.h"
#include "wayland_server.h"
+#include "workspace.h"
#include <KConfigGroup>
#include <KGlobalAccel>
+#include <KWayland/Client/surface.h>
+#include <KWayland/Client/shell.h>
+
#include <QAction>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
@@ -53,6 +58,7 @@ private Q_SLOTS:
void testPerLayoutShortcut();
void testDBusServiceExport();
void testVirtualDesktopPolicy();
+ void testWindowPolicy();
private:
void reconfigureLayouts();
@@ -67,6 +73,8 @@ void KeyboardLayoutTest::reconfigureLayouts()
void KeyboardLayoutTest::initTestCase()
{
+ qRegisterMetaType<KWin::ShellClient*>();
+ qRegisterMetaType<KWin::AbstractClient*>();
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
QVERIFY(workspaceCreatedSpy.isValid());
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
@@ -82,10 +90,12 @@ void KeyboardLayoutTest::initTestCase()
void KeyboardLayoutTest::init()
{
+ QVERIFY(Test::setupWaylandConnection());
}
void KeyboardLayoutTest::cleanup()
{
+ Test::destroyWaylandConnection();
}
class LayoutChangedSignalWrapper : public QObject
@@ -337,5 +347,52 @@ void KeyboardLayoutTest::testVirtualDesktopPolicy()
}
+void KeyboardLayoutTest::testWindowPolicy()
+{
+ KConfigGroup layoutGroup = kwinApp()->kxkbConfig()->group("Layout");
+ layoutGroup.writeEntry("LayoutList", QStringLiteral("us,de,de(neo)"));
+ layoutGroup.writeEntry("SwitchMode", QStringLiteral("Window"));
+ 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);
+ };
+ auto reply = changeLayout(QStringLiteral("German"));
+ 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);
+ // this should have switched back to English
+ QTRY_COMPARE(xkb->layoutName(), QStringLiteral("English (US)"));
+ // now change to another layout
+ reply = changeLayout(QStringLiteral("German (Neo 2)"));
+ reply.waitForFinished();
+ QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
+
+ // activate other window
+ workspace()->activateClient(c1);
+ QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German"));
+ workspace()->activateClient(c2);
+ QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)"));
+}
+
WAYLANDTEST_MAIN(KeyboardLayoutTest)
#include "keyboard_layout_test.moc"
diff --git a/keyboard_layout_switching.cpp b/keyboard_layout_switching.cpp
index 198da98..c93c624 100644
--- a/keyboard_layout_switching.cpp
+++ b/keyboard_layout_switching.cpp
@@ -19,7 +19,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "keyboard_layout_switching.h"
#include "keyboard_layout.h"
+#include "abstract_client.h"
+#include "deleted.h"
#include "virtualdesktops.h"
+#include "workspace.h"
#include "xkb.h"
namespace KWin
@@ -54,6 +57,9 @@ Policy *Policy::create(Xkb *xkb, KeyboardLayout *layout, const QString &policy)
if (policy.toLower() == QStringLiteral("desktop")) {
return new VirtualDesktopPolicy(xkb, layout);
}
+ if (policy.toLower() == QStringLiteral("window")) {
+ return new WindowPolicy(xkb, layout);
+ }
return new GlobalPolicy(xkb, layout);
}
@@ -77,19 +83,26 @@ void VirtualDesktopPolicy::clearCache()
m_layouts.clear();
}
+namespace {
+template <typename T, typename U>
+quint32 getLayout(const T &layouts, const U &reference)
+{
+ auto it = layouts.constFind(reference);
+ if (it == layouts.constEnd()) {
+ return 0;
+ } else {
+ return it.value();
+ }
+}
+}
+
void VirtualDesktopPolicy::desktopChanged()
{
auto d = VirtualDesktopManager::self()->currentDesktop();
if (!d) {
return;
}
- auto it = m_layouts.constFind(d);
- if (it == m_layouts.constEnd()) {
- // new desktop - go to default;
- setLayout(0);
- } else {
- setLayout(it.value());
- }
+ setLayout(getLayout(m_layouts, d));
}
void VirtualDesktopPolicy::layoutChanged()
@@ -115,5 +128,59 @@ void VirtualDesktopPolicy::layoutChanged()
}
}
+WindowPolicy::WindowPolicy(KWin::Xkb* xkb, KWin::KeyboardLayout* layout)
+ : Policy(xkb, layout)
+{
+ connect(workspace(), &Workspace::clientActivated, this,
+ [this] (AbstractClient *c) {
+ if (!c) {
+ return;
+ }
+ // ignore some special types
+ if (c->isDesktop() || c->isDock()) {
+ return;
+ }
+ setLayout(getLayout(m_layouts, c));
+ }
+ );
+}
+
+WindowPolicy::~WindowPolicy()
+{
+}
+
+void WindowPolicy::clearCache()
+{
+ m_layouts.clear();
+}
+
+void WindowPolicy::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;
+ }
+}
+
}
}
diff --git a/keyboard_layout_switching.h b/keyboard_layout_switching.h
index abb20cd..33cdd8d 100644
--- a/keyboard_layout_switching.h
+++ b/keyboard_layout_switching.h
@@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin
{
+class AbstractClient;
class KeyboardLayout;
class Xkb;
class VirtualDesktop;
@@ -92,6 +93,25 @@ private:
QHash<VirtualDesktop *, quint32> m_layouts;
};
+class WindowPolicy : public Policy
+{
+ Q_OBJECT
+public:
+ explicit WindowPolicy(Xkb *xkb, KeyboardLayout *layout);
+ ~WindowPolicy() override;
+
+ QString name() const override {
+ return QStringLiteral("Window");
+ }
+
+protected:
+ void clearCache() override;
+ void layoutChanged() override;
+
+private:
+ QHash<AbstractClient*, quint32> m_layouts;
+};
+
}
}