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
This commit is contained in:
parent
bf99d9ffdd
commit
c8274dbe57
3 changed files with 151 additions and 7 deletions
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue