Commit 8e1018de authored by Andrey Butirsky's avatar Andrey Butirsky Committed by David Edmundson
Browse files

save default keyboard layout

Implemented for Global, Virtual Desktop and Application layout policies.
Not implemented for Window policy due separate windows do not preserve
their IDs between sessions (still could be implemented the same way as for Application policy).

Layout saving/restoring happens on Session save/load.
Covered by unit tests
parent cf271288
......@@ -161,13 +161,16 @@ void KeyboardLayout::reconfigure()
{
if (m_config) {
m_config->reparseConfiguration();
const QString policyKey = m_config->group(QStringLiteral("Layout")).readEntry("SwitchMode", QStringLiteral("Global"));
const KConfigGroup layoutGroup = m_config->group("Layout");
const QString policyKey = layoutGroup.readEntry("SwitchMode", QStringLiteral("Global"));
m_xkb->reconfigure();
if (!m_policy || m_policy->name() != policyKey) {
delete m_policy;
m_policy = KeyboardLayoutSwitching::Policy::create(m_xkb, this, policyKey);
m_policy = KeyboardLayoutSwitching::Policy::create(m_xkb, this, layoutGroup, policyKey);
}
} else {
m_xkb->reconfigure();
}
m_xkb->reconfigure();
resetLayout();
}
......@@ -178,9 +181,9 @@ void KeyboardLayout::resetLayout()
updateNotifier();
reinitNotifierMenu();
loadShortcuts();
emit layoutsReconfigured();
initDBusInterface();
emit layoutsReconfigured();
}
void KeyboardLayout::loadShortcuts()
......
......@@ -31,8 +31,9 @@ namespace KWin
namespace KeyboardLayoutSwitching
{
Policy::Policy(Xkb *xkb, KeyboardLayout *layout)
Policy::Policy(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config)
: QObject(layout)
, m_config(config)
, m_xkb(xkb)
, m_layout(layout)
{
......@@ -52,31 +53,108 @@ quint32 Policy::layout() const
return m_xkb->currentLayout();
}
Policy *Policy::create(Xkb *xkb, KeyboardLayout *layout, const QString &policy)
Policy *Policy::create(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config, const QString &policy)
{
if (policy.toLower() == QStringLiteral("desktop")) {
return new VirtualDesktopPolicy(xkb, layout);
return new VirtualDesktopPolicy(xkb, layout, config);
}
if (policy.toLower() == QStringLiteral("window")) {
return new WindowPolicy(xkb, layout);
}
if (policy.toLower() == QStringLiteral("winclass")) {
return new ApplicationPolicy(xkb, layout);
return new ApplicationPolicy(xkb, layout, config);
}
return new GlobalPolicy(xkb, layout);
return new GlobalPolicy(xkb, layout, config);
}
GlobalPolicy::GlobalPolicy(Xkb *xkb, KeyboardLayout *layout)
: Policy(xkb, layout)
const char Policy::defaultLayoutEntryKeyPrefix[] = "LayoutDefault";
const QString Policy::defaultLayoutEntryKey() const
{
return QLatin1String(defaultLayoutEntryKeyPrefix) % name() % QLatin1Char('_');
}
void Policy::clearLayouts()
{
const QStringList layoutEntryList = m_config.keyList().filter(defaultLayoutEntryKeyPrefix);
for (const auto &layoutEntry : layoutEntryList) {
m_config.deleteEntry(layoutEntry);
}
}
const QString GlobalPolicy::defaultLayoutEntryKey() const
{
return QLatin1String(defaultLayoutEntryKeyPrefix) % name();
}
GlobalPolicy::GlobalPolicy(Xkb *xkb, KeyboardLayout *_layout, const KConfigGroup &config)
: Policy(xkb, _layout, config)
{
connect(workspace()->sessionManager(), &SessionManager::prepareSessionSaveRequested, this,
[this] (const QString &name) {
Q_UNUSED(name)
clearLayouts();
if (layout()) {
m_config.writeEntry(defaultLayoutEntryKey(), layout());
}
}
);
connect(workspace()->sessionManager(), &SessionManager::loadSessionRequested, this,
[this, xkb] (const QString &name) {
Q_UNUSED(name)
if (xkb->numberOfLayouts() > 1) {
xkb->switchToLayout(m_config.readEntry(defaultLayoutEntryKey(), 0));
}
}
);
}
GlobalPolicy::~GlobalPolicy() = default;
VirtualDesktopPolicy::VirtualDesktopPolicy(Xkb *xkb, KeyboardLayout *layout)
: Policy(xkb, layout)
VirtualDesktopPolicy::VirtualDesktopPolicy(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config)
: Policy(xkb, layout, config)
{
connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, this, &VirtualDesktopPolicy::desktopChanged);
connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged,
this, &VirtualDesktopPolicy::desktopChanged);
connect(workspace()->sessionManager(), &SessionManager::prepareSessionSaveRequested, this,
[this] (const QString &name) {
Q_UNUSED(name)
clearLayouts();
for (auto i = m_layouts.constBegin(); i != m_layouts.constEnd(); ++i) {
if (const uint layout = *i) {
m_config.writeEntry(
defaultLayoutEntryKey() %
QLatin1String( QByteArray::number(i.key()->x11DesktopNumber()) ),
layout);
}
}
}
);
connect(workspace()->sessionManager(), &SessionManager::loadSessionRequested, this,
[this, xkb] (const QString &name) {
Q_UNUSED(name)
if (xkb->numberOfLayouts() > 1) {
for (KWin::VirtualDesktop* const desktop : VirtualDesktopManager::self()->desktops()) {
const uint layout = m_config.readEntry(
defaultLayoutEntryKey() %
QLatin1String( QByteArray::number(desktop->x11DesktopNumber()) ),
0u);
if (layout) {
m_layouts.insert(desktop, layout);
connect(desktop, &VirtualDesktop::aboutToBeDestroyed, this,
[this, desktop] {
m_layouts.remove(desktop);
}
);
}
}
desktopChanged();
}
}
);
}
VirtualDesktopPolicy::~VirtualDesktopPolicy() = default;
......@@ -185,10 +263,44 @@ void WindowPolicy::layoutChanged()
}
}
ApplicationPolicy::ApplicationPolicy(KWin::Xkb* xkb, KWin::KeyboardLayout* layout)
: Policy(xkb, layout)
ApplicationPolicy::ApplicationPolicy(KWin::Xkb* xkb, KWin::KeyboardLayout* layout, const KConfigGroup &config)
: Policy(xkb, layout, config)
{
connect(workspace(), &Workspace::clientActivated, this, &ApplicationPolicy::clientActivated);
connect(workspace()->sessionManager(), &SessionManager::prepareSessionSaveRequested, this,
[this] (const QString &name) {
Q_UNUSED(name)
clearLayouts();
for (auto i = m_layouts.constBegin(); i != m_layouts.constEnd(); ++i) {
if (const uint layout = *i) {
const QByteArray desktopFileName = i.key()->desktopFileName();
if (!desktopFileName.isEmpty()) {
m_config.writeEntry(
defaultLayoutEntryKey() % QLatin1String(desktopFileName),
layout);
}
}
}
}
);
connect(workspace()->sessionManager(), &SessionManager::loadSessionRequested, this,
[this, xkb] (const QString &name) {
Q_UNUSED(name)
if (xkb->numberOfLayouts() > 1) {
const QString keyPrefix = defaultLayoutEntryKey();
const QStringList keyList = m_config.keyList().filter(keyPrefix);
for (const QString& key : keyList) {
m_layoutsRestored.insert(
key.midRef(keyPrefix.size()).toLatin1(),
m_config.readEntry(key, 0));
}
}
m_layoutsRestored.squeeze();
}
);
}
ApplicationPolicy::~ApplicationPolicy()
......@@ -204,14 +316,22 @@ void ApplicationPolicy::clientActivated(AbstractClient *c)
if (c->isDesktop() || c->isDock()) {
return;
}
quint32 layout = 0;
for (auto it = m_layouts.constBegin(); it != m_layouts.constEnd(); it++) {
auto it = m_layouts.constFind(c);
if(it != m_layouts.constEnd()) {
setLayout(it.value());
return;
};
for (it = m_layouts.constBegin(); it != m_layouts.constEnd(); it++) {
if (AbstractClient::belongToSameApplication(c, it.key())) {
layout = it.value();
break;
setLayout(it.value());
layoutChanged();
return;
}
}
setLayout(layout);
setLayout( m_layoutsRestored.take(c->desktopFileName()) );
if (layout()) {
layoutChanged();
}
}
void ApplicationPolicy::clearCache()
......
......@@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QObject>
#include <QHash>
#include <KConfigGroup>
namespace KWin
{
......@@ -42,16 +43,22 @@ public:
virtual QString name() const = 0;
static Policy *create(Xkb *xkb, KeyboardLayout *layout, const QString &policy);
static Policy *create(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config, const QString &policy);
protected:
explicit Policy(Xkb *xkb, KeyboardLayout *layout);
explicit Policy(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config = KConfigGroup());
virtual void clearCache() = 0;
virtual void layoutChanged() = 0;
void setLayout(quint32 layout);
quint32 layout() const;
KConfigGroup m_config;
virtual const QString defaultLayoutEntryKey() const;
void clearLayouts();
static const char defaultLayoutEntryKeyPrefix[];
private:
Xkb *m_xkb;
KeyboardLayout *m_layout;
......@@ -61,7 +68,7 @@ class GlobalPolicy : public Policy
{
Q_OBJECT
public:
explicit GlobalPolicy(Xkb *xkb, KeyboardLayout *layout);
explicit GlobalPolicy(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config);
~GlobalPolicy() override;
QString name() const override {
......@@ -71,13 +78,16 @@ public:
protected:
void clearCache() override {}
void layoutChanged() override {}
private:
const QString defaultLayoutEntryKey() const override;
};
class VirtualDesktopPolicy : public Policy
{
Q_OBJECT
public:
explicit VirtualDesktopPolicy(Xkb *xkb, KeyboardLayout *layout);
explicit VirtualDesktopPolicy(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config);
~VirtualDesktopPolicy() override;
QString name() const override {
......@@ -116,7 +126,7 @@ class ApplicationPolicy : public Policy
{
Q_OBJECT
public:
explicit ApplicationPolicy(Xkb *xkb, KeyboardLayout *layout);
explicit ApplicationPolicy(Xkb *xkb, KeyboardLayout *layout, const KConfigGroup &config);
~ApplicationPolicy() override;
QString name() const override {
......@@ -130,6 +140,7 @@ protected:
private:
void clientActivated(AbstractClient *c);
QHash<AbstractClient*, quint32> m_layouts;
QHash<QByteArray, quint32> m_layoutsRestored;
};
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment