diff --git a/globalshortcuts.cpp b/globalshortcuts.cpp index 51ca1b8a5..89fc63235 100644 --- a/globalshortcuts.cpp +++ b/globalshortcuts.cpp @@ -1,312 +1,309 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 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 . *********************************************************************/ // own #include "globalshortcuts.h" // kwin #include #include "main.h" #include "gestures.h" #include "utils.h" // KDE #include #include // Qt #include namespace KWin { uint qHash(SwipeDirection direction) { return uint(direction); } GlobalShortcut::GlobalShortcut(const QKeySequence &shortcut) : m_shortcut(shortcut) , m_pointerModifiers(Qt::NoModifier) , m_pointerButtons(Qt::NoButton) - , m_axis(PointerAxisUp) { } GlobalShortcut::GlobalShortcut(Qt::KeyboardModifiers pointerButtonModifiers, Qt::MouseButtons pointerButtons) : m_shortcut(QKeySequence()) , m_pointerModifiers(pointerButtonModifiers) , m_pointerButtons(pointerButtons) - , m_axis(PointerAxisUp) { } -GlobalShortcut::GlobalShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis) +GlobalShortcut::GlobalShortcut(Qt::KeyboardModifiers modifiers) : m_shortcut(QKeySequence()) , m_pointerModifiers(modifiers) , m_pointerButtons(Qt::NoButton) - , m_axis(axis) { } GlobalShortcut::GlobalShortcut(SwipeDirection direction) : m_shortcut(QKeySequence()) , m_pointerModifiers(Qt::NoModifier) , m_pointerButtons(Qt::NoButton) - , m_axis(PointerAxisUp) , m_swipeDirection(direction) { } GlobalShortcut::~GlobalShortcut() { } InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers modifiers, const QKeySequence &shortcut, QAction *action) : GlobalShortcut(shortcut) , m_action(action) { Q_UNUSED(modifiers) } InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers pointerButtonModifiers, Qt::MouseButtons pointerButtons, QAction *action) : GlobalShortcut(pointerButtonModifiers, pointerButtons) , m_action(action) { } InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers axisModifiers, PointerAxisDirection axis, QAction *action) - : GlobalShortcut(axisModifiers, axis) + : GlobalShortcut(axisModifiers) , m_action(action) { + Q_UNUSED(axis) } static SwipeGesture::Direction toSwipeDirection(SwipeDirection direction) { switch (direction) { case SwipeDirection::Up: return SwipeGesture::Direction::Up; case SwipeDirection::Down: return SwipeGesture::Direction::Down; case SwipeDirection::Left: return SwipeGesture::Direction::Left; case SwipeDirection::Right: return SwipeGesture::Direction::Right; case SwipeDirection::Invalid: default: Q_UNREACHABLE(); } } InternalGlobalShortcut::InternalGlobalShortcut(Qt::KeyboardModifiers swipeModifier, SwipeDirection direction, QAction *action) : GlobalShortcut(direction) , m_action(action) , m_swipe(new SwipeGesture) { Q_UNUSED(swipeModifier) m_swipe->setDirection(toSwipeDirection(direction)); m_swipe->setMinimumFingerCount(4); m_swipe->setMaximumFingerCount(4); QObject::connect(m_swipe.data(), &SwipeGesture::triggered, m_action, &QAction::trigger, Qt::QueuedConnection); } 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_gestureRecognizer(new GestureRecognizer(this)) { } template void clearShortcuts(T &shortcuts) { for (auto it = shortcuts.begin(); it != shortcuts.end(); ++it) { qDeleteAll((*it)); } } GlobalShortcutsManager::~GlobalShortcutsManager() { clearShortcuts(m_pointerShortcuts); clearShortcuts(m_axisShortcuts); clearShortcuts(m_swipeShortcuts); } void GlobalShortcutsManager::init() { if (kwinApp()->shouldUseWaylandForCompositing()) { qputenv("KGLOBALACCELD_PLATFORM", QByteArrayLiteral("org.kde.kwin")); 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"; } } } template void handleDestroyedAction(QObject *object, T &shortcuts) { for (auto it = shortcuts.begin(); it != shortcuts.end(); ++it) { auto &list = it.value(); auto it2 = list.begin(); while (it2 != list.end()) { if (InternalGlobalShortcut *shortcut = dynamic_cast(it2.value())) { if (shortcut->action() == object) { it2 = list.erase(it2); delete shortcut; continue; } } ++it2; } } } void GlobalShortcutsManager::objectDeleted(QObject *object) { handleDestroyedAction(object, m_pointerShortcuts); handleDestroyedAction(object, m_axisShortcuts); handleDestroyedAction(object, m_swipeShortcuts); } template GlobalShortcut *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 s; s.insert(value, cut); shortcuts.insert(modifiers, s); } return cut; } void GlobalShortcutsManager::registerPointerShortcut(QAction *action, Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons) { addShortcut(m_pointerShortcuts, action, modifiers, pointerButtons); connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted); } void GlobalShortcutsManager::registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis) { addShortcut(m_axisShortcuts, action, modifiers, axis); connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted); } void GlobalShortcutsManager::registerTouchpadSwipe(QAction *action, SwipeDirection direction) { auto shortcut = addShortcut(m_swipeShortcuts, action, Qt::NoModifier, direction); connect(action, &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted); m_gestureRecognizer->registerGesture(static_cast(shortcut)->swipeGesture()); } template bool processShortcut(Qt::KeyboardModifiers mods, T key, U &shortcuts) { auto it = shortcuts.find(mods); if (it == shortcuts.end()) { return false; } auto it2 = (*it).find(key); if (it2 == (*it).end()) { return false; } it2.value()->invoke(); return true; } bool GlobalShortcutsManager::processKey(Qt::KeyboardModifiers mods, int keyQt) { if (m_kglobalAccelInterface) { auto check = [this] (Qt::KeyboardModifiers mods, int keyQt) { bool retVal = false; QMetaObject::invokeMethod(m_kglobalAccelInterface, "checkKeyPressed", Qt::DirectConnection, Q_RETURN_ARG(bool, retVal), Q_ARG(int, int(mods) | keyQt)); return retVal; }; if (check(mods, keyQt)) { return true; } else if (keyQt == Qt::Key_Backtab) { // KGlobalAccel on X11 has some workaround for Backtab // see kglobalaccel/src/runtime/plugins/xcb/kglobalccel_x11.cpp method x11KeyPress // Apparently KKeySequenceWidget captures Shift+Tab instead of Backtab // thus if the key is backtab we should adjust to add shift again and use tab // in addition KWin registers the shortcut incorrectly as Alt+Shift+Backtab // this should be changed to either Alt+Backtab or Alt+Shift+Tab to match KKeySequenceWidget // trying the variants if (check(mods | Qt::ShiftModifier, keyQt)) { return true; } if (check(mods | Qt::ShiftModifier, Qt::Key_Tab)) { return true; } } } return false; } bool GlobalShortcutsManager::processPointerPressed(Qt::KeyboardModifiers mods, Qt::MouseButtons pointerButtons) { return processShortcut(mods, pointerButtons, m_pointerShortcuts); } bool GlobalShortcutsManager::processAxis(Qt::KeyboardModifiers mods, PointerAxisDirection axis) { return processShortcut(mods, axis, m_axisShortcuts); } void GlobalShortcutsManager::processSwipeStart(uint fingerCount) { m_gestureRecognizer->startSwipeGesture(fingerCount); } void GlobalShortcutsManager::processSwipeUpdate(const QSizeF &delta) { m_gestureRecognizer->updateSwipeGesture(delta); } void GlobalShortcutsManager::processSwipeCancel() { m_gestureRecognizer->cancelSwipeGesture(); } void GlobalShortcutsManager::processSwipeEnd() { m_gestureRecognizer->endSwipeGesture(); // TODO: cancel on Wayland Seat if one triggered } } // namespace diff --git a/globalshortcuts.h b/globalshortcuts.h index a03bd2920..b491879ac 100644 --- a/globalshortcuts.h +++ b/globalshortcuts.h @@ -1,193 +1,192 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2013 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_GLOBALSHORTCUTS_H #define KWIN_GLOBALSHORTCUTS_H // KWin #include // Qt #include class QAction; class KGlobalAccelD; class KGlobalAccelInterface; namespace KWin { class GlobalShortcut; class SwipeGesture; class GestureRecognizer; /** * @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(); void init(); /** * @brief Registers an internal global pointer shortcut * * @param action The action to trigger if the shortcut is pressed * @param modifiers The modifiers which need to be hold to trigger the action * @param pointerButtons The pointer button which needs to be pressed */ void registerPointerShortcut(QAction *action, Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons); /** * @brief Registers an internal global axis shortcut * * @param action The action to trigger if the shortcut is triggered * @param modifiers The modifiers which need to be hold to trigger the action * @param pointerButtons The pointer axis */ void registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis); void registerTouchpadSwipe(QAction *action, SwipeDirection direction); /** * @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 keyQt The Qt::Key which got pressed * @return @c true if a shortcut triggered, @c false otherwise */ bool processKey(Qt::KeyboardModifiers modifiers, int keyQt); bool processPointerPressed(Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons); /** * @brief Processes a pointer axis 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 axis The axis direction which has triggered this event * @return @c true if a shortcut triggered, @c false otherwise */ bool processAxis(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis); void processSwipeStart(uint fingerCount); void processSwipeUpdate(const QSizeF &delta); void processSwipeCancel(); void processSwipeEnd(); void setKGlobalAccelInterface(KGlobalAccelInterface *interface) { m_kglobalAccelInterface = interface; } private: void objectDeleted(QObject *object); QHash > m_pointerShortcuts; QHash > m_axisShortcuts; QHash > m_swipeShortcuts; KGlobalAccelD *m_kglobalAccel = nullptr; KGlobalAccelInterface *m_kglobalAccelInterface = nullptr; GestureRecognizer *m_gestureRecognizer; }; class GlobalShortcut { public: virtual ~GlobalShortcut(); const QKeySequence &shortcut() const; Qt::KeyboardModifiers pointerButtonModifiers() const; Qt::MouseButtons pointerButtons() const; SwipeDirection swipeDirection() const { return m_swipeDirection; } virtual void invoke() = 0; protected: GlobalShortcut(const QKeySequence &shortcut); GlobalShortcut(Qt::KeyboardModifiers pointerButtonModifiers, Qt::MouseButtons pointerButtons); - GlobalShortcut(Qt::KeyboardModifiers axisModifiers, PointerAxisDirection axis); + GlobalShortcut(Qt::KeyboardModifiers axisModifiers); GlobalShortcut(SwipeDirection direction); private: QKeySequence m_shortcut; Qt::KeyboardModifiers m_pointerModifiers; Qt::MouseButtons m_pointerButtons; - PointerAxisDirection m_axis; SwipeDirection m_swipeDirection = SwipeDirection::Invalid;; }; class InternalGlobalShortcut : public GlobalShortcut { public: InternalGlobalShortcut(Qt::KeyboardModifiers modifiers, const QKeySequence &shortcut, QAction *action); InternalGlobalShortcut(Qt::KeyboardModifiers pointerButtonModifiers, Qt::MouseButtons pointerButtons, QAction *action); InternalGlobalShortcut(Qt::KeyboardModifiers axisModifiers, PointerAxisDirection axis, QAction *action); InternalGlobalShortcut(Qt::KeyboardModifiers swipeModifier, SwipeDirection direction, QAction *action); virtual ~InternalGlobalShortcut(); void invoke() override; QAction *action() const; SwipeGesture *swipeGesture() const { return m_swipe.data(); } private: QAction *m_action; QScopedPointer m_swipe; }; inline QAction *InternalGlobalShortcut::action() const { return m_action; } inline const QKeySequence &GlobalShortcut::shortcut() const { return m_shortcut; } inline Qt::KeyboardModifiers GlobalShortcut::pointerButtonModifiers() const { return m_pointerModifiers; } inline Qt::MouseButtons GlobalShortcut::pointerButtons() const { return m_pointerButtons; } } // namespace #endif