diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb42c8283c..e057a600b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -370,6 +370,7 @@ set(kwin_KDEINIT_SRCS
input_event.cpp
input_event_spy.cpp
keyboard_input.cpp
+ keyboard_layout.cpp
pointer_input.cpp
touch_input.cpp
netinfo.cpp
diff --git a/keyboard_input.cpp b/keyboard_input.cpp
index f48deefea9..b7f331cf83 100644
--- a/keyboard_input.cpp
+++ b/keyboard_input.cpp
@@ -20,6 +20,7 @@ along with this program. If not, see .
#include "keyboard_input.h"
#include "input_event.h"
#include "input_event_spy.h"
+#include "keyboard_layout.h"
#include "abstract_client.h"
#include "options.h"
#include "utils.h"
@@ -377,19 +378,6 @@ void Xkb::updateModifiers()
const xkb_layout_index_t layout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE);
if (layout != m_currentLayout) {
m_currentLayout = layout;
- // notify OSD service about the new layout
- if (kwinApp()->usesLibinput()) {
- // only if kwin is in charge of keyboard input
- QDBusMessage msg = QDBusMessage::createMethodCall(
- QStringLiteral("org.kde.plasmashell"),
- QStringLiteral("/org/kde/osdService"),
- QStringLiteral("org.kde.osdService"),
- QStringLiteral("kbdLayoutChanged"));
-
- msg << QString::fromLocal8Bit(xkb_keymap_layout_get_name(m_keymap, layout));
-
- QDBusConnection::sessionBus().asyncCall(msg);
- }
}
if (waylandServer()) {
waylandServer()->seat()->updateKeyboardModifiers(xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_DEPRESSED)),
@@ -399,6 +387,11 @@ void Xkb::updateModifiers()
}
}
+QString Xkb::layoutName() const
+{
+ return QString::fromLocal8Bit(xkb_keymap_layout_get_name(m_keymap, m_currentLayout));
+}
+
void Xkb::updateConsumedModifiers(uint32_t key)
{
Qt::KeyboardModifiers mods = Qt::NoModifier;
@@ -564,6 +557,9 @@ void KeyboardInputRedirection::init()
m_input->installInputEventSpy(new KeyStateChangedSpy(m_input));
m_modifiersChangedSpy = new ModifiersChangedSpy(m_input);
m_input->installInputEventSpy(m_modifiersChangedSpy);
+ m_keyboardLayout = new KeyboardLayout(m_xkb.data());
+ m_keyboardLayout->init();
+ m_input->installInputEventSpy(m_keyboardLayout);
// setup key repeat
m_keyRepeat.timer = new QTimer(this);
@@ -593,33 +589,6 @@ void KeyboardInputRedirection::init()
if (waylandServer()->hasScreenLockerIntegration()) {
connect(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged, this, &KeyboardInputRedirection::update);
}
-
- QAction *switchKeyboardAction = new QAction(this);
- switchKeyboardAction->setObjectName(QStringLiteral("Switch to Next Keyboard Layout"));
- switchKeyboardAction->setProperty("componentName", QStringLiteral("KDE Keyboard Layout Switcher"));
- const QKeySequence sequence = QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_K);
- KGlobalAccel::self()->setDefaultShortcut(switchKeyboardAction, QList({sequence}));
- KGlobalAccel::self()->setShortcut(switchKeyboardAction, QList({sequence}));
- m_input->registerShortcut(sequence, switchKeyboardAction);
- connect(switchKeyboardAction, &QAction::triggered, this,
- [this] {
- m_xkb->switchToNextLayout();
- }
- );
-
- QDBusConnection::sessionBus().connect(QString(),
- QStringLiteral("/Layouts"),
- QStringLiteral("org.kde.keyboard"),
- QStringLiteral("reloadConfig"),
- this,
- SLOT(reconfigure()));
-
- m_xkb->reconfigure();
-}
-
-void KeyboardInputRedirection::reconfigure()
-{
- m_xkb->reconfigure();
}
void KeyboardInputRedirection::update()
@@ -737,6 +706,7 @@ void KeyboardInputRedirection::processModifiers(uint32_t modsDepressed, uint32_t
// TODO: send to proper Client and also send when active Client changes
m_xkb->updateModifiers(modsDepressed, modsLatched, modsLocked, group);
m_modifiersChangedSpy->updateModifiers(modifiers());
+ m_keyboardLayout->checkLayoutChange();
}
void KeyboardInputRedirection::processKeymapChange(int fd, uint32_t size)
@@ -746,6 +716,7 @@ void KeyboardInputRedirection::processKeymapChange(int fd, uint32_t size)
}
// TODO: should we pass the keymap to our Clients? Or only to the currently active one and update
m_xkb->installKeymap(fd, size);
+ m_keyboardLayout->resetLayout();
}
}
diff --git a/keyboard_input.h b/keyboard_input.h
index 729de26ebd..e9a31bc795 100644
--- a/keyboard_input.h
+++ b/keyboard_input.h
@@ -43,6 +43,7 @@ namespace KWin
{
class InputRedirection;
+class KeyboardLayout;
class ModifiersChangedSpy;
class Toplevel;
@@ -94,6 +95,7 @@ public:
quint32 currentLayout() const {
return m_currentLayout;
}
+ QString layoutName() const;
private:
xkb_keymap *loadKeymapFromConfig();
@@ -167,9 +169,6 @@ public:
Q_SIGNALS:
void ledsChanged(KWin::Xkb::LEDs);
-private Q_SLOTS:
- void reconfigure();
-
private:
InputRedirection *m_input;
bool m_inited = false;
@@ -181,6 +180,7 @@ private:
QTimer *timer = nullptr;
} m_keyRepeat;
ModifiersChangedSpy *m_modifiersChangedSpy = nullptr;
+ KeyboardLayout *m_keyboardLayout = nullptr;
};
inline
diff --git a/keyboard_layout.cpp b/keyboard_layout.cpp
new file mode 100644
index 0000000000..e778f3b913
--- /dev/null
+++ b/keyboard_layout.cpp
@@ -0,0 +1,115 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2016, 2017 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#include "keyboard_layout.h"
+#include "keyboard_input.h"
+#include "input_event.h"
+#include "main.h"
+#include "platform.h"
+
+#include
+#include
+#include
+#include
+#include
+
+namespace KWin
+{
+
+KeyboardLayout::KeyboardLayout(Xkb *xkb)
+ : QObject()
+ , m_xkb(xkb)
+{
+}
+
+KeyboardLayout::~KeyboardLayout() = default;
+
+void KeyboardLayout::init()
+{
+ QAction *switchKeyboardAction = new QAction(this);
+ switchKeyboardAction->setObjectName(QStringLiteral("Switch to Next Keyboard Layout"));
+ switchKeyboardAction->setProperty("componentName", QStringLiteral("KDE Keyboard Layout Switcher"));
+ const QKeySequence sequence = QKeySequence(Qt::ALT+Qt::CTRL+Qt::Key_K);
+ KGlobalAccel::self()->setDefaultShortcut(switchKeyboardAction, QList({sequence}));
+ KGlobalAccel::self()->setShortcut(switchKeyboardAction, QList({sequence}));
+ kwinApp()->platform()->setupActionForGlobalAccel(switchKeyboardAction);
+ connect(switchKeyboardAction, &QAction::triggered, this,
+ [this] {
+ m_xkb->switchToNextLayout();
+ checkLayoutChange();
+ }
+ );
+
+ QDBusConnection::sessionBus().connect(QString(),
+ QStringLiteral("/Layouts"),
+ QStringLiteral("org.kde.keyboard"),
+ QStringLiteral("reloadConfig"),
+ this,
+ SLOT(reconfigure()));
+
+ reconfigure();
+}
+
+void KeyboardLayout::reconfigure()
+{
+ m_xkb->reconfigure();
+ resetLayout();
+}
+
+void KeyboardLayout::resetLayout()
+{
+ m_layout = m_xkb->currentLayout();
+}
+
+void KeyboardLayout::keyEvent(KeyEvent *event)
+{
+ if (!event->isAutoRepeat()) {
+ checkLayoutChange();
+ }
+}
+
+void KeyboardLayout::checkLayoutChange()
+{
+ const auto layout = m_xkb->currentLayout();
+ if (m_layout == layout) {
+ return;
+ }
+ m_layout = layout;
+ notifyLayoutChange();
+}
+
+void KeyboardLayout::notifyLayoutChange()
+{
+ // notify OSD service about the new layout
+ if (!kwinApp()->usesLibinput()) {
+ return;
+ }
+ // only if kwin is in charge of keyboard input
+ QDBusMessage msg = QDBusMessage::createMethodCall(
+ QStringLiteral("org.kde.plasmashell"),
+ QStringLiteral("/org/kde/osdService"),
+ QStringLiteral("org.kde.osdService"),
+ QStringLiteral("kbdLayoutChanged"));
+
+ msg << m_xkb->layoutName();
+
+ QDBusConnection::sessionBus().asyncCall(msg);
+}
+
+}
diff --git a/keyboard_layout.h b/keyboard_layout.h
new file mode 100644
index 0000000000..7a71e6e5d2
--- /dev/null
+++ b/keyboard_layout.h
@@ -0,0 +1,56 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2016, 2017 Martin Gräßlin
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*********************************************************************/
+#ifndef KWIN_KEYBOARD_LAYOUT_H
+#define KWIN_KEYBOARD_LAYOUT_H
+
+#include "input_event_spy.h"
+#include
+typedef uint32_t xkb_layout_index_t;
+
+namespace KWin
+{
+class Xkb;
+
+class KeyboardLayout : public QObject, public InputEventSpy
+{
+ Q_OBJECT
+public:
+ explicit KeyboardLayout(Xkb *xkb);
+ ~KeyboardLayout() override;
+
+ void init();
+
+ void checkLayoutChange();
+ void resetLayout();
+
+ void keyEvent(KeyEvent *event) override;
+
+private Q_SLOTS:
+ void reconfigure();
+
+private:
+ void notifyLayoutChange();
+ Xkb *m_xkb;
+ xkb_layout_index_t m_layout = 0;
+};
+
+}
+
+#endif