2013-07-10 09:41:16 +00:00
|
|
|
/********************************************************************
|
|
|
|
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>
|
2015-06-26 08:51:11 +00:00
|
|
|
#include "main.h"
|
|
|
|
#include "utils.h"
|
2013-07-10 09:41:16 +00:00
|
|
|
// KDE
|
|
|
|
#include <kkeyserver.h>
|
|
|
|
#include <KConfigGroup>
|
2015-06-26 08:51:11 +00:00
|
|
|
#include <KGlobalAccel/private/kglobalacceld.h>
|
2015-06-26 11:47:08 +00:00
|
|
|
#include <KGlobalAccel/private/kglobalaccel_interface.h>
|
2013-07-10 09:41:16 +00:00
|
|
|
// Qt
|
|
|
|
#include <QAction>
|
|
|
|
|
|
|
|
namespace KWin
|
|
|
|
{
|
|
|
|
|
|
|
|
GlobalShortcut::GlobalShortcut(const QKeySequence &shortcut)
|
|
|
|
: m_shortcut(shortcut)
|
2013-07-14 20:52:58 +00:00
|
|
|
, m_pointerModifiers(Qt::NoModifier)
|
|
|
|
, m_pointerButtons(Qt::NoButton)
|
2013-07-15 09:26:56 +00:00
|
|
|
, m_axis(PointerAxisUp)
|
2013-07-14 20:52:58 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalShortcut::GlobalShortcut(Qt::KeyboardModifiers pointerButtonModifiers, Qt::MouseButtons pointerButtons)
|
|
|
|
: m_shortcut(QKeySequence())
|
|
|
|
, m_pointerModifiers(pointerButtonModifiers)
|
|
|
|
, m_pointerButtons(pointerButtons)
|
2013-07-15 09:26:56 +00:00
|
|
|
, m_axis(PointerAxisUp)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalShortcut::GlobalShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis)
|
|
|
|
: m_shortcut(QKeySequence())
|
|
|
|
, m_pointerModifiers(modifiers)
|
|
|
|
, m_pointerButtons(Qt::NoButton)
|
|
|
|
, m_axis(axis)
|
2013-07-10 09:41:16 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalShortcut::~GlobalShortcut()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-16 16:50:10 +00:00
|
|
|
InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers modifiers, const QKeySequence &shortcut, QAction *action)
|
2013-07-10 09:41:16 +00:00
|
|
|
: GlobalShortcut(shortcut)
|
|
|
|
, m_action(action)
|
|
|
|
{
|
2013-07-16 16:50:10 +00:00
|
|
|
Q_UNUSED(modifiers)
|
2013-07-10 09:41:16 +00:00
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers pointerButtonModifiers, Qt::MouseButtons pointerButtons, QAction *action)
|
|
|
|
: GlobalShortcut(pointerButtonModifiers, pointerButtons)
|
|
|
|
, m_action(action)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:26:56 +00:00
|
|
|
InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers axisModifiers, PointerAxisDirection axis, QAction *action)
|
|
|
|
: GlobalShortcut(axisModifiers, axis)
|
|
|
|
, m_action(action)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-10 09:41:16 +00:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
template <typename T>
|
|
|
|
void clearShortcuts(T &shortcuts)
|
2013-07-10 09:41:16 +00:00
|
|
|
{
|
2013-07-14 20:52:58 +00:00
|
|
|
for (auto it = shortcuts.begin(); it != shortcuts.end(); ++it) {
|
2013-07-10 09:41:16 +00:00
|
|
|
qDeleteAll((*it));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
GlobalShortcutsManager::~GlobalShortcutsManager()
|
|
|
|
{
|
|
|
|
clearShortcuts(m_shortcuts);
|
|
|
|
clearShortcuts(m_pointerShortcuts);
|
2013-07-15 09:26:56 +00:00
|
|
|
clearShortcuts(m_axisShortcuts);
|
2013-07-14 20:52:58 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 11:47:08 +00:00
|
|
|
void GlobalShortcutsManager::init()
|
|
|
|
{
|
|
|
|
if (kwinApp()->shouldUseWaylandForCompositing()) {
|
2015-07-06 02:50:20 +00:00
|
|
|
qputenv("KGLOBALACCELD_PLATFORM", QByteArrayLiteral("org.kde.kwin"));
|
2015-06-26 11:47:08 +00:00
|
|
|
m_kglobalAccel = new KGlobalAccelD(this);
|
|
|
|
if (!m_kglobalAccel->init()) {
|
|
|
|
qCDebug(KWIN_CORE) << "Init of kglobalaccel failed";
|
|
|
|
delete m_kglobalAccel;
|
|
|
|
m_kglobalAccel = nullptr;
|
|
|
|
} else {
|
|
|
|
qCDebug(KWIN_CORE) << "KGlobalAcceld inited";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
template <typename T>
|
|
|
|
void handleDestroyedAction(QObject *object, T &shortcuts)
|
2013-07-10 09:41:16 +00:00
|
|
|
{
|
2013-07-14 20:52:58 +00:00
|
|
|
for (auto it = shortcuts.begin(); it != shortcuts.end(); ++it) {
|
2013-07-16 16:13:49 +00:00
|
|
|
auto &list = it.value();
|
|
|
|
auto it2 = list.begin();
|
|
|
|
while (it2 != list.end()) {
|
|
|
|
if (InternalGlobalShortcut *shortcut = dynamic_cast<InternalGlobalShortcut*>(it2.value())) {
|
2013-07-10 09:41:16 +00:00
|
|
|
if (shortcut->action() == object) {
|
|
|
|
it2 = list.erase(it2);
|
2013-07-16 16:13:49 +00:00
|
|
|
delete shortcut;
|
|
|
|
continue;
|
2013-07-10 09:41:16 +00:00
|
|
|
}
|
|
|
|
}
|
2013-07-16 16:13:49 +00:00
|
|
|
++it2;
|
2013-07-10 09:41:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
void GlobalShortcutsManager::objectDeleted(QObject *object)
|
|
|
|
{
|
|
|
|
handleDestroyedAction(object, m_shortcuts);
|
|
|
|
handleDestroyedAction(object, m_pointerShortcuts);
|
2013-07-15 09:26:56 +00:00
|
|
|
handleDestroyedAction(object, m_axisShortcuts);
|
2013-07-14 20:52:58 +00:00
|
|
|
}
|
|
|
|
|
2013-07-16 16:50:10 +00:00
|
|
|
template <typename T, typename R>
|
|
|
|
void addShortcut(T &shortcuts, QAction *action, Qt::KeyboardModifiers modifiers, R value)
|
|
|
|
{
|
|
|
|
GlobalShortcut *cut = new InternalGlobalShortcut(modifiers, value, action);
|
|
|
|
auto it = shortcuts.find(modifiers);
|
|
|
|
if (it != shortcuts.end()) {
|
|
|
|
// TODO: check if shortcut already exists
|
|
|
|
(*it).insert(value, cut);
|
|
|
|
} else {
|
|
|
|
QHash<R, GlobalShortcut*> s;
|
|
|
|
s.insert(value, cut);
|
|
|
|
shortcuts.insert(modifiers, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-10 09:41:16 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-07-16 16:50:10 +00:00
|
|
|
addShortcut(m_shortcuts, action, mods, static_cast<uint32_t>(keysym));
|
2013-07-10 09:41:16 +00:00
|
|
|
connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
void GlobalShortcutsManager::registerPointerShortcut(QAction *action, Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons)
|
|
|
|
{
|
2013-07-16 16:50:10 +00:00
|
|
|
addShortcut(m_pointerShortcuts, action, modifiers, pointerButtons);
|
2013-07-14 20:52:58 +00:00
|
|
|
connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:26:56 +00:00
|
|
|
void GlobalShortcutsManager::registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis)
|
|
|
|
{
|
2013-07-16 16:50:10 +00:00
|
|
|
addShortcut(m_axisShortcuts, action, modifiers, axis);
|
2013-07-15 09:26:56 +00:00
|
|
|
connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
|
|
|
|
}
|
|
|
|
|
2013-07-10 09:41:16 +00:00
|
|
|
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());
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
template <typename T, typename U>
|
|
|
|
bool processShortcut(Qt::KeyboardModifiers mods, T key, U &shortcuts)
|
2013-07-10 09:41:16 +00:00
|
|
|
{
|
2013-07-14 20:52:58 +00:00
|
|
|
auto it = shortcuts.find(mods);
|
|
|
|
if (it == shortcuts.end()) {
|
2013-07-10 09:41:16 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto it2 = (*it).find(key);
|
|
|
|
if (it2 == (*it).end()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
it2.value()->invoke();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-14 20:52:58 +00:00
|
|
|
bool GlobalShortcutsManager::processKey(Qt::KeyboardModifiers mods, uint32_t key)
|
|
|
|
{
|
2015-06-26 11:47:08 +00:00
|
|
|
if (m_kglobalAccelInterface) {
|
|
|
|
bool retVal = false;
|
|
|
|
int keyQt = 0;
|
|
|
|
if (KKeyServer::symXToKeyQt(key, &keyQt)) {
|
|
|
|
QMetaObject::invokeMethod(m_kglobalAccelInterface,
|
|
|
|
"checkKeyPressed",
|
|
|
|
Qt::DirectConnection,
|
|
|
|
Q_RETURN_ARG(bool, retVal),
|
|
|
|
Q_ARG(int, int(mods) | keyQt));
|
|
|
|
if (retVal) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (processShortcut(mods, key, m_shortcuts)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2013-07-14 20:52:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GlobalShortcutsManager::processPointerPressed(Qt::KeyboardModifiers mods, Qt::MouseButtons pointerButtons)
|
|
|
|
{
|
|
|
|
return processShortcut(mods, pointerButtons, m_pointerShortcuts);
|
|
|
|
}
|
|
|
|
|
2013-07-15 09:26:56 +00:00
|
|
|
bool GlobalShortcutsManager::processAxis(Qt::KeyboardModifiers mods, PointerAxisDirection axis)
|
|
|
|
{
|
|
|
|
return processShortcut(mods, axis, m_axisShortcuts);
|
|
|
|
}
|
|
|
|
|
2013-07-10 09:41:16 +00:00
|
|
|
} // namespace
|