Beginning of global shortcut handling inside KWin
A new GlobalShortcutsManager is introduced which is responsible for holding the registered shortcuts and triggering the matching action. The InputRedirection checks with the GlobalShortcutManager whether a key press event triggers a global shortcut and stops processing the event in that case. At the moment the GlobalShortcutsManager only supports the very basics for KWin internal usage. External applications can not yet make usage of the global shortcut system inside KWin.
This commit is contained in:
parent
95c6e2d7ba
commit
24b23dfc01
5 changed files with 297 additions and 1 deletions
|
@ -264,6 +264,7 @@ set(kwin_KDEINIT_SRCS
|
|||
cursor.cpp
|
||||
tabgroup.cpp
|
||||
focuschain.cpp
|
||||
globalshortcuts.cpp
|
||||
input.cpp
|
||||
netinfo.cpp
|
||||
placement.cpp
|
||||
|
|
158
globalshortcuts.cpp
Normal file
158
globalshortcuts.cpp
Normal file
|
@ -0,0 +1,158 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
// own
|
||||
#include "globalshortcuts.h"
|
||||
// kwin
|
||||
#include <config-kwin.h>
|
||||
// KDE
|
||||
#include <kkeyserver.h>
|
||||
#include <KConfigGroup>
|
||||
// Qt
|
||||
#include <QAction>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
GlobalShortcut::GlobalShortcut(const QKeySequence &shortcut)
|
||||
: m_shortcut(shortcut)
|
||||
{
|
||||
}
|
||||
|
||||
GlobalShortcut::~GlobalShortcut()
|
||||
{
|
||||
}
|
||||
|
||||
InternalGlobalShortcut::InternalGlobalShortcut(const QKeySequence &shortcut, QAction *action)
|
||||
: GlobalShortcut(shortcut)
|
||||
, m_action(action)
|
||||
{
|
||||
}
|
||||
|
||||
InternalGlobalShortcut::~InternalGlobalShortcut()
|
||||
{
|
||||
}
|
||||
|
||||
void InternalGlobalShortcut::invoke()
|
||||
{
|
||||
// using QueuedConnection so that we finish the even processing first
|
||||
QMetaObject::invokeMethod(m_action, "trigger", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
GlobalShortcutsManager::GlobalShortcutsManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_config(KSharedConfig::openConfig(QStringLiteral("kglobalshortcutsrc"), KConfig::SimpleConfig))
|
||||
{
|
||||
}
|
||||
|
||||
GlobalShortcutsManager::~GlobalShortcutsManager()
|
||||
{
|
||||
for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); ++it) {
|
||||
qDeleteAll((*it));
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalShortcutsManager::objectDeleted(QObject *object)
|
||||
{
|
||||
for (auto it = m_shortcuts.begin(); it != m_shortcuts.end(); ++it) {
|
||||
auto list = (*it);
|
||||
for (auto it2 = list.begin(); it2 != list.end(); ++it2) {
|
||||
if (InternalGlobalShortcut *shortcut = dynamic_cast<InternalGlobalShortcut*>((*it2))) {
|
||||
if (shortcut->action() == object) {
|
||||
delete *it2;
|
||||
it2 = list.erase(it2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalShortcutsManager::registerShortcut(QAction *action, const QKeySequence &shortcut)
|
||||
{
|
||||
QKeySequence s = getShortcutForAction(KWIN_NAME, action->objectName(), shortcut);
|
||||
if (s.isEmpty()) {
|
||||
// TODO: insert into a list of empty shortcuts to react on changes
|
||||
return;
|
||||
}
|
||||
int keys = s[0];
|
||||
Qt::KeyboardModifiers mods = Qt::NoModifier;
|
||||
if (keys & Qt::ShiftModifier) {
|
||||
mods |= Qt::ShiftModifier;
|
||||
}
|
||||
if (keys & Qt::ControlModifier) {
|
||||
mods |= Qt::ControlModifier;
|
||||
}
|
||||
if (keys & Qt::AltModifier) {
|
||||
mods |= Qt::AltModifier;
|
||||
}
|
||||
if (keys & Qt::MetaModifier) {
|
||||
mods |= Qt::MetaModifier;
|
||||
}
|
||||
int keysym = 0;
|
||||
if (!KKeyServer::keyQtToSymX(keys, &keysym)) {
|
||||
return;
|
||||
}
|
||||
GlobalShortcut *cut = new InternalGlobalShortcut(s, action);
|
||||
auto it = m_shortcuts.find(mods);
|
||||
if (it != m_shortcuts.end()) {
|
||||
// TODO: check if key already exists?
|
||||
(*it).insert(keysym, cut);
|
||||
} else {
|
||||
QHash<uint32_t, GlobalShortcut*> shortcuts;
|
||||
shortcuts.insert(keysym, cut);
|
||||
m_shortcuts.insert(mods, shortcuts);
|
||||
}
|
||||
connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
|
||||
}
|
||||
|
||||
QKeySequence GlobalShortcutsManager::getShortcutForAction(const QString &componentName, const QString &actionName, const QKeySequence &defaultShortcut)
|
||||
{
|
||||
if (!m_config->hasGroup(componentName)) {
|
||||
return defaultShortcut;
|
||||
}
|
||||
KConfigGroup group = m_config->group(componentName);
|
||||
if (!group.hasKey(actionName)) {
|
||||
return defaultShortcut;
|
||||
}
|
||||
QStringList parts = group.readEntry(actionName, QStringList());
|
||||
// must consist of three parts
|
||||
if (parts.size() != 3) {
|
||||
return defaultShortcut;
|
||||
}
|
||||
if (parts.first() == "none") {
|
||||
return defaultShortcut;
|
||||
}
|
||||
return QKeySequence(parts.first());
|
||||
}
|
||||
|
||||
bool GlobalShortcutsManager::processKey(Qt::KeyboardModifiers mods, uint32_t key)
|
||||
{
|
||||
auto it = m_shortcuts.find(mods);
|
||||
if (it == m_shortcuts.end()) {
|
||||
return false;
|
||||
}
|
||||
auto it2 = (*it).find(key);
|
||||
if (it2 == (*it).end()) {
|
||||
return false;
|
||||
}
|
||||
it2.value()->invoke();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
118
globalshortcuts.h
Normal file
118
globalshortcuts.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#ifndef KWIN_GLOBALSHORTCUTS_H
|
||||
#define KWIN_GLOBALSHORTCUTS_H
|
||||
// KDE
|
||||
#include <KSharedConfig>
|
||||
// Qt
|
||||
#include <QKeySequence>
|
||||
|
||||
class QAction;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class GlobalShortcut;
|
||||
|
||||
/**
|
||||
* @brief Manager for the global shortcut system inside KWin.
|
||||
*
|
||||
* This class is responsible for holding all the global shortcuts and to process a key press event.
|
||||
* That is trigger a shortcut if there is a match.
|
||||
*
|
||||
* For internal shortcut handling (those which are delivered inside KWin) QActions are used and
|
||||
* triggered if the shortcut matches. For external shortcut handling a DBus interface is used.
|
||||
**/
|
||||
class GlobalShortcutsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit GlobalShortcutsManager(QObject *parent = nullptr);
|
||||
virtual ~GlobalShortcutsManager();
|
||||
/**
|
||||
* @brief Registers an internal global shortcut
|
||||
*
|
||||
* @param action The action to trigger if the shortcut is pressed
|
||||
* @param shortcut The key sequence which triggers this shortcut
|
||||
*/
|
||||
void registerShortcut(QAction *action, const QKeySequence &shortcut);
|
||||
|
||||
/**
|
||||
* @brief Processes a key event to decide whether a shortcut needs to be triggered.
|
||||
*
|
||||
* If a shortcut triggered this method returns @c true to indicate to the caller that the event
|
||||
* should not be further processed. If there is no shortcut which triggered for the key, then
|
||||
* @c false is returned.
|
||||
*
|
||||
* @param modifiers The current hold modifiers
|
||||
* @param key The keysymbol which has been pressed
|
||||
* @return @c true if a shortcut triggered, @c false otherwise
|
||||
*/
|
||||
bool processKey(Qt::KeyboardModifiers modifiers, uint32_t key);
|
||||
private:
|
||||
void objectDeleted(QObject *object);
|
||||
QKeySequence getShortcutForAction(const QString &componentName, const QString &actionName, const QKeySequence &defaultShortcut);
|
||||
QHash<Qt::KeyboardModifiers, QHash<uint32_t, GlobalShortcut*> > m_shortcuts;
|
||||
KSharedConfigPtr m_config;
|
||||
};
|
||||
|
||||
class GlobalShortcut
|
||||
{
|
||||
public:
|
||||
virtual ~GlobalShortcut();
|
||||
|
||||
const QKeySequence &shortcut() const;
|
||||
virtual void invoke() = 0;
|
||||
|
||||
protected:
|
||||
GlobalShortcut(const QKeySequence &shortcut);
|
||||
|
||||
private:
|
||||
QKeySequence m_shortcut;
|
||||
};
|
||||
|
||||
class InternalGlobalShortcut : public GlobalShortcut
|
||||
{
|
||||
public:
|
||||
InternalGlobalShortcut(const QKeySequence &shortcut, QAction *action);
|
||||
virtual ~InternalGlobalShortcut();
|
||||
|
||||
void invoke() override;
|
||||
|
||||
QAction *action() const;
|
||||
private:
|
||||
QAction *m_action;
|
||||
};
|
||||
|
||||
inline
|
||||
QAction *InternalGlobalShortcut::action() const
|
||||
{
|
||||
return m_action;
|
||||
}
|
||||
|
||||
inline
|
||||
const QKeySequence &GlobalShortcut::shortcut() const
|
||||
{
|
||||
return m_shortcut;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
13
input.cpp
13
input.cpp
|
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include "effects.h"
|
||||
#include "globalshortcuts.h"
|
||||
#include "unmanaged.h"
|
||||
#include "workspace.h"
|
||||
// KDE
|
||||
|
@ -157,6 +158,7 @@ InputRedirection::InputRedirection(QObject *parent)
|
|||
, m_xkb(new Xkb())
|
||||
#endif
|
||||
, m_pointerWindow()
|
||||
, m_shortcuts(new GlobalShortcutsManager(this))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -255,7 +257,6 @@ void InputRedirection::processKeyboardKey(uint32_t key, InputRedirection::Keyboa
|
|||
Q_UNUSED(time)
|
||||
#if HAVE_XKB
|
||||
m_xkb->updateKey(key, state);
|
||||
// TODO: process global shortcuts
|
||||
// TODO: pass to internal parts of KWin
|
||||
if (effects && static_cast< EffectsHandlerImpl* >(effects)->hasKeyboardGrab()) {
|
||||
const xkb_keysym_t keysym = m_xkb->toKeysym(key);
|
||||
|
@ -272,6 +273,12 @@ void InputRedirection::processKeyboardKey(uint32_t key, InputRedirection::Keyboa
|
|||
c->keyPressEvent(m_xkb->toQtKey(m_xkb->toKeysym(key)));
|
||||
return;
|
||||
}
|
||||
// process global shortcuts
|
||||
if (state == KeyboardKeyPressed) {
|
||||
if (m_shortcuts->processKey(m_xkb->modifiers(), m_xkb->toKeysym(key))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// check unmanaged
|
||||
if (!workspace()->unmanagedList().isEmpty()) {
|
||||
|
@ -420,5 +427,9 @@ Qt::KeyboardModifiers InputRedirection::keyboardModifiers() const
|
|||
#endif
|
||||
}
|
||||
|
||||
void InputRedirection::registerShortcut(const QKeySequence &shortcut, QAction *action)
|
||||
{
|
||||
m_shortcuts->registerShortcut(action, shortcut);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
8
input.h
8
input.h
|
@ -30,8 +30,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <xkbcommon/xkbcommon.h>
|
||||
#endif
|
||||
|
||||
class QAction;
|
||||
class QKeySequence;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
class GlobalShortcutsManager;
|
||||
class Toplevel;
|
||||
class Xkb;
|
||||
|
||||
|
@ -77,6 +81,8 @@ public:
|
|||
Qt::MouseButtons qtButtonStates() const;
|
||||
Qt::KeyboardModifiers keyboardModifiers() const;
|
||||
|
||||
void registerShortcut(const QKeySequence &shortcut, QAction *action);
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
@ -144,6 +150,8 @@ private:
|
|||
*/
|
||||
QWeakPointer<Toplevel> m_pointerWindow;
|
||||
|
||||
GlobalShortcutsManager *m_shortcuts;
|
||||
|
||||
KWIN_SINGLETON(InputRedirection)
|
||||
friend InputRedirection *input();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue