KWin
Loading...
Searching...
No Matches
globalshortcuts.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9// own
10#include "globalshortcuts.h"
11// config
12#include <config-kwin.h>
13// kwin
14#include "effect/globals.h"
15#include "gestures.h"
16#include "main.h"
17#include "utils/common.h"
18// KDE
19#include <kglobalaccel_interface.h>
20#include <kglobalacceld.h>
21// Qt
22#include <QAction>
23// system
24#include <signal.h>
25#include <variant>
26
27namespace KWin
28{
30 : m_shortcut(sc)
31 , m_action(action)
32{
33 if (auto swipeGesture = std::get_if<RealtimeFeedbackSwipeShortcut>(&sc)) {
34 m_swipeGesture = std::make_unique<SwipeGesture>();
35 m_swipeGesture->setDirection(swipeGesture->direction);
36 m_swipeGesture->setMinimumDelta(QPointF(200, 200));
37 m_swipeGesture->setMaximumFingerCount(swipeGesture->fingerCount);
38 m_swipeGesture->setMinimumFingerCount(swipeGesture->fingerCount);
39 QObject::connect(m_swipeGesture.get(), &SwipeGesture::triggered, m_action, &QAction::trigger, Qt::QueuedConnection);
40 QObject::connect(m_swipeGesture.get(), &SwipeGesture::cancelled, m_action, &QAction::trigger, Qt::QueuedConnection);
41 if (swipeGesture->progressCallback) {
42 QObject::connect(m_swipeGesture.get(), &SwipeGesture::progress, swipeGesture->progressCallback);
43 }
44 } else if (auto pinchGesture = std::get_if<RealtimeFeedbackPinchShortcut>(&sc)) {
45 m_pinchGesture = std::make_unique<PinchGesture>();
46 m_pinchGesture->setDirection(pinchGesture->direction);
47 m_pinchGesture->setMaximumFingerCount(pinchGesture->fingerCount);
48 m_pinchGesture->setMinimumFingerCount(pinchGesture->fingerCount);
49 QObject::connect(m_pinchGesture.get(), &PinchGesture::triggered, m_action, &QAction::trigger, Qt::QueuedConnection);
50 QObject::connect(m_pinchGesture.get(), &PinchGesture::cancelled, m_action, &QAction::trigger, Qt::QueuedConnection);
51 if (pinchGesture->scaleCallback) {
52 QObject::connect(m_pinchGesture.get(), &PinchGesture::progress, pinchGesture->scaleCallback);
53 }
54 }
55}
56
60
61QAction *GlobalShortcut::action() const
62{
63 return m_action;
64}
65
67{
68 QMetaObject::invokeMethod(m_action, &QAction::trigger, Qt::QueuedConnection);
69}
70
72{
73 return m_shortcut;
74}
75
77{
78 return m_swipeGesture.get();
79}
80
82{
83 return m_pinchGesture.get();
84}
85
87 : QObject(parent)
88 , m_touchpadGestureRecognizer(new GestureRecognizer(this))
89 , m_touchscreenGestureRecognizer(new GestureRecognizer(this))
90{
91}
92
96
98{
99 if (kwinApp()->shouldUseWaylandForCompositing()) {
100 qputenv("KGLOBALACCELD_PLATFORM", QByteArrayLiteral("org.kde.kwin"));
101 m_kglobalAccel = std::make_unique<KGlobalAccelD>();
102 if (!m_kglobalAccel->init()) {
103 qCDebug(KWIN_CORE) << "Init of kglobalaccel failed";
104 m_kglobalAccel.reset();
105 } else {
106 qCDebug(KWIN_CORE) << "KGlobalAcceld inited";
107 }
108 }
109}
110
111void GlobalShortcutsManager::objectDeleted(QObject *object)
112{
113 auto it = m_shortcuts.begin();
114 while (it != m_shortcuts.end()) {
115 if (it->action() == object) {
116 it = m_shortcuts.erase(it);
117 } else {
118 ++it;
119 }
120 }
121}
122
123bool GlobalShortcutsManager::add(GlobalShortcut sc, DeviceType device)
124{
125 const auto &recognizer = device == DeviceType::Touchpad ? m_touchpadGestureRecognizer : m_touchscreenGestureRecognizer;
126 if (std::holds_alternative<RealtimeFeedbackSwipeShortcut>(sc.shortcut())) {
127 recognizer->registerSwipeGesture(sc.swipeGesture());
128 } else if (std::holds_alternative<RealtimeFeedbackPinchShortcut>(sc.shortcut())) {
129 recognizer->registerPinchGesture(sc.pinchGesture());
130 }
131 connect(sc.action(), &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
132 m_shortcuts.push_back(std::move(sc));
133 return true;
134}
135
136void GlobalShortcutsManager::registerPointerShortcut(QAction *action, Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons)
137{
138 add(GlobalShortcut(PointerButtonShortcut{modifiers, pointerButtons}, action));
139}
140
141void GlobalShortcutsManager::registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis)
142{
143 add(GlobalShortcut(PointerAxisShortcut{modifiers, axis}, action));
144}
145
146void GlobalShortcutsManager::registerTouchpadSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback)
147{
148 add(GlobalShortcut(RealtimeFeedbackSwipeShortcut{DeviceType::Touchpad, direction, progressCallback, fingerCount}, action), DeviceType::Touchpad);
149}
150
151void GlobalShortcutsManager::registerTouchpadPinch(PinchDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback)
152{
153 add(GlobalShortcut(RealtimeFeedbackPinchShortcut{direction, progressCallback, fingerCount}, action), DeviceType::Touchpad);
154}
155
156void GlobalShortcutsManager::registerTouchscreenSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback)
157{
158 add(GlobalShortcut(RealtimeFeedbackSwipeShortcut{DeviceType::Touchscreen, direction, progressCallback, fingerCount}, action), DeviceType::Touchscreen);
159}
160
161void GlobalShortcutsManager::forceRegisterTouchscreenSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function<void(qreal)> progressCallback)
162{
163 GlobalShortcut shortcut{RealtimeFeedbackSwipeShortcut{DeviceType::Touchscreen, direction, progressCallback, fingerCount}, action};
164 const auto it = std::find_if(m_shortcuts.begin(), m_shortcuts.end(), [&shortcut](const auto &s) {
165 return shortcut.shortcut() == s.shortcut();
166 });
167 if (it != m_shortcuts.end()) {
168 m_shortcuts.erase(it);
169 }
170 m_touchscreenGestureRecognizer->registerSwipeGesture(shortcut.swipeGesture());
171 connect(shortcut.action(), &QAction::destroyed, this, &GlobalShortcutsManager::objectDeleted);
172 m_shortcuts.push_back(std::move(shortcut));
173}
174
175bool GlobalShortcutsManager::processKey(Qt::KeyboardModifiers mods, int keyQt)
176{
177 if (m_kglobalAccelInterface) {
178 if (!keyQt && !mods) {
179 return false;
180 }
181 auto check = [this](Qt::KeyboardModifiers mods, int keyQt) {
182 bool retVal = false;
183 QMetaObject::invokeMethod(m_kglobalAccelInterface,
184 "checkKeyPressed",
185 Qt::DirectConnection,
186 Q_RETURN_ARG(bool, retVal),
187 Q_ARG(int, int(mods) | keyQt));
188 return retVal;
189 };
190 if (check(mods, keyQt)) {
191 return true;
192 } else if (keyQt == Qt::Key_Backtab) {
193 // KGlobalAccel on X11 has some workaround for Backtab
194 // see kglobalaccel/src/runtime/plugins/xcb/kglobalccel_x11.cpp method x11KeyPress
195 // Apparently KKeySequenceWidget captures Shift+Tab instead of Backtab
196 // thus if the key is backtab we should adjust to add shift again and use tab
197 // in addition KWin registers the shortcut incorrectly as Alt+Shift+Backtab
198 // this should be changed to either Alt+Backtab or Alt+Shift+Tab to match KKeySequenceWidget
199 // trying the variants
200 if (check(mods | Qt::ShiftModifier, keyQt)) {
201 return true;
202 }
203 if (check(mods | Qt::ShiftModifier, Qt::Key_Tab)) {
204 return true;
205 }
206 }
207 }
208 return false;
209}
210
211bool GlobalShortcutsManager::processKeyRelease(Qt::KeyboardModifiers mods, int keyQt)
212{
213 if (m_kglobalAccelInterface) {
214 QMetaObject::invokeMethod(m_kglobalAccelInterface,
215 "checkKeyReleased",
216 Qt::DirectConnection,
217 Q_ARG(int, int(mods) | keyQt));
218 }
219 return false;
220}
221
222template<typename ShortcutKind, typename... Args>
223bool match(QList<GlobalShortcut> &shortcuts, Args... args)
224{
225 for (auto &sc : shortcuts) {
226 if (std::holds_alternative<ShortcutKind>(sc.shortcut())) {
227 if (std::get<ShortcutKind>(sc.shortcut()) == ShortcutKind{args...}) {
228 sc.invoke();
229 return true;
230 }
231 }
232 }
233 return false;
234}
235
236// TODO(C++20): use ranges for a nicer way of filtering by shortcut type
237bool GlobalShortcutsManager::processPointerPressed(Qt::KeyboardModifiers mods, Qt::MouseButtons pointerButtons)
238{
239 return match<PointerButtonShortcut>(m_shortcuts, mods, pointerButtons);
240}
241
242bool GlobalShortcutsManager::processAxis(Qt::KeyboardModifiers mods, PointerAxisDirection axis)
243{
244 return match<PointerAxisShortcut>(m_shortcuts, mods, axis);
245}
246
248{
249 if (device == DeviceType::Touchpad) {
250 m_touchpadGestureRecognizer->startSwipeGesture(fingerCount);
251 } else {
252 m_touchscreenGestureRecognizer->startSwipeGesture(fingerCount);
253 }
254}
255
257{
258 if (device == DeviceType::Touchpad) {
259 m_touchpadGestureRecognizer->updateSwipeGesture(delta);
260 } else {
261 m_touchscreenGestureRecognizer->updateSwipeGesture(delta);
262 }
263}
264
266{
267 if (device == DeviceType::Touchpad) {
268 m_touchpadGestureRecognizer->cancelSwipeGesture();
269 } else {
270 m_touchscreenGestureRecognizer->cancelSwipeGesture();
271 }
272}
273
275{
276 if (device == DeviceType::Touchpad) {
277 m_touchpadGestureRecognizer->endSwipeGesture();
278 } else {
279 m_touchscreenGestureRecognizer->endSwipeGesture();
280 }
281 // TODO: cancel on Wayland Seat if one triggered
282}
283
285{
286 m_touchpadGestureRecognizer->startPinchGesture(fingerCount);
287}
288
289void GlobalShortcutsManager::processPinchUpdate(qreal scale, qreal angleDelta, const QPointF &delta)
290{
291 m_touchpadGestureRecognizer->updatePinchGesture(scale, angleDelta, delta);
292}
293
295{
296 m_touchpadGestureRecognizer->cancelPinchGesture();
297}
298
300{
301 m_touchpadGestureRecognizer->endPinchGesture();
302}
303
304} // namespace
305
306#include "moc_globalshortcuts.cpp"
void cancelled()
void triggered()
const Shortcut & shortcut() const
QAction * action() const
GlobalShortcut(Shortcut &&shortcut, QAction *action)
PinchGesture * pinchGesture() const
SwipeGesture * swipeGesture() const
void registerTouchpadPinch(PinchDirection direction, uint32_t fingerCount, QAction *action, std::function< void(qreal)> progressCallback={})
void processSwipeEnd(DeviceType device)
void processPinchUpdate(qreal scale, qreal angleDelta, const QPointF &delta)
GlobalShortcutsManager(QObject *parent=nullptr)
void processSwipeUpdate(DeviceType device, const QPointF &delta)
void registerPointerShortcut(QAction *action, Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons)
Registers an internal global pointer shortcut.
void processSwipeCancel(DeviceType device)
bool processKeyRelease(Qt::KeyboardModifiers modifiers, int keyQt)
void forceRegisterTouchscreenSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function< void(qreal)> progressCallback={})
bool processKey(Qt::KeyboardModifiers modifiers, int keyQt)
Processes a key event to decide whether a shortcut needs to be triggered.
void registerTouchpadSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function< void(qreal)> progressCallback={})
bool processAxis(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis)
Processes a pointer axis event to decide whether a shortcut needs to be triggered.
bool processPointerPressed(Qt::KeyboardModifiers modifiers, Qt::MouseButtons pointerButtons)
void processPinchStart(uint fingerCount)
void processSwipeStart(DeviceType device, uint fingerCount)
void registerTouchscreenSwipe(SwipeDirection direction, uint32_t fingerCount, QAction *action, std::function< void(qreal)> progressCallback={})
void registerAxisShortcut(QAction *action, Qt::KeyboardModifiers modifiers, PointerAxisDirection axis)
Registers an internal global axis shortcut.
PinchDirection direction() const
Definition gestures.cpp:545
void progress(qreal)
SwipeDirection direction() const
Definition gestures.cpp:423
void progress(qreal)
std::variant< KeyboardShortcut, PointerButtonShortcut, PointerAxisShortcut, RealtimeFeedbackSwipeShortcut, RealtimeFeedbackPinchShortcut > Shortcut
PointerAxisDirection
The direction in which a pointer axis is moved.
Definition globals.h:104
PinchDirection
Definition globals.h:123
SwipeDirection
Directions for swipe gestures.
Definition globals.h:115
bool match(QList< GlobalShortcut > &shortcuts, Args... args)