File indexing completed on 2024-04-28 16:48:49

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0006     SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
0007     SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 #include "input.h"
0012 
0013 #include "backends/fakeinput/fakeinputbackend.h"
0014 #include "backends/libinput/connection.h"
0015 #include "backends/libinput/device.h"
0016 #include "core/inputbackend.h"
0017 #include "core/session.h"
0018 #include "effects.h"
0019 #include "gestures.h"
0020 #include "globalshortcuts.h"
0021 #include "hide_cursor_spy.h"
0022 #include "idledetector.h"
0023 #include "input_event.h"
0024 #include "input_event_spy.h"
0025 #include "inputmethod.h"
0026 #include "keyboard_input.h"
0027 #include "main.h"
0028 #include "mousebuttons.h"
0029 #include "pointer_input.h"
0030 #include "tablet_input.h"
0031 #include "touch_input.h"
0032 #include "x11window.h"
0033 #if KWIN_BUILD_TABBOX
0034 #include "tabbox/tabbox.h"
0035 #endif
0036 #include "core/output.h"
0037 #include "core/outputbackend.h"
0038 #include "cursor.h"
0039 #include "cursorsource.h"
0040 #include "internalwindow.h"
0041 #include "popup_input_filter.h"
0042 #include "screenedge.h"
0043 #include "unmanaged.h"
0044 #include "virtualdesktops.h"
0045 #include "wayland/display.h"
0046 #include "wayland/inputmethod_v1_interface.h"
0047 #include "wayland/seat_interface.h"
0048 #include "wayland/shmclientbuffer.h"
0049 #include "wayland/surface_interface.h"
0050 #include "wayland/tablet_v2_interface.h"
0051 #include "wayland_server.h"
0052 #include "workspace.h"
0053 #include "xkb.h"
0054 #include "xwayland/xwayland_interface.h"
0055 
0056 #include <KDecoration2/Decoration>
0057 #include <KGlobalAccel>
0058 #include <KLocalizedString>
0059 #include <decorations/decoratedclient.h>
0060 
0061 // screenlocker
0062 #if KWIN_BUILD_SCREENLOCKER
0063 #include <KScreenLocker/KsldApp>
0064 #endif
0065 // Qt
0066 #include <QAction>
0067 #include <QDBusConnection>
0068 #include <QDBusMessage>
0069 #include <QDBusPendingCall>
0070 #include <QKeyEvent>
0071 #include <QThread>
0072 #include <qpa/qwindowsysteminterface.h>
0073 
0074 #include <xkbcommon/xkbcommon.h>
0075 
0076 #include "osd.h"
0077 #include <cmath>
0078 
0079 using namespace std::literals;
0080 
0081 namespace KWin
0082 {
0083 
0084 static KWaylandServer::PointerAxisSource kwinAxisSourceToKWaylandAxisSource(InputRedirection::PointerAxisSource source)
0085 {
0086     switch (source) {
0087     case KWin::InputRedirection::PointerAxisSourceWheel:
0088         return KWaylandServer::PointerAxisSource::Wheel;
0089     case KWin::InputRedirection::PointerAxisSourceFinger:
0090         return KWaylandServer::PointerAxisSource::Finger;
0091     case KWin::InputRedirection::PointerAxisSourceContinuous:
0092         return KWaylandServer::PointerAxisSource::Continuous;
0093     case KWin::InputRedirection::PointerAxisSourceWheelTilt:
0094         return KWaylandServer::PointerAxisSource::WheelTilt;
0095     case KWin::InputRedirection::PointerAxisSourceUnknown:
0096     default:
0097         return KWaylandServer::PointerAxisSource::Unknown;
0098     }
0099 }
0100 
0101 InputEventFilter::InputEventFilter() = default;
0102 
0103 InputEventFilter::~InputEventFilter()
0104 {
0105     if (input()) {
0106         input()->uninstallInputEventFilter(this);
0107     }
0108 }
0109 
0110 bool InputEventFilter::pointerEvent(MouseEvent *event, quint32 nativeButton)
0111 {
0112     return false;
0113 }
0114 
0115 bool InputEventFilter::wheelEvent(WheelEvent *event)
0116 {
0117     return false;
0118 }
0119 
0120 bool InputEventFilter::keyEvent(KeyEvent *event)
0121 {
0122     return false;
0123 }
0124 
0125 bool InputEventFilter::touchDown(qint32 id, const QPointF &point, std::chrono::microseconds time)
0126 {
0127     return false;
0128 }
0129 
0130 bool InputEventFilter::touchMotion(qint32 id, const QPointF &point, std::chrono::microseconds time)
0131 {
0132     return false;
0133 }
0134 
0135 bool InputEventFilter::touchUp(qint32 id, std::chrono::microseconds time)
0136 {
0137     return false;
0138 }
0139 
0140 bool InputEventFilter::touchCancel()
0141 {
0142     return false;
0143 }
0144 
0145 bool InputEventFilter::touchFrame()
0146 {
0147     return false;
0148 }
0149 
0150 bool InputEventFilter::pinchGestureBegin(int fingerCount, std::chrono::microseconds time)
0151 {
0152     return false;
0153 }
0154 
0155 bool InputEventFilter::pinchGestureUpdate(qreal scale, qreal angleDelta, const QPointF &delta, std::chrono::microseconds time)
0156 {
0157     return false;
0158 }
0159 
0160 bool InputEventFilter::pinchGestureEnd(std::chrono::microseconds time)
0161 {
0162     return false;
0163 }
0164 
0165 bool InputEventFilter::pinchGestureCancelled(std::chrono::microseconds time)
0166 {
0167     return false;
0168 }
0169 
0170 bool InputEventFilter::swipeGestureBegin(int fingerCount, std::chrono::microseconds time)
0171 {
0172     return false;
0173 }
0174 
0175 bool InputEventFilter::swipeGestureUpdate(const QPointF &delta, std::chrono::microseconds time)
0176 {
0177     return false;
0178 }
0179 
0180 bool InputEventFilter::swipeGestureEnd(std::chrono::microseconds time)
0181 {
0182     return false;
0183 }
0184 
0185 bool InputEventFilter::swipeGestureCancelled(std::chrono::microseconds time)
0186 {
0187     return false;
0188 }
0189 
0190 bool InputEventFilter::holdGestureBegin(int fingerCount, std::chrono::microseconds time)
0191 {
0192     return false;
0193 }
0194 
0195 bool InputEventFilter::holdGestureEnd(std::chrono::microseconds time)
0196 {
0197     return false;
0198 }
0199 
0200 bool InputEventFilter::holdGestureCancelled(std::chrono::microseconds time)
0201 {
0202     return false;
0203 }
0204 
0205 bool InputEventFilter::switchEvent(SwitchEvent *event)
0206 {
0207     return false;
0208 }
0209 
0210 bool InputEventFilter::tabletToolEvent(TabletEvent *event)
0211 {
0212     return false;
0213 }
0214 
0215 bool InputEventFilter::tabletToolButtonEvent(uint button, bool pressed, const TabletToolId &tabletId, std::chrono::microseconds time)
0216 {
0217     return false;
0218 }
0219 
0220 bool InputEventFilter::tabletPadButtonEvent(uint button, bool pressed, const TabletPadId &tabletPadId, std::chrono::microseconds time)
0221 {
0222     return false;
0223 }
0224 
0225 bool InputEventFilter::tabletPadStripEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time)
0226 {
0227     return false;
0228 }
0229 
0230 bool InputEventFilter::tabletPadRingEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time)
0231 {
0232     return false;
0233 }
0234 
0235 void InputEventFilter::passToWaylandServer(QKeyEvent *event)
0236 {
0237     Q_ASSERT(waylandServer());
0238     if (event->isAutoRepeat()) {
0239         return;
0240     }
0241 
0242     KWaylandServer::SeatInterface *seat = waylandServer()->seat();
0243     const int keyCode = event->nativeScanCode();
0244     switch (event->type()) {
0245     case QEvent::KeyPress:
0246         seat->notifyKeyboardKey(keyCode, KWaylandServer::KeyboardKeyState::Pressed);
0247         break;
0248     case QEvent::KeyRelease:
0249         seat->notifyKeyboardKey(keyCode, KWaylandServer::KeyboardKeyState::Released);
0250         break;
0251     default:
0252         break;
0253     }
0254 }
0255 
0256 bool InputEventFilter::passToInputMethod(QKeyEvent *event)
0257 {
0258     if (!kwinApp()->inputMethod()) {
0259         return false;
0260     }
0261     if (auto keyboardGrab = kwinApp()->inputMethod()->keyboardGrab()) {
0262         if (event->isAutoRepeat()) {
0263             return true;
0264         }
0265         auto newState = event->type() == QEvent::KeyPress ? KWaylandServer::KeyboardKeyState::Pressed : KWaylandServer::KeyboardKeyState::Released;
0266         keyboardGrab->sendKey(waylandServer()->display()->nextSerial(), event->timestamp(), event->nativeScanCode(), newState);
0267         return true;
0268     } else {
0269         return false;
0270     }
0271 }
0272 
0273 class VirtualTerminalFilter : public InputEventFilter
0274 {
0275 public:
0276     bool keyEvent(KeyEvent *event) override
0277     {
0278         // really on press and not on release? X11 switches on press.
0279         if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) {
0280             const xkb_keysym_t keysym = event->nativeVirtualKey();
0281             if (keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12) {
0282                 kwinApp()->session()->switchTo(keysym - XKB_KEY_XF86Switch_VT_1 + 1);
0283                 return true;
0284             }
0285         }
0286         return false;
0287     }
0288 };
0289 
0290 class TerminateServerFilter : public InputEventFilter
0291 {
0292 public:
0293     bool keyEvent(KeyEvent *event) override
0294     {
0295         if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) {
0296             if (event->nativeVirtualKey() == XKB_KEY_Terminate_Server) {
0297                 qCWarning(KWIN_CORE) << "Request to terminate server";
0298                 QMetaObject::invokeMethod(QCoreApplication::instance(), &QCoreApplication::quit, Qt::QueuedConnection);
0299                 return true;
0300             }
0301         }
0302         return false;
0303     }
0304 };
0305 
0306 class LockScreenFilter : public InputEventFilter
0307 {
0308 public:
0309     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
0310     {
0311         if (!waylandServer()->isScreenLocked()) {
0312             return false;
0313         }
0314 
0315         auto window = input()->findToplevel(event->globalPos());
0316         if (window && window->isClient() && window->isLockScreen()) {
0317             workspace()->activateWindow(window);
0318         }
0319 
0320         auto seat = waylandServer()->seat();
0321         seat->setTimestamp(event->timestamp());
0322         if (event->type() == QEvent::MouseMove) {
0323             if (pointerSurfaceAllowed()) {
0324                 // TODO: should the pointer position always stay in sync, i.e. not do the check?
0325                 seat->notifyPointerMotion(event->screenPos());
0326                 seat->notifyPointerFrame();
0327             }
0328         } else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) {
0329             if (pointerSurfaceAllowed()) {
0330                 // TODO: can we leak presses/releases here when we move the mouse in between from an allowed surface to
0331                 //       disallowed one or vice versa?
0332                 const auto state = event->type() == QEvent::MouseButtonPress
0333                     ? KWaylandServer::PointerButtonState::Pressed
0334                     : KWaylandServer::PointerButtonState::Released;
0335                 seat->notifyPointerButton(nativeButton, state);
0336                 seat->notifyPointerFrame();
0337             }
0338         }
0339         return true;
0340     }
0341     bool wheelEvent(WheelEvent *event) override
0342     {
0343         if (!waylandServer()->isScreenLocked()) {
0344             return false;
0345         }
0346         auto seat = waylandServer()->seat();
0347         if (pointerSurfaceAllowed()) {
0348             const WheelEvent *wheelEvent = static_cast<WheelEvent *>(event);
0349             seat->setTimestamp(wheelEvent->timestamp());
0350             seat->notifyPointerAxis(wheelEvent->orientation(), wheelEvent->delta(),
0351                                     wheelEvent->deltaV120(),
0352                                     kwinAxisSourceToKWaylandAxisSource(wheelEvent->axisSource()));
0353             seat->notifyPointerFrame();
0354         }
0355         return true;
0356     }
0357     bool keyEvent(KeyEvent *event) override
0358     {
0359         if (!waylandServer()->isScreenLocked()) {
0360             return false;
0361         }
0362         if (event->isAutoRepeat()) {
0363             // wayland client takes care of it
0364             return true;
0365         }
0366         // send event to KSldApp for global accel
0367         // if event is set to accepted it means a whitelisted shortcut was triggered
0368         // in that case we filter it out and don't process it further
0369 #if KWIN_BUILD_SCREENLOCKER
0370         event->setAccepted(false);
0371         QCoreApplication::sendEvent(ScreenLocker::KSldApp::self(), event);
0372         if (event->isAccepted()) {
0373             return true;
0374         }
0375 #endif
0376 
0377         // continue normal processing
0378         input()->keyboard()->update();
0379         auto seat = waylandServer()->seat();
0380         seat->setTimestamp(event->timestamp());
0381         if (!keyboardSurfaceAllowed()) {
0382             // don't pass event to seat
0383             return true;
0384         }
0385         switch (event->type()) {
0386         case QEvent::KeyPress:
0387             seat->notifyKeyboardKey(event->nativeScanCode(), KWaylandServer::KeyboardKeyState::Pressed);
0388             break;
0389         case QEvent::KeyRelease:
0390             seat->notifyKeyboardKey(event->nativeScanCode(), KWaylandServer::KeyboardKeyState::Released);
0391             break;
0392         default:
0393             break;
0394         }
0395         return true;
0396     }
0397     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0398     {
0399         if (!waylandServer()->isScreenLocked()) {
0400             return false;
0401         }
0402         auto seat = waylandServer()->seat();
0403         seat->setTimestamp(time);
0404         if (touchSurfaceAllowed()) {
0405             seat->notifyTouchDown(id, pos);
0406         }
0407         return true;
0408     }
0409     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0410     {
0411         if (!waylandServer()->isScreenLocked()) {
0412             return false;
0413         }
0414         auto seat = waylandServer()->seat();
0415         seat->setTimestamp(time);
0416         if (touchSurfaceAllowed()) {
0417             seat->notifyTouchMotion(id, pos);
0418         }
0419         return true;
0420     }
0421     bool touchUp(qint32 id, std::chrono::microseconds time) override
0422     {
0423         if (!waylandServer()->isScreenLocked()) {
0424             return false;
0425         }
0426         auto seat = waylandServer()->seat();
0427         seat->setTimestamp(time);
0428         if (touchSurfaceAllowed()) {
0429             seat->notifyTouchUp(id);
0430         }
0431         return true;
0432     }
0433     bool pinchGestureBegin(int fingerCount, std::chrono::microseconds time) override
0434     {
0435         // no touchpad multi-finger gestures on lock screen
0436         return waylandServer()->isScreenLocked();
0437     }
0438     bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QPointF &delta, std::chrono::microseconds time) override
0439     {
0440         // no touchpad multi-finger gestures on lock screen
0441         return waylandServer()->isScreenLocked();
0442     }
0443     bool pinchGestureEnd(std::chrono::microseconds time) override
0444     {
0445         // no touchpad multi-finger gestures on lock screen
0446         return waylandServer()->isScreenLocked();
0447     }
0448     bool pinchGestureCancelled(std::chrono::microseconds time) override
0449     {
0450         // no touchpad multi-finger gestures on lock screen
0451         return waylandServer()->isScreenLocked();
0452     }
0453 
0454     bool swipeGestureBegin(int fingerCount, std::chrono::microseconds time) override
0455     {
0456         // no touchpad multi-finger gestures on lock screen
0457         return waylandServer()->isScreenLocked();
0458     }
0459     bool swipeGestureUpdate(const QPointF &delta, std::chrono::microseconds time) override
0460     {
0461         // no touchpad multi-finger gestures on lock screen
0462         return waylandServer()->isScreenLocked();
0463     }
0464     bool swipeGestureEnd(std::chrono::microseconds time) override
0465     {
0466         // no touchpad multi-finger gestures on lock screen
0467         return waylandServer()->isScreenLocked();
0468     }
0469     bool swipeGestureCancelled(std::chrono::microseconds time) override
0470     {
0471         // no touchpad multi-finger gestures on lock screen
0472         return waylandServer()->isScreenLocked();
0473     }
0474     bool holdGestureBegin(int fingerCount, std::chrono::microseconds time) override
0475     {
0476         // no touchpad multi-finger gestures on lock screen
0477         return waylandServer()->isScreenLocked();
0478     }
0479     bool holdGestureEnd(std::chrono::microseconds time) override
0480     {
0481         // no touchpad multi-finger gestures on lock screen
0482         return waylandServer()->isScreenLocked();
0483     }
0484 
0485 private:
0486     bool surfaceAllowed(KWaylandServer::SurfaceInterface *(KWaylandServer::SeatInterface::*method)() const) const
0487     {
0488         if (KWaylandServer::SurfaceInterface *s = (waylandServer()->seat()->*method)()) {
0489             if (Window *t = waylandServer()->findWindow(s)) {
0490                 return t->isLockScreen() || t->isInputMethod() || t->isLockScreenOverlay();
0491             }
0492             return false;
0493         }
0494         return true;
0495     }
0496     bool pointerSurfaceAllowed() const
0497     {
0498         return surfaceAllowed(&KWaylandServer::SeatInterface::focusedPointerSurface);
0499     }
0500     bool keyboardSurfaceAllowed() const
0501     {
0502         return surfaceAllowed(&KWaylandServer::SeatInterface::focusedKeyboardSurface);
0503     }
0504     bool touchSurfaceAllowed() const
0505     {
0506         return surfaceAllowed(&KWaylandServer::SeatInterface::focusedTouchSurface);
0507     }
0508 };
0509 
0510 class EffectsFilter : public InputEventFilter
0511 {
0512 public:
0513     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
0514     {
0515         if (!effects) {
0516             return false;
0517         }
0518         return static_cast<EffectsHandlerImpl *>(effects)->checkInputWindowEvent(event);
0519     }
0520     bool wheelEvent(WheelEvent *event) override
0521     {
0522         if (!effects) {
0523             return false;
0524         }
0525         return static_cast<EffectsHandlerImpl *>(effects)->checkInputWindowEvent(event);
0526     }
0527     bool keyEvent(KeyEvent *event) override
0528     {
0529         if (!effects || !static_cast<EffectsHandlerImpl *>(effects)->hasKeyboardGrab()) {
0530             return false;
0531         }
0532         waylandServer()->seat()->setFocusedKeyboardSurface(nullptr);
0533         passToWaylandServer(event);
0534         static_cast<EffectsHandlerImpl *>(effects)->grabbedKeyboardEvent(event);
0535         return true;
0536     }
0537     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0538     {
0539         if (!effects) {
0540             return false;
0541         }
0542         return static_cast<EffectsHandlerImpl *>(effects)->touchDown(id, pos, time);
0543     }
0544     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0545     {
0546         if (!effects) {
0547             return false;
0548         }
0549         return static_cast<EffectsHandlerImpl *>(effects)->touchMotion(id, pos, time);
0550     }
0551     bool touchUp(qint32 id, std::chrono::microseconds time) override
0552     {
0553         if (!effects) {
0554             return false;
0555         }
0556         return static_cast<EffectsHandlerImpl *>(effects)->touchUp(id, time);
0557     }
0558     bool tabletToolEvent(TabletEvent *event) override
0559     {
0560         if (!effects) {
0561             return false;
0562         }
0563         return static_cast<EffectsHandlerImpl *>(effects)->tabletToolEvent(event);
0564     }
0565     bool tabletToolButtonEvent(uint button, bool pressed, const TabletToolId &tabletToolId, std::chrono::microseconds time) override
0566     {
0567         if (!effects) {
0568             return false;
0569         }
0570         return static_cast<EffectsHandlerImpl *>(effects)->tabletToolButtonEvent(button, pressed, tabletToolId, time);
0571     }
0572     bool tabletPadButtonEvent(uint button, bool pressed, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
0573     {
0574         if (!effects) {
0575             return false;
0576         }
0577         return static_cast<EffectsHandlerImpl *>(effects)->tabletPadButtonEvent(button, pressed, tabletPadId, time);
0578     }
0579     bool tabletPadStripEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
0580     {
0581         if (!effects) {
0582             return false;
0583         }
0584         return static_cast<EffectsHandlerImpl *>(effects)->tabletPadStripEvent(number, position, isFinger, tabletPadId, time);
0585     }
0586     bool tabletPadRingEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
0587     {
0588         if (!effects) {
0589             return false;
0590         }
0591         return static_cast<EffectsHandlerImpl *>(effects)->tabletPadRingEvent(number, position, isFinger, tabletPadId, time);
0592     }
0593 };
0594 
0595 class MoveResizeFilter : public InputEventFilter
0596 {
0597 public:
0598     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
0599     {
0600         Window *window = workspace()->moveResizeWindow();
0601         if (!window) {
0602             return false;
0603         }
0604         switch (event->type()) {
0605         case QEvent::MouseMove:
0606             window->updateInteractiveMoveResize(event->screenPos());
0607             break;
0608         case QEvent::MouseButtonRelease:
0609             if (event->buttons() == Qt::NoButton) {
0610                 window->endInteractiveMoveResize();
0611             }
0612             break;
0613         default:
0614             break;
0615         }
0616         return true;
0617     }
0618     bool wheelEvent(WheelEvent *event) override
0619     {
0620         // filter out while moving a window
0621         return workspace()->moveResizeWindow() != nullptr;
0622     }
0623     bool keyEvent(KeyEvent *event) override
0624     {
0625         Window *window = workspace()->moveResizeWindow();
0626         if (!window) {
0627             return false;
0628         }
0629         if (event->type() == QEvent::KeyPress) {
0630             window->keyPressEvent(event->key() | event->modifiers());
0631             if (window->isInteractiveMove() || window->isInteractiveResize()) {
0632                 // only update if mode didn't end
0633                 window->updateInteractiveMoveResize(input()->globalPointer());
0634             }
0635         }
0636         return true;
0637     }
0638 
0639     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0640     {
0641         Window *window = workspace()->moveResizeWindow();
0642         if (!window) {
0643             return false;
0644         }
0645         return true;
0646     }
0647 
0648     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0649     {
0650         Window *window = workspace()->moveResizeWindow();
0651         if (!window) {
0652             return false;
0653         }
0654         if (!m_set) {
0655             m_id = id;
0656             m_set = true;
0657         }
0658         if (m_id == id) {
0659             window->updateInteractiveMoveResize(pos);
0660         }
0661         return true;
0662     }
0663 
0664     bool touchUp(qint32 id, std::chrono::microseconds time) override
0665     {
0666         Window *window = workspace()->moveResizeWindow();
0667         if (!window) {
0668             return false;
0669         }
0670         if (m_id == id || !m_set) {
0671             window->endInteractiveMoveResize();
0672             m_set = false;
0673             // pass through to update decoration filter later on
0674             return false;
0675         }
0676         m_set = false;
0677         return true;
0678     }
0679 
0680     bool tabletToolEvent(TabletEvent *event) override
0681     {
0682         Window *window = workspace()->moveResizeWindow();
0683         if (!window) {
0684             return false;
0685         }
0686         switch (event->type()) {
0687         case QEvent::TabletMove:
0688             window->updateInteractiveMoveResize(event->globalPos());
0689             break;
0690         case QEvent::TabletRelease:
0691             window->endInteractiveMoveResize();
0692             break;
0693         default:
0694             break;
0695         }
0696         // Let TabletInputFilter receive the event, so the cursor position can be updated.
0697         return false;
0698     }
0699 
0700 private:
0701     qint32 m_id = 0;
0702     bool m_set = false;
0703 };
0704 
0705 class WindowSelectorFilter : public InputEventFilter
0706 {
0707 public:
0708     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
0709     {
0710         if (!m_active) {
0711             return false;
0712         }
0713         switch (event->type()) {
0714         case QEvent::MouseButtonRelease:
0715             if (event->buttons() == Qt::NoButton) {
0716                 if (event->button() == Qt::RightButton) {
0717                     cancel();
0718                 } else {
0719                     accept(event->globalPos());
0720                 }
0721             }
0722             break;
0723         default:
0724             break;
0725         }
0726         return true;
0727     }
0728     bool wheelEvent(WheelEvent *event) override
0729     {
0730         // filter out while selecting a window
0731         return m_active;
0732     }
0733     bool keyEvent(KeyEvent *event) override
0734     {
0735         if (!m_active) {
0736             return false;
0737         }
0738         waylandServer()->seat()->setFocusedKeyboardSurface(nullptr);
0739         passToWaylandServer(event);
0740 
0741         if (event->type() == QEvent::KeyPress) {
0742             // x11 variant does this on key press, so do the same
0743             if (event->key() == Qt::Key_Escape) {
0744                 cancel();
0745             } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return || event->key() == Qt::Key_Space) {
0746                 accept(input()->globalPointer());
0747             }
0748             if (input()->supportsPointerWarping()) {
0749                 int mx = 0;
0750                 int my = 0;
0751                 if (event->key() == Qt::Key_Left) {
0752                     mx = -10;
0753                 }
0754                 if (event->key() == Qt::Key_Right) {
0755                     mx = 10;
0756                 }
0757                 if (event->key() == Qt::Key_Up) {
0758                     my = -10;
0759                 }
0760                 if (event->key() == Qt::Key_Down) {
0761                     my = 10;
0762                 }
0763                 if (event->modifiers() & Qt::ControlModifier) {
0764                     mx /= 10;
0765                     my /= 10;
0766                 }
0767                 input()->warpPointer(input()->globalPointer() + QPointF(mx, my));
0768             }
0769         }
0770         // filter out while selecting a window
0771         return true;
0772     }
0773 
0774     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0775     {
0776         if (!isActive()) {
0777             return false;
0778         }
0779         m_touchPoints.insert(id, pos);
0780         return true;
0781     }
0782 
0783     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
0784     {
0785         if (!isActive()) {
0786             return false;
0787         }
0788         auto it = m_touchPoints.find(id);
0789         if (it != m_touchPoints.end()) {
0790             *it = pos;
0791         }
0792         return true;
0793     }
0794 
0795     bool touchUp(qint32 id, std::chrono::microseconds time) override
0796     {
0797         if (!isActive()) {
0798             return false;
0799         }
0800         auto it = m_touchPoints.find(id);
0801         if (it != m_touchPoints.end()) {
0802             const auto pos = it.value();
0803             m_touchPoints.erase(it);
0804             if (m_touchPoints.isEmpty()) {
0805                 accept(pos);
0806             }
0807         }
0808         return true;
0809     }
0810 
0811     bool isActive() const
0812     {
0813         return m_active;
0814     }
0815     void start(std::function<void(KWin::Window *)> callback)
0816     {
0817         Q_ASSERT(!m_active);
0818         m_active = true;
0819         m_callback = callback;
0820         input()->keyboard()->update();
0821         input()->touch()->cancel();
0822     }
0823     void start(std::function<void(const QPoint &)> callback)
0824     {
0825         Q_ASSERT(!m_active);
0826         m_active = true;
0827         m_pointSelectionFallback = callback;
0828         input()->keyboard()->update();
0829         input()->touch()->cancel();
0830     }
0831 
0832 private:
0833     void deactivate()
0834     {
0835         m_active = false;
0836         m_callback = std::function<void(KWin::Window *)>();
0837         m_pointSelectionFallback = std::function<void(const QPoint &)>();
0838         input()->pointer()->removeWindowSelectionCursor();
0839         input()->keyboard()->update();
0840         m_touchPoints.clear();
0841     }
0842     void cancel()
0843     {
0844         if (m_callback) {
0845             m_callback(nullptr);
0846         }
0847         if (m_pointSelectionFallback) {
0848             m_pointSelectionFallback(QPoint(-1, -1));
0849         }
0850         deactivate();
0851     }
0852     void accept(const QPointF &pos)
0853     {
0854         if (m_callback) {
0855             // TODO: this ignores shaped windows
0856             m_callback(input()->findToplevel(pos));
0857         }
0858         if (m_pointSelectionFallback) {
0859             m_pointSelectionFallback(pos.toPoint());
0860         }
0861         deactivate();
0862     }
0863 
0864     bool m_active = false;
0865     std::function<void(KWin::Window *)> m_callback;
0866     std::function<void(const QPoint &)> m_pointSelectionFallback;
0867     QMap<quint32, QPointF> m_touchPoints;
0868 };
0869 
0870 class GlobalShortcutFilter : public InputEventFilter
0871 {
0872 public:
0873     GlobalShortcutFilter()
0874     {
0875         m_powerDown.setSingleShot(true);
0876         m_powerDown.setInterval(1000);
0877     }
0878 
0879     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
0880     {
0881         if (event->type() == QEvent::MouseButtonPress) {
0882             if (input()->shortcuts()->processPointerPressed(event->modifiers(), event->buttons())) {
0883                 return true;
0884             }
0885         }
0886         return false;
0887     }
0888     bool wheelEvent(WheelEvent *event) override
0889     {
0890         if (event->modifiers() == Qt::NoModifier) {
0891             return false;
0892         }
0893         PointerAxisDirection direction = PointerAxisUp;
0894         if (event->angleDelta().x() < 0) {
0895             direction = PointerAxisRight;
0896         } else if (event->angleDelta().x() > 0) {
0897             direction = PointerAxisLeft;
0898         } else if (event->angleDelta().y() < 0) {
0899             direction = PointerAxisDown;
0900         } else if (event->angleDelta().y() > 0) {
0901             direction = PointerAxisUp;
0902         }
0903         return input()->shortcuts()->processAxis(event->modifiers(), direction);
0904     }
0905     bool keyEvent(KeyEvent *event) override
0906     {
0907         if (event->key() == Qt::Key_PowerOff) {
0908             const auto modifiers = static_cast<KeyEvent *>(event)->modifiersRelevantForGlobalShortcuts();
0909             if (event->type() == QEvent::KeyPress && !event->isAutoRepeat()) {
0910                 QObject::connect(&m_powerDown, &QTimer::timeout, input()->shortcuts(), [this, modifiers] {
0911                     QObject::disconnect(&m_powerDown, &QTimer::timeout, input()->shortcuts(), nullptr);
0912                     m_powerDown.stop();
0913                     input()->shortcuts()->processKey(modifiers, Qt::Key_PowerDown);
0914                 });
0915                 m_powerDown.start();
0916                 return true;
0917             } else if (event->type() == QEvent::KeyRelease) {
0918                 const bool ret = !m_powerDown.isActive() || input()->shortcuts()->processKey(modifiers, event->key());
0919                 m_powerDown.stop();
0920                 return ret;
0921             }
0922         } else if (event->type() == QEvent::KeyPress) {
0923             if (!waylandServer()->isKeyboardShortcutsInhibited()) {
0924                 return input()->shortcuts()->processKey(static_cast<KeyEvent *>(event)->modifiersRelevantForGlobalShortcuts(), event->key());
0925             }
0926         } else if (event->type() == QEvent::KeyRelease) {
0927             if (!waylandServer()->isKeyboardShortcutsInhibited()) {
0928                 return input()->shortcuts()->processKeyRelease(static_cast<KeyEvent *>(event)->modifiersRelevantForGlobalShortcuts(), event->key());
0929             }
0930         }
0931         return false;
0932     }
0933     bool swipeGestureBegin(int fingerCount, std::chrono::microseconds time) override
0934     {
0935         m_touchpadGestureFingerCount = fingerCount;
0936         if (m_touchpadGestureFingerCount >= 3) {
0937             input()->shortcuts()->processSwipeStart(DeviceType::Touchpad, fingerCount);
0938             return true;
0939         } else {
0940             return false;
0941         }
0942     }
0943     bool swipeGestureUpdate(const QPointF &delta, std::chrono::microseconds time) override
0944     {
0945         if (m_touchpadGestureFingerCount >= 3) {
0946             input()->shortcuts()->processSwipeUpdate(DeviceType::Touchpad, delta);
0947             return true;
0948         } else {
0949             return false;
0950         }
0951     }
0952     bool swipeGestureCancelled(std::chrono::microseconds time) override
0953     {
0954         if (m_touchpadGestureFingerCount >= 3) {
0955             input()->shortcuts()->processSwipeCancel(DeviceType::Touchpad);
0956             return true;
0957         } else {
0958             return false;
0959         }
0960     }
0961     bool swipeGestureEnd(std::chrono::microseconds time) override
0962     {
0963         if (m_touchpadGestureFingerCount >= 3) {
0964             input()->shortcuts()->processSwipeEnd(DeviceType::Touchpad);
0965             return true;
0966         } else {
0967             return false;
0968         }
0969     }
0970     bool pinchGestureBegin(int fingerCount, std::chrono::microseconds time) override
0971     {
0972         m_touchpadGestureFingerCount = fingerCount;
0973         if (m_touchpadGestureFingerCount >= 3) {
0974             input()->shortcuts()->processPinchStart(fingerCount);
0975             return true;
0976         } else {
0977             return false;
0978         }
0979     }
0980     bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QPointF &delta, std::chrono::microseconds time) override
0981     {
0982         if (m_touchpadGestureFingerCount >= 3) {
0983             input()->shortcuts()->processPinchUpdate(scale, angleDelta, delta);
0984             return true;
0985         } else {
0986             return false;
0987         }
0988     }
0989     bool pinchGestureEnd(std::chrono::microseconds time) override
0990     {
0991         if (m_touchpadGestureFingerCount >= 3) {
0992             input()->shortcuts()->processPinchEnd();
0993             return true;
0994         } else {
0995             return false;
0996         }
0997     }
0998     bool pinchGestureCancelled(std::chrono::microseconds time) override
0999     {
1000         if (m_touchpadGestureFingerCount >= 3) {
1001             input()->shortcuts()->processPinchCancel();
1002             return true;
1003         } else {
1004             return false;
1005         }
1006     }
1007     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1008     {
1009         if (m_gestureTaken) {
1010             input()->shortcuts()->processSwipeCancel(DeviceType::Touchscreen);
1011             m_gestureCancelled = true;
1012             return true;
1013         } else {
1014             m_touchPoints.insert(id, pos);
1015             if (m_touchPoints.count() == 1) {
1016                 m_lastTouchDownTime = time;
1017             } else {
1018                 if (time - m_lastTouchDownTime > 250ms) {
1019                     m_gestureCancelled = true;
1020                     return false;
1021                 }
1022                 m_lastTouchDownTime = time;
1023                 auto output = workspace()->outputAt(pos);
1024                 auto physicalSize = output->orientateSize(output->physicalSize());
1025                 if (!physicalSize.isValid()) {
1026                     physicalSize = QSize(190, 100);
1027                 }
1028                 float xfactor = physicalSize.width() / (float)output->geometry().width();
1029                 float yfactor = physicalSize.height() / (float)output->geometry().height();
1030                 bool distanceMatch = std::any_of(m_touchPoints.constBegin(), m_touchPoints.constEnd(), [pos, xfactor, yfactor](const auto &point) {
1031                     QPointF p = pos - point;
1032                     return std::abs(xfactor * p.x()) + std::abs(yfactor * p.y()) < 50;
1033                 });
1034                 if (!distanceMatch) {
1035                     m_gestureCancelled = true;
1036                     return false;
1037                 }
1038             }
1039             if (m_touchPoints.count() >= 3 && !m_gestureCancelled) {
1040                 m_gestureTaken = true;
1041                 m_syntheticCancel = true;
1042                 input()->processFilters(std::bind(&InputEventFilter::touchCancel, std::placeholders::_1));
1043                 m_syntheticCancel = false;
1044                 input()->shortcuts()->processSwipeStart(DeviceType::Touchscreen, m_touchPoints.count());
1045                 return true;
1046             }
1047         }
1048         return false;
1049     }
1050 
1051     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1052     {
1053         if (m_gestureTaken) {
1054             if (m_gestureCancelled) {
1055                 return true;
1056             }
1057             auto output = workspace()->outputAt(pos);
1058             const auto physicalSize = output->orientateSize(output->physicalSize());
1059             const float xfactor = physicalSize.width() / (float)output->geometry().width();
1060             const float yfactor = physicalSize.height() / (float)output->geometry().height();
1061 
1062             auto &point = m_touchPoints[id];
1063             const QPointF dist = pos - point;
1064             const QPointF delta = QPointF(xfactor * dist.x(), yfactor * dist.y());
1065             input()->shortcuts()->processSwipeUpdate(DeviceType::Touchscreen, 5 * delta / m_touchPoints.size());
1066             point = pos;
1067             return true;
1068         }
1069         return false;
1070     }
1071 
1072     bool touchUp(qint32 id, std::chrono::microseconds time) override
1073     {
1074         m_touchPoints.remove(id);
1075         if (m_gestureTaken) {
1076             if (!m_gestureCancelled) {
1077                 input()->shortcuts()->processSwipeEnd(DeviceType::Touchscreen);
1078                 m_gestureCancelled = true;
1079             }
1080             m_gestureTaken &= m_touchPoints.count() > 0;
1081             m_gestureCancelled &= m_gestureTaken;
1082             return true;
1083         } else {
1084             m_gestureCancelled &= m_touchPoints.count() > 0;
1085             return false;
1086         }
1087     }
1088 
1089     bool touchCancel() override
1090     {
1091         if (m_syntheticCancel) {
1092             return false;
1093         }
1094         const bool oldGestureTaken = m_gestureTaken;
1095         m_gestureTaken = false;
1096         m_gestureCancelled = false;
1097         m_touchPoints.clear();
1098         return oldGestureTaken;
1099     }
1100 
1101     bool touchFrame() override
1102     {
1103         return m_gestureTaken;
1104     }
1105 
1106 private:
1107     bool m_gestureTaken = false;
1108     bool m_gestureCancelled = false;
1109     bool m_syntheticCancel = false;
1110     std::chrono::microseconds m_lastTouchDownTime = std::chrono::microseconds::zero();
1111     QPointF m_lastAverageDistance;
1112     QMap<int32_t, QPointF> m_touchPoints;
1113     int m_touchpadGestureFingerCount = 0;
1114 
1115     QTimer m_powerDown;
1116 };
1117 
1118 namespace
1119 {
1120 
1121 enum class MouseAction {
1122     ModifierOnly,
1123     ModifierAndWindow
1124 };
1125 std::pair<bool, bool> performWindowMouseAction(QMouseEvent *event, Window *window, MouseAction action = MouseAction::ModifierOnly)
1126 {
1127     Options::MouseCommand command = Options::MouseNothing;
1128     bool wasAction = false;
1129     if (static_cast<MouseEvent *>(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) {
1130         if (!input()->pointer()->isConstrained() && !workspace()->globalShortcutsDisabled()) {
1131             wasAction = true;
1132             switch (event->button()) {
1133             case Qt::LeftButton:
1134                 command = options->commandAll1();
1135                 break;
1136             case Qt::MiddleButton:
1137                 command = options->commandAll2();
1138                 break;
1139             case Qt::RightButton:
1140                 command = options->commandAll3();
1141                 break;
1142             default:
1143                 // nothing
1144                 break;
1145             }
1146         }
1147     } else {
1148         if (action == MouseAction::ModifierAndWindow) {
1149             command = window->getMouseCommand(event->button(), &wasAction);
1150         }
1151     }
1152     if (wasAction) {
1153         return std::make_pair(wasAction, !window->performMouseCommand(command, event->globalPos()));
1154     }
1155     return std::make_pair(wasAction, false);
1156 }
1157 
1158 std::pair<bool, bool> performWindowWheelAction(QWheelEvent *event, Window *window, MouseAction action = MouseAction::ModifierOnly)
1159 {
1160     bool wasAction = false;
1161     Options::MouseCommand command = Options::MouseNothing;
1162     if (static_cast<WheelEvent *>(event)->modifiersRelevantForGlobalShortcuts() == options->commandAllModifier()) {
1163         if (!input()->pointer()->isConstrained() && !workspace()->globalShortcutsDisabled()) {
1164             wasAction = true;
1165             command = options->operationWindowMouseWheel(-1 * event->angleDelta().y());
1166         }
1167     } else {
1168         if (action == MouseAction::ModifierAndWindow) {
1169             command = window->getWheelCommand(Qt::Vertical, &wasAction);
1170         }
1171     }
1172     if (wasAction) {
1173         return std::make_pair(wasAction, !window->performMouseCommand(command, event->globalPosition()));
1174     }
1175     return std::make_pair(wasAction, false);
1176 }
1177 
1178 }
1179 
1180 class InternalWindowEventFilter : public InputEventFilter
1181 {
1182     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
1183     {
1184         if (!input()->pointer()->focus() || !input()->pointer()->focus()->isInternal()) {
1185             return false;
1186         }
1187         QWindow *internal = static_cast<InternalWindow *>(input()->pointer()->focus())->handle();
1188         if (!internal) {
1189             // the handle can be nullptr if the tooltip gets closed while focus updates are blocked
1190             return false;
1191         }
1192         QMouseEvent mouseEvent(event->type(),
1193                                event->pos() - internal->position(),
1194                                event->globalPos(),
1195                                event->button(), event->buttons(), event->modifiers());
1196         QCoreApplication::sendEvent(internal, &mouseEvent);
1197         return mouseEvent.isAccepted();
1198     }
1199     bool wheelEvent(WheelEvent *event) override
1200     {
1201         if (!input()->pointer()->focus() || !input()->pointer()->focus()->isInternal()) {
1202             return false;
1203         }
1204         QWindow *internal = static_cast<InternalWindow *>(input()->pointer()->focus())->handle();
1205         const QPointF localPos = event->globalPosition() - internal->position();
1206         QWheelEvent wheelEvent(localPos, event->globalPosition(), QPoint(),
1207                                event->angleDelta() * -1,
1208                                event->buttons(),
1209                                event->modifiers(),
1210                                Qt::NoScrollPhase,
1211                                false);
1212         QCoreApplication::sendEvent(internal, &wheelEvent);
1213         return wheelEvent.isAccepted();
1214     }
1215     bool keyEvent(KeyEvent *event) override
1216     {
1217         const QList<InternalWindow *> &windows = workspace()->internalWindows();
1218         QWindow *found = nullptr;
1219         for (auto it = windows.crbegin(); it != windows.crend(); ++it) {
1220             if (QWindow *w = (*it)->handle()) {
1221                 if (!w->isVisible()) {
1222                     continue;
1223                 }
1224                 if (!workspace()->geometry().contains(w->geometry())) {
1225                     continue;
1226                 }
1227                 if (w->property("_q_showWithoutActivating").toBool()) {
1228                     continue;
1229                 }
1230                 if (w->property("outputOnly").toBool()) {
1231                     continue;
1232                 }
1233                 if (w->flags().testFlag(Qt::ToolTip)) {
1234                     continue;
1235                 }
1236                 found = w;
1237                 break;
1238             }
1239         }
1240         if (QGuiApplication::focusWindow() != found) {
1241             QWindowSystemInterface::handleWindowActivated(found);
1242         }
1243         if (!found) {
1244             return false;
1245         }
1246         auto xkb = input()->keyboard()->xkb();
1247         Qt::Key key = xkb->toQtKey(xkb->toKeysym(event->nativeScanCode()),
1248                                    event->nativeScanCode(),
1249                                    Qt::KeyboardModifiers(),
1250                                    true /* workaround for QTBUG-62102 */);
1251         QKeyEvent internalEvent(event->type(), key,
1252                                 event->modifiers(), event->nativeScanCode(), event->nativeVirtualKey(),
1253                                 event->nativeModifiers(), event->text());
1254         internalEvent.setAccepted(false);
1255         if (QCoreApplication::sendEvent(found, &internalEvent)) {
1256             waylandServer()->seat()->setFocusedKeyboardSurface(nullptr);
1257             passToWaylandServer(event);
1258             return true;
1259         }
1260         return false;
1261     }
1262 
1263     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1264     {
1265         auto seat = waylandServer()->seat();
1266         if (seat->isTouchSequence()) {
1267             // something else is getting the events
1268             return false;
1269         }
1270         auto touch = input()->touch();
1271         if (touch->internalPressId() != -1) {
1272             // already on internal window, ignore further touch points, but filter out
1273             m_pressedIds.insert(id);
1274             return true;
1275         }
1276         // a new touch point
1277         seat->setTimestamp(time);
1278         if (!input()->touch()->focus() || !input()->touch()->focus()->isInternal()) {
1279             return false;
1280         }
1281         touch->setInternalPressId(id);
1282         // Qt's touch event API is rather complex, let's do fake mouse events instead
1283         QWindow *internal = static_cast<InternalWindow *>(input()->touch()->focus())->handle();
1284         m_lastGlobalTouchPos = pos;
1285         m_lastLocalTouchPos = pos - internal->position();
1286 
1287         QEnterEvent enterEvent(m_lastLocalTouchPos, m_lastLocalTouchPos, pos);
1288         QCoreApplication::sendEvent(internal, &enterEvent);
1289 
1290         QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers());
1291         e.setAccepted(false);
1292         QCoreApplication::sendEvent(internal, &e);
1293         return true;
1294     }
1295     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1296     {
1297         auto touch = input()->touch();
1298         if (!input()->touch()->focus() || !input()->touch()->focus()->isInternal()) {
1299             return false;
1300         }
1301         if (touch->internalPressId() == -1) {
1302             return false;
1303         }
1304         waylandServer()->seat()->setTimestamp(time);
1305         if (touch->internalPressId() != qint32(id) || m_pressedIds.contains(id)) {
1306             // ignore, but filter out
1307             return true;
1308         }
1309         QWindow *internal = static_cast<InternalWindow *>(input()->touch()->focus())->handle();
1310         m_lastGlobalTouchPos = pos;
1311         m_lastLocalTouchPos = pos - QPointF(internal->x(), internal->y());
1312 
1313         QMouseEvent e(QEvent::MouseMove, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers());
1314         QCoreApplication::instance()->sendEvent(internal, &e);
1315         return true;
1316     }
1317     bool touchUp(qint32 id, std::chrono::microseconds time) override
1318     {
1319         auto touch = input()->touch();
1320         const bool removed = m_pressedIds.remove(id);
1321         if (touch->internalPressId() == -1) {
1322             return removed;
1323         }
1324         waylandServer()->seat()->setTimestamp(time);
1325         if (touch->internalPressId() != qint32(id)) {
1326             // ignore, but filter out
1327             return true;
1328         }
1329         if (!input()->touch()->focus() || !input()->touch()->focus()->isInternal()) {
1330             return removed;
1331         }
1332         QWindow *internal = static_cast<InternalWindow *>(input()->touch()->focus())->handle();
1333         // send mouse up
1334         QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers());
1335         e.setAccepted(false);
1336         QCoreApplication::sendEvent(internal, &e);
1337 
1338         QEvent leaveEvent(QEvent::Leave);
1339         QCoreApplication::sendEvent(internal, &leaveEvent);
1340 
1341         m_lastGlobalTouchPos = QPointF();
1342         m_lastLocalTouchPos = QPointF();
1343         input()->touch()->setInternalPressId(-1);
1344         return true;
1345     }
1346 
1347 private:
1348     QSet<qint32> m_pressedIds;
1349     QPointF m_lastGlobalTouchPos;
1350     QPointF m_lastLocalTouchPos;
1351 };
1352 
1353 class MouseWheelAccumulator
1354 {
1355 public:
1356     float accumulate(WheelEvent *event)
1357     {
1358         m_scrollV120 += event->deltaV120();
1359         m_scrollDistance += event->delta();
1360         if (std::abs(m_scrollV120) >= 120 || (!event->deltaV120() && std::abs(m_scrollDistance) >= 15)) {
1361             float ret = m_scrollDistance;
1362             m_scrollV120 = 0;
1363             m_scrollDistance = 0;
1364             return ret;
1365         } else {
1366             return 0;
1367         }
1368     }
1369 
1370 private:
1371     float m_scrollDistance = 0;
1372     int m_scrollV120 = 0;
1373 };
1374 
1375 class DecorationEventFilter : public InputEventFilter
1376 {
1377 public:
1378     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
1379     {
1380         auto decoration = input()->pointer()->decoration();
1381         if (!decoration) {
1382             return false;
1383         }
1384         const QPointF p = event->screenPos() - decoration->window()->pos();
1385         switch (event->type()) {
1386         case QEvent::MouseMove: {
1387             QHoverEvent e(QEvent::HoverMove, p, p);
1388             QCoreApplication::instance()->sendEvent(decoration->decoration(), &e);
1389             decoration->window()->processDecorationMove(p, event->screenPos());
1390             return true;
1391         }
1392         case QEvent::MouseButtonPress:
1393         case QEvent::MouseButtonRelease: {
1394             const auto actionResult = performWindowMouseAction(event, decoration->window());
1395             if (actionResult.first) {
1396                 return actionResult.second;
1397             }
1398             QMouseEvent e(event->type(), p, event->screenPos(), event->button(), event->buttons(), event->modifiers());
1399             e.setTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(event->timestamp()).count());
1400             e.setAccepted(false);
1401             QCoreApplication::sendEvent(decoration->decoration(), &e);
1402             if (!e.isAccepted() && event->type() == QEvent::MouseButtonPress) {
1403                 decoration->window()->processDecorationButtonPress(&e);
1404             }
1405             if (event->type() == QEvent::MouseButtonRelease) {
1406                 decoration->window()->processDecorationButtonRelease(&e);
1407             }
1408             return true;
1409         }
1410         default:
1411             break;
1412         }
1413         return false;
1414     }
1415     bool wheelEvent(WheelEvent *event) override
1416     {
1417         auto decoration = input()->pointer()->decoration();
1418         if (!decoration) {
1419             return false;
1420         }
1421         if (event->angleDelta().y() != 0) {
1422             // client window action only on vertical scrolling
1423             const auto actionResult = performWindowWheelAction(event, decoration->window());
1424             if (actionResult.first) {
1425                 return actionResult.second;
1426             }
1427         }
1428         const QPointF localPos = event->globalPosition() - decoration->window()->pos();
1429         const Qt::Orientation orientation = (event->angleDelta().x() != 0) ? Qt::Horizontal : Qt::Vertical;
1430         QWheelEvent e(localPos, event->globalPosition(), QPoint(),
1431                       event->angleDelta(),
1432                       event->buttons(),
1433                       event->modifiers(),
1434                       Qt::NoScrollPhase,
1435                       false);
1436         e.setAccepted(false);
1437         QCoreApplication::sendEvent(decoration, &e);
1438         if (e.isAccepted()) {
1439             return true;
1440         }
1441         if ((orientation == Qt::Vertical) && decoration->window()->titlebarPositionUnderMouse()) {
1442             if (float delta = m_accumulator.accumulate(event)) {
1443                 decoration->window()->performMouseCommand(options->operationTitlebarMouseWheel(delta * -1),
1444                                                           event->globalPosition());
1445             }
1446         }
1447         return true;
1448     }
1449     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1450     {
1451         auto seat = waylandServer()->seat();
1452         if (seat->isTouchSequence()) {
1453             return false;
1454         }
1455         if (input()->touch()->decorationPressId() != -1) {
1456             // already on a decoration, ignore further touch points, but filter out
1457             return true;
1458         }
1459         seat->setTimestamp(time);
1460         auto decoration = input()->touch()->decoration();
1461         if (!decoration) {
1462             return false;
1463         }
1464 
1465         input()->touch()->setDecorationPressId(id);
1466         m_lastGlobalTouchPos = pos;
1467         m_lastLocalTouchPos = pos - decoration->window()->pos();
1468 
1469         QHoverEvent hoverEvent(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos);
1470         QCoreApplication::sendEvent(decoration->decoration(), &hoverEvent);
1471 
1472         QMouseEvent e(QEvent::MouseButtonPress, m_lastLocalTouchPos, pos, Qt::LeftButton, Qt::LeftButton, input()->keyboardModifiers());
1473         e.setAccepted(false);
1474         QCoreApplication::sendEvent(decoration->decoration(), &e);
1475         if (!e.isAccepted()) {
1476             decoration->window()->processDecorationButtonPress(&e);
1477         }
1478         return true;
1479     }
1480     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1481     {
1482         auto decoration = input()->touch()->decoration();
1483         if (!decoration) {
1484             return false;
1485         }
1486         if (input()->touch()->decorationPressId() == -1) {
1487             return false;
1488         }
1489         if (input()->touch()->decorationPressId() != qint32(id)) {
1490             // ignore, but filter out
1491             return true;
1492         }
1493         m_lastGlobalTouchPos = pos;
1494         m_lastLocalTouchPos = pos - decoration->window()->pos();
1495 
1496         QHoverEvent e(QEvent::HoverMove, m_lastLocalTouchPos, m_lastLocalTouchPos);
1497         QCoreApplication::instance()->sendEvent(decoration->decoration(), &e);
1498         decoration->window()->processDecorationMove(m_lastLocalTouchPos, pos);
1499         return true;
1500     }
1501     bool touchUp(qint32 id, std::chrono::microseconds time) override
1502     {
1503         auto decoration = input()->touch()->decoration();
1504         if (!decoration) {
1505             // can happen when quick tiling
1506             if (input()->touch()->decorationPressId() == id) {
1507                 m_lastGlobalTouchPos = QPointF();
1508                 m_lastLocalTouchPos = QPointF();
1509                 input()->touch()->setDecorationPressId(-1);
1510                 return true;
1511             }
1512             return false;
1513         }
1514         if (input()->touch()->decorationPressId() == -1) {
1515             return false;
1516         }
1517         if (input()->touch()->decorationPressId() != qint32(id)) {
1518             // ignore, but filter out
1519             return true;
1520         }
1521 
1522         // send mouse up
1523         QMouseEvent e(QEvent::MouseButtonRelease, m_lastLocalTouchPos, m_lastGlobalTouchPos, Qt::LeftButton, Qt::MouseButtons(), input()->keyboardModifiers());
1524         e.setAccepted(false);
1525         QCoreApplication::sendEvent(decoration->decoration(), &e);
1526         decoration->window()->processDecorationButtonRelease(&e);
1527 
1528         QHoverEvent leaveEvent(QEvent::HoverLeave, QPointF(), QPointF());
1529         QCoreApplication::sendEvent(decoration->decoration(), &leaveEvent);
1530 
1531         m_lastGlobalTouchPos = QPointF();
1532         m_lastLocalTouchPos = QPointF();
1533         input()->touch()->setDecorationPressId(-1);
1534         return true;
1535     }
1536     bool tabletToolEvent(TabletEvent *event) override
1537     {
1538         auto decoration = input()->tablet()->decoration();
1539         if (!decoration) {
1540             return false;
1541         }
1542         const QPointF p = event->globalPosF() - decoration->window()->pos();
1543         switch (event->type()) {
1544         case QEvent::TabletMove:
1545         case QEvent::TabletEnterProximity: {
1546             QHoverEvent e(QEvent::HoverMove, p, p);
1547             QCoreApplication::instance()->sendEvent(decoration->decoration(), &e);
1548             decoration->window()->processDecorationMove(p, event->globalPosF());
1549             break;
1550         }
1551         case QEvent::TabletPress:
1552         case QEvent::TabletRelease: {
1553             const bool isPressed = event->type() == QEvent::TabletPress;
1554             QMouseEvent e(isPressed ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease,
1555                           p,
1556                           event->globalPosF(),
1557                           Qt::LeftButton,
1558                           isPressed ? Qt::LeftButton : Qt::MouseButtons(),
1559                           input()->keyboardModifiers());
1560             e.setAccepted(false);
1561             QCoreApplication::sendEvent(decoration->decoration(), &e);
1562             if (!e.isAccepted() && isPressed) {
1563                 decoration->window()->processDecorationButtonPress(&e);
1564             }
1565             if (event->type() == QEvent::TabletRelease) {
1566                 decoration->window()->processDecorationButtonRelease(&e);
1567             }
1568             break;
1569         }
1570         case QEvent::TabletLeaveProximity: {
1571             QHoverEvent leaveEvent(QEvent::HoverLeave, QPointF(), QPointF());
1572             QCoreApplication::sendEvent(decoration->decoration(), &leaveEvent);
1573             break;
1574         }
1575         default:
1576             break;
1577         }
1578         // Let TabletInputFilter receive the event, so the tablet can be registered and the cursor position can be updated.
1579         return false;
1580     }
1581 
1582 private:
1583     QPointF m_lastGlobalTouchPos;
1584     QPointF m_lastLocalTouchPos;
1585     MouseWheelAccumulator m_accumulator;
1586 };
1587 
1588 #if KWIN_BUILD_TABBOX
1589 class TabBoxInputFilter : public InputEventFilter
1590 {
1591 public:
1592     bool pointerEvent(MouseEvent *event, quint32 button) override
1593     {
1594         if (!workspace()->tabbox() || !workspace()->tabbox()->isGrabbed()) {
1595             return false;
1596         }
1597         return workspace()->tabbox()->handleMouseEvent(event);
1598     }
1599     bool keyEvent(KeyEvent *event) override
1600     {
1601         if (!workspace()->tabbox() || !workspace()->tabbox()->isGrabbed()) {
1602             return false;
1603         }
1604         auto seat = waylandServer()->seat();
1605         seat->setFocusedKeyboardSurface(nullptr);
1606         input()->pointer()->setEnableConstraints(false);
1607         // pass the key event to the seat, so that it has a proper model of the currently hold keys
1608         // this is important for combinations like alt+shift to ensure that shift is not considered pressed
1609         passToWaylandServer(event);
1610 
1611         if (event->type() == QEvent::KeyPress) {
1612             workspace()->tabbox()->keyPress(event->modifiersRelevantForTabBox() | event->key());
1613         } else if (static_cast<KeyEvent *>(event)->modifiersRelevantForGlobalShortcuts() == Qt::NoModifier) {
1614             workspace()->tabbox()->modifiersReleased();
1615         }
1616         return true;
1617     }
1618     bool wheelEvent(WheelEvent *event) override
1619     {
1620         if (!workspace()->tabbox() || !workspace()->tabbox()->isGrabbed()) {
1621             return false;
1622         }
1623         return workspace()->tabbox()->handleWheelEvent(event);
1624     }
1625 };
1626 #endif
1627 
1628 class ScreenEdgeInputFilter : public InputEventFilter
1629 {
1630 public:
1631     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
1632     {
1633         workspace()->screenEdges()->isEntered(event);
1634         // always forward
1635         return false;
1636     }
1637     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1638     {
1639         // TODO: better check whether a touch sequence is in progress
1640         if (m_touchInProgress || waylandServer()->seat()->isTouchSequence()) {
1641             // cancel existing touch
1642             workspace()->screenEdges()->gestureRecognizer()->cancelSwipeGesture();
1643             m_touchInProgress = false;
1644             m_id = 0;
1645             return false;
1646         }
1647         if (workspace()->screenEdges()->gestureRecognizer()->startSwipeGesture(pos) > 0) {
1648             m_touchInProgress = true;
1649             m_id = id;
1650             m_lastPos = pos;
1651             return true;
1652         }
1653         return false;
1654     }
1655     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1656     {
1657         if (m_touchInProgress && m_id == id) {
1658             workspace()->screenEdges()->gestureRecognizer()->updateSwipeGesture(pos - m_lastPos);
1659             m_lastPos = pos;
1660             return true;
1661         }
1662         return false;
1663     }
1664     bool touchUp(qint32 id, std::chrono::microseconds time) override
1665     {
1666         if (m_touchInProgress && m_id == id) {
1667             workspace()->screenEdges()->gestureRecognizer()->endSwipeGesture();
1668             m_touchInProgress = false;
1669             return true;
1670         }
1671         return false;
1672     }
1673 
1674 private:
1675     bool m_touchInProgress = false;
1676     qint32 m_id = 0;
1677     QPointF m_lastPos;
1678 };
1679 
1680 /**
1681  * This filter implements window actions. If the event should not be passed to the
1682  * current pointer window it will filter out the event
1683  */
1684 class WindowActionInputFilter : public InputEventFilter
1685 {
1686 public:
1687     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
1688     {
1689         if (event->type() != QEvent::MouseButtonPress) {
1690             return false;
1691         }
1692         Window *window = input()->pointer()->focus();
1693         if (!window || !window->isClient()) {
1694             return false;
1695         }
1696         const auto actionResult = performWindowMouseAction(event, window, MouseAction::ModifierAndWindow);
1697         if (actionResult.first) {
1698             return actionResult.second;
1699         }
1700         return false;
1701     }
1702     bool wheelEvent(WheelEvent *event) override
1703     {
1704         if (event->angleDelta().y() == 0) {
1705             // only actions on vertical scroll
1706             return false;
1707         }
1708         Window *window = input()->pointer()->focus();
1709         if (!window || !window->isClient()) {
1710             return false;
1711         }
1712         const auto actionResult = performWindowWheelAction(event, window, MouseAction::ModifierAndWindow);
1713         if (actionResult.first) {
1714             return actionResult.second;
1715         }
1716         return false;
1717     }
1718     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1719     {
1720         auto seat = waylandServer()->seat();
1721         if (seat->isTouchSequence()) {
1722             return false;
1723         }
1724         Window *window = input()->touch()->focus();
1725         if (!window || !window->isClient()) {
1726             return false;
1727         }
1728         bool wasAction = false;
1729         const Options::MouseCommand command = window->getMouseCommand(Qt::LeftButton, &wasAction);
1730         if (wasAction) {
1731             return !window->performMouseCommand(command, pos);
1732         }
1733         return false;
1734     }
1735     bool tabletToolEvent(TabletEvent *event) override
1736     {
1737         if (event->type() != QEvent::TabletPress) {
1738             return false;
1739         }
1740         Window *window = input()->tablet()->focus();
1741         if (!window || !window->isClient()) {
1742             return false;
1743         }
1744         bool wasAction = false;
1745         const Options::MouseCommand command = window->getMouseCommand(Qt::LeftButton, &wasAction);
1746         if (wasAction) {
1747             return !window->performMouseCommand(command, event->globalPos());
1748         }
1749         return false;
1750     }
1751 };
1752 
1753 class InputKeyboardFilter : public InputEventFilter
1754 {
1755 public:
1756     bool keyEvent(KeyEvent *event) override
1757     {
1758         return passToInputMethod(event);
1759     }
1760 };
1761 
1762 /**
1763  * The remaining default input filter which forwards events to other windows
1764  */
1765 class ForwardInputFilter : public InputEventFilter
1766 {
1767 public:
1768     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
1769     {
1770         auto seat = waylandServer()->seat();
1771         seat->setTimestamp(event->timestamp());
1772         switch (event->type()) {
1773         case QEvent::MouseMove: {
1774             seat->notifyPointerMotion(event->globalPos());
1775             MouseEvent *e = static_cast<MouseEvent *>(event);
1776             if (!e->delta().isNull()) {
1777                 seat->relativePointerMotion(e->delta(), e->deltaUnaccelerated(), e->timestamp());
1778             }
1779             seat->notifyPointerFrame();
1780             break;
1781         }
1782         case QEvent::MouseButtonPress:
1783             seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Pressed);
1784             seat->notifyPointerFrame();
1785             break;
1786         case QEvent::MouseButtonRelease:
1787             seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Released);
1788             seat->notifyPointerFrame();
1789             break;
1790         default:
1791             break;
1792         }
1793         return true;
1794     }
1795     bool wheelEvent(WheelEvent *event) override
1796     {
1797         auto seat = waylandServer()->seat();
1798         seat->setTimestamp(event->timestamp());
1799         auto _event = static_cast<WheelEvent *>(event);
1800         seat->notifyPointerAxis(_event->orientation(), _event->delta(), _event->deltaV120(),
1801                                 kwinAxisSourceToKWaylandAxisSource(_event->axisSource()));
1802         seat->notifyPointerFrame();
1803         return true;
1804     }
1805     bool keyEvent(KeyEvent *event) override
1806     {
1807         if (event->isAutoRepeat()) {
1808             // handled by Wayland client
1809             return false;
1810         }
1811         auto seat = waylandServer()->seat();
1812         input()->keyboard()->update();
1813         seat->setTimestamp(event->timestamp());
1814         passToWaylandServer(event);
1815         return true;
1816     }
1817     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1818     {
1819         auto seat = waylandServer()->seat();
1820         seat->setTimestamp(time);
1821         seat->notifyTouchDown(id, pos);
1822         return true;
1823     }
1824     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
1825     {
1826         auto seat = waylandServer()->seat();
1827         seat->setTimestamp(time);
1828         seat->notifyTouchMotion(id, pos);
1829         return true;
1830     }
1831     bool touchUp(qint32 id, std::chrono::microseconds time) override
1832     {
1833         auto seat = waylandServer()->seat();
1834         seat->setTimestamp(time);
1835         seat->notifyTouchUp(id);
1836         return true;
1837     }
1838     bool touchCancel() override
1839     {
1840         waylandServer()->seat()->notifyTouchCancel();
1841         return true;
1842     }
1843     bool touchFrame() override
1844     {
1845         waylandServer()->seat()->notifyTouchFrame();
1846         return true;
1847     }
1848     bool pinchGestureBegin(int fingerCount, std::chrono::microseconds time) override
1849     {
1850         auto seat = waylandServer()->seat();
1851         seat->setTimestamp(time);
1852         seat->startPointerPinchGesture(fingerCount);
1853         return true;
1854     }
1855     bool pinchGestureUpdate(qreal scale, qreal angleDelta, const QPointF &delta, std::chrono::microseconds time) override
1856     {
1857         auto seat = waylandServer()->seat();
1858         seat->setTimestamp(time);
1859         seat->updatePointerPinchGesture(delta, scale, angleDelta);
1860         return true;
1861     }
1862     bool pinchGestureEnd(std::chrono::microseconds time) override
1863     {
1864         auto seat = waylandServer()->seat();
1865         seat->setTimestamp(time);
1866         seat->endPointerPinchGesture();
1867         return true;
1868     }
1869     bool pinchGestureCancelled(std::chrono::microseconds time) override
1870     {
1871         auto seat = waylandServer()->seat();
1872         seat->setTimestamp(time);
1873         seat->cancelPointerPinchGesture();
1874         return true;
1875     }
1876 
1877     bool swipeGestureBegin(int fingerCount, std::chrono::microseconds time) override
1878     {
1879         auto seat = waylandServer()->seat();
1880         seat->setTimestamp(time);
1881         seat->startPointerSwipeGesture(fingerCount);
1882         return true;
1883     }
1884     bool swipeGestureUpdate(const QPointF &delta, std::chrono::microseconds time) override
1885     {
1886         auto seat = waylandServer()->seat();
1887         seat->setTimestamp(time);
1888         seat->updatePointerSwipeGesture(delta);
1889         return true;
1890     }
1891     bool swipeGestureEnd(std::chrono::microseconds time) override
1892     {
1893         auto seat = waylandServer()->seat();
1894         seat->setTimestamp(time);
1895         seat->endPointerSwipeGesture();
1896         return true;
1897     }
1898     bool swipeGestureCancelled(std::chrono::microseconds time) override
1899     {
1900         auto seat = waylandServer()->seat();
1901         seat->setTimestamp(time);
1902         seat->cancelPointerSwipeGesture();
1903         return true;
1904     }
1905     bool holdGestureBegin(int fingerCount, std::chrono::microseconds time) override
1906     {
1907         auto seat = waylandServer()->seat();
1908         seat->setTimestamp(time);
1909         seat->startPointerHoldGesture(fingerCount);
1910         return true;
1911     }
1912     bool holdGestureEnd(std::chrono::microseconds time) override
1913     {
1914         auto seat = waylandServer()->seat();
1915         seat->setTimestamp(time);
1916         seat->endPointerHoldGesture();
1917         return true;
1918     }
1919     bool holdGestureCancelled(std::chrono::microseconds time) override
1920     {
1921         auto seat = waylandServer()->seat();
1922         seat->setTimestamp(time);
1923         seat->cancelPointerHoldGesture();
1924         return true;
1925     }
1926 };
1927 
1928 static KWaylandServer::SeatInterface *findSeat()
1929 {
1930     auto server = waylandServer();
1931     if (!server) {
1932         return nullptr;
1933     }
1934     return server->seat();
1935 }
1936 
1937 class SurfaceCursor : public Cursor
1938 {
1939 public:
1940     explicit SurfaceCursor(KWaylandServer::TabletToolV2Interface *tool)
1941         : Cursor(tool)
1942         , m_source(std::make_unique<ImageCursorSource>())
1943     {
1944         setSource(m_source.get());
1945         connect(tool, &KWaylandServer::TabletToolV2Interface::cursorChanged, this, [this](KWaylandServer::TabletCursorV2 *tcursor) {
1946             if (!tcursor || tcursor->enteredSerial() == 0) {
1947                 static WaylandCursorImage defaultCursor;
1948                 defaultCursor.loadThemeCursor(CursorShape(Qt::CrossCursor), m_source.get());
1949                 return;
1950             }
1951             auto cursorSurface = tcursor->surface();
1952             if (!cursorSurface) {
1953                 m_source->update(QImage(), QPoint());
1954                 return;
1955             }
1956 
1957             updateCursorSurface(cursorSurface, tcursor->hotspot());
1958         });
1959     }
1960 
1961     void updateCursorSurface(KWaylandServer::SurfaceInterface *surface, const QPoint &hotspot)
1962     {
1963         if (m_surface == surface && hotspot == m_hotspot) {
1964             return;
1965         }
1966 
1967         if (m_surface) {
1968             disconnect(m_surface, nullptr, this, nullptr);
1969         }
1970         m_surface = surface;
1971         m_hotspot = hotspot;
1972         connect(m_surface, &KWaylandServer::SurfaceInterface::committed, this, &SurfaceCursor::refresh);
1973 
1974         refresh();
1975     }
1976 
1977 private:
1978     void refresh()
1979     {
1980         auto buffer = qobject_cast<KWaylandServer::ShmClientBuffer *>(m_surface->buffer());
1981         if (!buffer) {
1982             m_source->update(QImage(), QPoint());
1983             return;
1984         }
1985 
1986         QImage cursorImage;
1987         cursorImage = buffer->data().copy();
1988         cursorImage.setDevicePixelRatio(m_surface->bufferScale());
1989         m_source->update(cursorImage, m_hotspot);
1990     }
1991 
1992     QPointer<KWaylandServer::SurfaceInterface> m_surface;
1993     std::unique_ptr<ImageCursorSource> m_source;
1994     QPoint m_hotspot;
1995 };
1996 
1997 /**
1998  * Handles input coming from a tablet device (e.g. wacom) often with a pen
1999  */
2000 class TabletInputFilter : public QObject, public InputEventFilter
2001 {
2002 public:
2003     TabletInputFilter()
2004     {
2005         const auto devices = input()->devices();
2006         for (InputDevice *device : devices) {
2007             integrateDevice(device);
2008         }
2009         connect(input(), &InputRedirection::deviceAdded, this, &TabletInputFilter::integrateDevice);
2010         connect(input(), &InputRedirection::deviceRemoved, this, &TabletInputFilter::removeDevice);
2011 
2012         auto tabletNextOutput = new QAction(this);
2013         tabletNextOutput->setProperty("componentName", QStringLiteral("kwin"));
2014         tabletNextOutput->setText(i18n("Move the tablet to the next output"));
2015         tabletNextOutput->setObjectName(QStringLiteral("Move Tablet to Next Output"));
2016         KGlobalAccel::setGlobalShortcut(tabletNextOutput, QList<QKeySequence>());
2017         connect(tabletNextOutput, &QAction::triggered, this, &TabletInputFilter::trackNextOutput);
2018     }
2019 
2020     static KWaylandServer::TabletSeatV2Interface *findTabletSeat()
2021     {
2022         auto server = waylandServer();
2023         if (!server) {
2024             return nullptr;
2025         }
2026         KWaylandServer::TabletManagerV2Interface *manager = server->tabletManagerV2();
2027         return manager->seat(findSeat());
2028     }
2029 
2030     void integrateDevice(InputDevice *inputDevice)
2031     {
2032         auto device = qobject_cast<LibInput::Device *>(inputDevice);
2033         if (!device || (!device->isTabletTool() && !device->isTabletPad())) {
2034             return;
2035         }
2036 
2037         KWaylandServer::TabletSeatV2Interface *tabletSeat = findTabletSeat();
2038         if (!tabletSeat) {
2039             qCCritical(KWIN_CORE) << "Could not find tablet seat";
2040             return;
2041         }
2042         struct udev_device *const udev_device = libinput_device_get_udev_device(device->device());
2043         const char *devnode = udev_device_get_syspath(udev_device);
2044 
2045         auto deviceGroup = libinput_device_get_device_group(device->device());
2046         auto tablet = static_cast<KWaylandServer::TabletV2Interface *>(libinput_device_group_get_user_data(deviceGroup));
2047         if (!tablet) {
2048             tablet = tabletSeat->addTablet(device->vendor(), device->product(), device->sysName(), device->name(), {QString::fromUtf8(devnode)});
2049             libinput_device_group_set_user_data(deviceGroup, tablet);
2050         }
2051 
2052         if (device->isTabletPad()) {
2053             const int buttonsCount = libinput_device_tablet_pad_get_num_buttons(device->device());
2054             const int ringsCount = libinput_device_tablet_pad_get_num_rings(device->device());
2055             const int stripsCount = libinput_device_tablet_pad_get_num_strips(device->device());
2056             const int modes = libinput_device_tablet_pad_get_num_mode_groups(device->device());
2057 
2058             auto firstGroup = libinput_device_tablet_pad_get_mode_group(device->device(), 0);
2059             tabletSeat->addTabletPad(device->sysName(), device->name(), {QString::fromUtf8(devnode)}, buttonsCount, ringsCount, stripsCount, modes, libinput_tablet_pad_mode_group_get_mode(firstGroup), tablet);
2060         }
2061     }
2062 
2063     static void trackNextOutput()
2064     {
2065         const auto outputs = workspace()->outputs();
2066         if (outputs.isEmpty()) {
2067             return;
2068         }
2069 
2070         int tabletToolCount = 0;
2071         InputDevice *changedDevice = nullptr;
2072         const auto devices = input()->devices();
2073         for (const auto device : devices) {
2074             if (!device->isTabletTool()) {
2075                 continue;
2076             }
2077 
2078             tabletToolCount++;
2079             if (device->outputName().isEmpty()) {
2080                 device->setOutputName(outputs.constFirst()->name());
2081                 changedDevice = device;
2082                 continue;
2083             }
2084 
2085             auto it = std::find_if(outputs.begin(), outputs.end(), [device](const auto &output) {
2086                 return output->name() == device->outputName();
2087             });
2088             ++it;
2089             auto nextOutput = it == outputs.end() ? outputs.first() : *it;
2090             device->setOutputName(nextOutput->name());
2091             changedDevice = device;
2092         }
2093         const QString message = tabletToolCount == 1 ? i18n("Tablet moved to %1", changedDevice->outputName()) : i18n("Tablets switched outputs");
2094         OSD::show(message, QStringLiteral("input-tablet"), 5000);
2095     }
2096 
2097     void removeDevice(InputDevice *inputDevice)
2098     {
2099         auto device = qobject_cast<LibInput::Device *>(inputDevice);
2100         if (device) {
2101             auto deviceGroup = libinput_device_get_device_group(device->device());
2102             libinput_device_group_set_user_data(deviceGroup, nullptr);
2103 
2104             KWaylandServer::TabletSeatV2Interface *tabletSeat = findTabletSeat();
2105             if (tabletSeat) {
2106                 tabletSeat->removeDevice(device->sysName());
2107             } else {
2108                 qCCritical(KWIN_CORE) << "Could not find tablet to remove" << device->sysName();
2109             }
2110         }
2111     }
2112 
2113     KWaylandServer::TabletToolV2Interface::Type getType(const KWin::TabletToolId &tabletToolId)
2114     {
2115         using Type = KWaylandServer::TabletToolV2Interface::Type;
2116         switch (tabletToolId.m_toolType) {
2117         case InputRedirection::Pen:
2118             return Type::Pen;
2119         case InputRedirection::Eraser:
2120             return Type::Eraser;
2121         case InputRedirection::Brush:
2122             return Type::Brush;
2123         case InputRedirection::Pencil:
2124             return Type::Pencil;
2125         case InputRedirection::Airbrush:
2126             return Type::Airbrush;
2127         case InputRedirection::Finger:
2128             return Type::Finger;
2129         case InputRedirection::Mouse:
2130             return Type::Mouse;
2131         case InputRedirection::Lens:
2132             return Type::Lens;
2133         case InputRedirection::Totem:
2134             return Type::Totem;
2135         }
2136         return Type::Pen;
2137     }
2138 
2139     KWaylandServer::TabletToolV2Interface *createTool(const KWin::TabletToolId &tabletToolId)
2140     {
2141         using namespace KWaylandServer;
2142         KWaylandServer::TabletSeatV2Interface *tabletSeat = findTabletSeat();
2143 
2144         const auto f = [](InputRedirection::Capability cap) {
2145             switch (cap) {
2146             case InputRedirection::Tilt:
2147                 return TabletToolV2Interface::Tilt;
2148             case InputRedirection::Pressure:
2149                 return TabletToolV2Interface::Pressure;
2150             case InputRedirection::Distance:
2151                 return TabletToolV2Interface::Distance;
2152             case InputRedirection::Rotation:
2153                 return TabletToolV2Interface::Rotation;
2154             case InputRedirection::Slider:
2155                 return TabletToolV2Interface::Slider;
2156             case InputRedirection::Wheel:
2157                 return TabletToolV2Interface::Wheel;
2158             }
2159             return TabletToolV2Interface::Wheel;
2160         };
2161         QVector<TabletToolV2Interface::Capability> ifaceCapabilities;
2162         ifaceCapabilities.resize(tabletToolId.m_capabilities.size());
2163         std::transform(tabletToolId.m_capabilities.constBegin(), tabletToolId.m_capabilities.constEnd(), ifaceCapabilities.begin(), f);
2164 
2165         TabletToolV2Interface *tool = tabletSeat->addTool(getType(tabletToolId), tabletToolId.m_serialId, tabletToolId.m_uniqueId, ifaceCapabilities, tabletToolId.deviceSysName);
2166 
2167         const auto cursor = new SurfaceCursor(tool);
2168         Cursors::self()->addCursor(cursor);
2169         m_cursorByTool[tool] = cursor;
2170 
2171         return tool;
2172     }
2173 
2174     bool tabletToolEvent(TabletEvent *event) override
2175     {
2176         using namespace KWaylandServer;
2177 
2178         if (!workspace()) {
2179             return false;
2180         }
2181 
2182         KWaylandServer::TabletSeatV2Interface *tabletSeat = findTabletSeat();
2183         if (!tabletSeat) {
2184             qCCritical(KWIN_CORE) << "Could not find tablet manager";
2185             return false;
2186         }
2187         auto tool = tabletSeat->toolByHardwareSerial(event->tabletId().m_serialId, getType(event->tabletId()));
2188         if (!tool) {
2189             tool = createTool(event->tabletId());
2190         }
2191 
2192         // NOTE: tablet will be nullptr as the device is removed (see ::removeDevice) but events from the tool
2193         // may still happen (e.g. Release or ProximityOut events)
2194         auto tablet = static_cast<KWaylandServer::TabletV2Interface *>(event->tabletId().m_deviceGroupData);
2195 
2196         Window *window = input()->findToplevel(event->globalPos());
2197         if (!window || !window->surface()) {
2198             return false;
2199         }
2200 
2201         KWaylandServer::SurfaceInterface *surface = window->surface();
2202         tool->setCurrentSurface(surface);
2203 
2204         if (!tool->isClientSupported() || (tablet && !tablet->isSurfaceSupported(surface))) {
2205             return emulateTabletEvent(event);
2206         }
2207 
2208         switch (event->type()) {
2209         case QEvent::TabletMove: {
2210             const auto pos = window->mapToLocal(event->globalPosF());
2211             tool->sendMotion(pos);
2212             m_cursorByTool[tool]->setPos(event->globalPos());
2213             break;
2214         }
2215         case QEvent::TabletEnterProximity: {
2216             const QPoint pos = event->globalPos();
2217             m_cursorByTool[tool]->setPos(pos);
2218             tool->sendProximityIn(tablet);
2219             tool->sendMotion(window->mapToLocal(event->globalPosF()));
2220             break;
2221         }
2222         case QEvent::TabletLeaveProximity:
2223             tool->sendProximityOut();
2224             break;
2225         case QEvent::TabletPress: {
2226             const auto pos = window->mapToLocal(event->globalPosF());
2227             tool->sendMotion(pos);
2228             m_cursorByTool[tool]->setPos(event->globalPos());
2229             tool->sendDown();
2230             break;
2231         }
2232         case QEvent::TabletRelease:
2233             tool->sendUp();
2234             break;
2235         default:
2236             qCWarning(KWIN_CORE) << "Unexpected tablet event type" << event;
2237             break;
2238         }
2239         const quint32 MAX_VAL = 65535;
2240 
2241         if (tool->hasCapability(TabletToolV2Interface::Pressure)) {
2242             tool->sendPressure(MAX_VAL * event->pressure());
2243         }
2244         if (tool->hasCapability(TabletToolV2Interface::Tilt)) {
2245             tool->sendTilt(event->xTilt(), event->yTilt());
2246         }
2247         if (tool->hasCapability(TabletToolV2Interface::Rotation)) {
2248             tool->sendRotation(event->rotation());
2249         }
2250 
2251         tool->sendFrame(event->timestamp());
2252         return true;
2253     }
2254 
2255     bool emulateTabletEvent(TabletEvent *event)
2256     {
2257         if (!workspace()) {
2258             return false;
2259         }
2260 
2261         switch (event->type()) {
2262         case QEvent::TabletMove:
2263         case QEvent::TabletEnterProximity:
2264             input()->pointer()->processMotionAbsolute(event->globalPosF(), std::chrono::milliseconds(event->timestamp()));
2265             break;
2266         case QEvent::TabletPress:
2267             input()->pointer()->processButton(KWin::qtMouseButtonToButton(Qt::LeftButton),
2268                                               InputRedirection::PointerButtonPressed, std::chrono::milliseconds(event->timestamp()));
2269             break;
2270         case QEvent::TabletRelease:
2271             input()->pointer()->processButton(KWin::qtMouseButtonToButton(Qt::LeftButton),
2272                                               InputRedirection::PointerButtonReleased, std::chrono::milliseconds(event->timestamp()));
2273             break;
2274         case QEvent::TabletLeaveProximity:
2275             break;
2276         default:
2277             qCWarning(KWIN_CORE) << "Unexpected tablet event type" << event;
2278             break;
2279         }
2280         return true;
2281     }
2282 
2283     bool tabletToolButtonEvent(uint button, bool pressed, const TabletToolId &tabletToolId, std::chrono::microseconds time) override
2284     {
2285         KWaylandServer::TabletSeatV2Interface *tabletSeat = findTabletSeat();
2286         auto tool = tabletSeat->toolByHardwareSerial(tabletToolId.m_serialId, getType(tabletToolId));
2287         if (!tool) {
2288             tool = createTool(tabletToolId);
2289         }
2290         if (!tool->isClientSupported()) {
2291             return false;
2292         }
2293         tool->sendButton(button, pressed);
2294         return true;
2295     }
2296 
2297     KWaylandServer::TabletPadV2Interface *findAndAdoptPad(const TabletPadId &tabletPadId) const
2298     {
2299         Window *window = workspace()->activeWindow();
2300         auto seat = findTabletSeat();
2301         if (!window || !window->surface() || !seat->isClientSupported(window->surface()->client())) {
2302             return nullptr;
2303         }
2304 
2305         auto tablet = static_cast<KWaylandServer::TabletV2Interface *>(tabletPadId.data);
2306         KWaylandServer::SurfaceInterface *surface = window->surface();
2307         auto pad = tablet->pad();
2308         if (!pad) {
2309             return nullptr;
2310         }
2311         pad->setCurrentSurface(surface, tablet);
2312         return pad;
2313     }
2314 
2315     bool tabletPadButtonEvent(uint button, bool pressed, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
2316     {
2317         auto pad = findAndAdoptPad(tabletPadId);
2318         if (!pad) {
2319             return false;
2320         }
2321         pad->sendButton(time, button, pressed);
2322         return true;
2323     }
2324 
2325     bool tabletPadRingEvent(int number, int angle, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
2326     {
2327         auto pad = findAndAdoptPad(tabletPadId);
2328         if (!pad) {
2329             return false;
2330         }
2331         auto ring = pad->ring(number);
2332 
2333         ring->sendAngle(angle);
2334         if (isFinger) {
2335             ring->sendSource(KWaylandServer::TabletPadRingV2Interface::SourceFinger);
2336         }
2337         ring->sendFrame(std::chrono::duration_cast<std::chrono::milliseconds>(time).count());
2338         return true;
2339     }
2340 
2341     bool tabletPadStripEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
2342     {
2343         auto pad = findAndAdoptPad(tabletPadId);
2344         if (!pad) {
2345             return false;
2346         }
2347         auto strip = pad->strip(number);
2348 
2349         strip->sendPosition(position);
2350         if (isFinger) {
2351             strip->sendSource(KWaylandServer::TabletPadStripV2Interface::SourceFinger);
2352         }
2353         strip->sendFrame(std::chrono::duration_cast<std::chrono::milliseconds>(time).count());
2354         return true;
2355     }
2356 
2357     QHash<KWaylandServer::TabletToolV2Interface *, Cursor *> m_cursorByTool;
2358 };
2359 
2360 static KWaylandServer::AbstractDropHandler *dropHandler(Window *window)
2361 {
2362     auto surface = window->surface();
2363     if (!surface) {
2364         return nullptr;
2365     }
2366     auto seat = waylandServer()->seat();
2367     auto dropTarget = seat->dropHandlerForSurface(surface);
2368     if (dropTarget) {
2369         return dropTarget;
2370     }
2371 
2372     if (qobject_cast<X11Window *>(window) && kwinApp()->xwayland()) {
2373         return kwinApp()->xwayland()->xwlDropHandler();
2374     }
2375 
2376     return nullptr;
2377 }
2378 
2379 class DragAndDropInputFilter : public QObject, public InputEventFilter
2380 {
2381     Q_OBJECT
2382 public:
2383     DragAndDropInputFilter()
2384     {
2385         m_raiseTimer.setSingleShot(true);
2386         m_raiseTimer.setInterval(250);
2387         connect(&m_raiseTimer, &QTimer::timeout, this, &DragAndDropInputFilter::raiseDragTarget);
2388     }
2389 
2390     bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
2391     {
2392         auto seat = waylandServer()->seat();
2393         if (!seat->isDragPointer()) {
2394             return false;
2395         }
2396         if (seat->isDragTouch()) {
2397             return true;
2398         }
2399         seat->setTimestamp(event->timestamp());
2400         switch (event->type()) {
2401         case QEvent::MouseMove: {
2402             const auto pos = input()->globalPointer();
2403             seat->notifyPointerMotion(pos);
2404             seat->notifyPointerFrame();
2405 
2406             Window *dragTarget = pickDragTarget(pos);
2407             if (dragTarget) {
2408                 if (dragTarget != m_dragTarget) {
2409                     workspace()->takeActivity(dragTarget, Workspace::ActivityFlag::ActivityFocus);
2410                     m_raiseTimer.start();
2411                 }
2412                 if ((pos - m_lastPos).manhattanLength() > 10) {
2413                     m_lastPos = pos;
2414                     // reset timer to delay raising the window
2415                     m_raiseTimer.start();
2416                 }
2417             }
2418             m_dragTarget = dragTarget;
2419 
2420             if (auto *xwl = kwinApp()->xwayland()) {
2421                 const auto ret = xwl->dragMoveFilter(dragTarget, event->globalPos());
2422                 if (ret == Xwl::DragEventReply::Ignore) {
2423                     return false;
2424                 } else if (ret == Xwl::DragEventReply::Take) {
2425                     break;
2426                 }
2427             }
2428 
2429             if (dragTarget) {
2430                 // TODO: consider decorations
2431                 if (dragTarget->surface() != seat->dragSurface()) {
2432                     seat->setDragTarget(dropHandler(dragTarget), dragTarget->surface(), dragTarget->inputTransformation());
2433                 }
2434             } else {
2435                 // no window at that place, if we have a surface we need to reset
2436                 seat->setDragTarget(nullptr, nullptr);
2437                 m_dragTarget = nullptr;
2438             }
2439             break;
2440         }
2441         case QEvent::MouseButtonPress:
2442             seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Pressed);
2443             seat->notifyPointerFrame();
2444             break;
2445         case QEvent::MouseButtonRelease:
2446             raiseDragTarget();
2447             m_dragTarget = nullptr;
2448             seat->notifyPointerButton(nativeButton, KWaylandServer::PointerButtonState::Released);
2449             seat->notifyPointerFrame();
2450             break;
2451         default:
2452             break;
2453         }
2454         // TODO: should we pass through effects?
2455         return true;
2456     }
2457 
2458     bool touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
2459     {
2460         auto seat = waylandServer()->seat();
2461         if (seat->isDragPointer()) {
2462             return true;
2463         }
2464         if (!seat->isDragTouch()) {
2465             return false;
2466         }
2467         if (m_touchId != id) {
2468             return true;
2469         }
2470         seat->setTimestamp(time);
2471         seat->notifyTouchDown(id, pos);
2472         m_lastPos = pos;
2473         return true;
2474     }
2475     bool touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
2476     {
2477         auto seat = waylandServer()->seat();
2478         if (seat->isDragPointer()) {
2479             return true;
2480         }
2481         if (!seat->isDragTouch()) {
2482             return false;
2483         }
2484         if (m_touchId < 0) {
2485             // We take for now the first id appearing as a move after a drag
2486             // started. We can optimize by specifying the id the drag is
2487             // associated with by implementing a key-value getter in KWayland.
2488             m_touchId = id;
2489         }
2490         if (m_touchId != id) {
2491             return true;
2492         }
2493         seat->setTimestamp(time);
2494         seat->notifyTouchMotion(id, pos);
2495 
2496         if (Window *t = pickDragTarget(pos)) {
2497             // TODO: consider decorations
2498             if (t->surface() != seat->dragSurface()) {
2499                 if ((m_dragTarget = static_cast<Window *>(t->isClient() ? t : nullptr))) {
2500                     workspace()->takeActivity(m_dragTarget, Workspace::ActivityFlag::ActivityFocus);
2501                     m_raiseTimer.start();
2502                 }
2503                 seat->setDragTarget(dropHandler(t), t->surface(), pos, t->inputTransformation());
2504             }
2505             if ((pos - m_lastPos).manhattanLength() > 10) {
2506                 m_lastPos = pos;
2507                 // reset timer to delay raising the window
2508                 m_raiseTimer.start();
2509             }
2510         } else {
2511             // no window at that place, if we have a surface we need to reset
2512             seat->setDragTarget(nullptr, nullptr);
2513             m_dragTarget = nullptr;
2514         }
2515         return true;
2516     }
2517     bool touchUp(qint32 id, std::chrono::microseconds time) override
2518     {
2519         auto seat = waylandServer()->seat();
2520         if (!seat->isDragTouch()) {
2521             return false;
2522         }
2523         seat->setTimestamp(time);
2524         seat->notifyTouchUp(id);
2525         if (m_touchId == id) {
2526             m_touchId = -1;
2527             raiseDragTarget();
2528         }
2529         return true;
2530     }
2531     bool keyEvent(KeyEvent *event) override
2532     {
2533         if (event->key() != Qt::Key_Escape) {
2534             return false;
2535         }
2536 
2537         auto seat = waylandServer()->seat();
2538         if (!seat->isDrag()) {
2539             return false;
2540         }
2541         seat->setTimestamp(event->timestamp());
2542 
2543         seat->cancelDrag();
2544 
2545         return true;
2546     }
2547 
2548 private:
2549     void raiseDragTarget()
2550     {
2551         m_raiseTimer.stop();
2552         if (m_dragTarget) {
2553             workspace()->takeActivity(m_dragTarget, Workspace::ActivityFlag::ActivityRaise);
2554         }
2555     }
2556 
2557     Window *pickDragTarget(const QPointF &pos) const
2558     {
2559         const QList<Window *> stacking = workspace()->stackingOrder();
2560         if (stacking.isEmpty()) {
2561             return nullptr;
2562         }
2563         auto it = stacking.end();
2564         do {
2565             --it;
2566             Window *window = (*it);
2567             if (window->isDeleted()) {
2568                 continue;
2569             }
2570             if (!window->isClient()) {
2571                 continue;
2572             }
2573             if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal()) {
2574                 continue;
2575             }
2576             if (!window->readyForPainting()) {
2577                 continue;
2578             }
2579             if (window->hitTest(pos)) {
2580                 return window;
2581             }
2582         } while (it != stacking.begin());
2583         return nullptr;
2584     }
2585 
2586     qint32 m_touchId = -1;
2587     QPointF m_lastPos = QPointF(-1, -1);
2588     QPointer<Window> m_dragTarget;
2589     QTimer m_raiseTimer;
2590 };
2591 
2592 KWIN_SINGLETON_FACTORY(InputRedirection)
2593 
2594 static const QString s_touchpadComponent = QStringLiteral("kcm_touchpad");
2595 
2596 InputRedirection::InputRedirection(QObject *parent)
2597     : QObject(parent)
2598     , m_keyboard(new KeyboardInputRedirection(this))
2599     , m_pointer(new PointerInputRedirection(this))
2600     , m_tablet(new TabletInputRedirection(this))
2601     , m_touch(new TouchInputRedirection(this))
2602     , m_shortcuts(new GlobalShortcutsManager(this))
2603 {
2604     qRegisterMetaType<KWin::InputRedirection::KeyboardKeyState>();
2605     qRegisterMetaType<KWin::InputRedirection::PointerButtonState>();
2606     qRegisterMetaType<KWin::InputRedirection::PointerAxis>();
2607     setupInputBackends();
2608     connect(kwinApp(), &Application::workspaceCreated, this, &InputRedirection::setupWorkspace);
2609 }
2610 
2611 InputRedirection::~InputRedirection()
2612 {
2613     m_inputBackends.clear();
2614     m_inputDevices.clear();
2615 
2616     s_self = nullptr;
2617     qDeleteAll(m_filters);
2618     qDeleteAll(m_spies);
2619 }
2620 
2621 void InputRedirection::installInputEventFilter(InputEventFilter *filter)
2622 {
2623     Q_ASSERT(!m_filters.contains(filter));
2624     m_filters << filter;
2625 }
2626 
2627 void InputRedirection::prependInputEventFilter(InputEventFilter *filter)
2628 {
2629     Q_ASSERT(!m_filters.contains(filter));
2630     m_filters.prepend(filter);
2631 }
2632 
2633 void InputRedirection::uninstallInputEventFilter(InputEventFilter *filter)
2634 {
2635     m_filters.removeOne(filter);
2636 }
2637 
2638 void InputRedirection::installInputEventSpy(InputEventSpy *spy)
2639 {
2640     m_spies << spy;
2641 }
2642 
2643 void InputRedirection::uninstallInputEventSpy(InputEventSpy *spy)
2644 {
2645     m_spies.removeOne(spy);
2646 }
2647 
2648 void InputRedirection::init()
2649 {
2650     m_inputConfigWatcher = KConfigWatcher::create(InputConfig::self()->inputConfig());
2651     connect(m_inputConfigWatcher.data(), &KConfigWatcher::configChanged,
2652             this, &InputRedirection::handleInputConfigChanged);
2653 
2654     m_shortcuts->init();
2655 }
2656 
2657 void InputRedirection::setupWorkspace()
2658 {
2659     connect(workspace(), &Workspace::outputsChanged, this, &InputRedirection::updateScreens);
2660     if (waylandServer()) {
2661         m_keyboard->init();
2662         m_pointer->init();
2663         m_touch->init();
2664         m_tablet->init();
2665 
2666         updateLeds(m_keyboard->xkb()->leds());
2667         connect(m_keyboard, &KeyboardInputRedirection::ledsChanged, this, &InputRedirection::updateLeds);
2668 
2669         setupTouchpadShortcuts();
2670         setupInputFilters();
2671         updateScreens();
2672     }
2673 }
2674 
2675 void InputRedirection::updateScreens()
2676 {
2677     for (const auto &backend : m_inputBackends) {
2678         backend->updateScreens();
2679     }
2680 }
2681 
2682 QObject *InputRedirection::lastInputHandler() const
2683 {
2684     return m_lastInputDevice;
2685 }
2686 
2687 void InputRedirection::setLastInputHandler(QObject *device)
2688 {
2689     m_lastInputDevice = device;
2690 }
2691 
2692 class WindowInteractedSpy : public InputEventSpy
2693 {
2694 public:
2695     void keyEvent(KeyEvent *event) override
2696     {
2697         if (event->isAutoRepeat() || event->type() != QEvent::KeyPress) {
2698             return;
2699         }
2700         update();
2701     }
2702 
2703     void pointerEvent(KWin::MouseEvent *event) override
2704     {
2705         if (event->type() != QEvent::MouseButtonPress) {
2706             return;
2707         }
2708         update();
2709     }
2710 
2711     void tabletPadButtonEvent(uint, bool pressed, const KWin::TabletPadId &, std::chrono::microseconds time) override
2712     {
2713         if (!pressed) {
2714             return;
2715         }
2716         update();
2717     }
2718 
2719     void tabletToolButtonEvent(uint, bool pressed, const KWin::TabletToolId &, std::chrono::microseconds time) override
2720     {
2721         if (!pressed) {
2722             return;
2723         }
2724         update();
2725     }
2726 
2727     void tabletToolEvent(KWin::TabletEvent *event) override
2728     {
2729         if (event->type() != QEvent::TabletPress) {
2730             return;
2731         }
2732         update();
2733     }
2734 
2735     void touchDown(qint32, const QPointF &, std::chrono::microseconds time) override
2736     {
2737         update();
2738     }
2739 
2740     void update()
2741     {
2742         auto window = workspace()->activeWindow();
2743         if (!window) {
2744             return;
2745         }
2746         window->setLastUsageSerial(waylandServer()->seat()->display()->serial());
2747     }
2748 };
2749 
2750 class UserActivitySpy : public InputEventSpy
2751 {
2752 public:
2753     void pointerEvent(MouseEvent *event) override
2754     {
2755         notifyActivity();
2756     }
2757     void wheelEvent(WheelEvent *event) override
2758     {
2759         notifyActivity();
2760     }
2761 
2762     void keyEvent(KeyEvent *event) override
2763     {
2764         notifyActivity();
2765     }
2766 
2767     void touchDown(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
2768     {
2769         notifyActivity();
2770     }
2771     void touchMotion(qint32 id, const QPointF &pos, std::chrono::microseconds time) override
2772     {
2773         notifyActivity();
2774     }
2775     void touchUp(qint32 id, std::chrono::microseconds time) override
2776     {
2777         notifyActivity();
2778     }
2779 
2780     void pinchGestureBegin(int fingerCount, std::chrono::microseconds time) override
2781     {
2782         notifyActivity();
2783     }
2784     void pinchGestureUpdate(qreal scale, qreal angleDelta, const QPointF &delta, std::chrono::microseconds time) override
2785     {
2786         notifyActivity();
2787     }
2788     void pinchGestureEnd(std::chrono::microseconds time) override
2789     {
2790         notifyActivity();
2791     }
2792     void pinchGestureCancelled(std::chrono::microseconds time) override
2793     {
2794         notifyActivity();
2795     }
2796 
2797     void swipeGestureBegin(int fingerCount, std::chrono::microseconds time) override
2798     {
2799         notifyActivity();
2800     }
2801     void swipeGestureUpdate(const QPointF &delta, std::chrono::microseconds time) override
2802     {
2803         notifyActivity();
2804     }
2805     void swipeGestureEnd(std::chrono::microseconds time) override
2806     {
2807         notifyActivity();
2808     }
2809     void swipeGestureCancelled(std::chrono::microseconds time) override
2810     {
2811         notifyActivity();
2812     }
2813 
2814     void holdGestureBegin(int fingerCount, std::chrono::microseconds time) override
2815     {
2816         notifyActivity();
2817     }
2818     void holdGestureEnd(std::chrono::microseconds time) override
2819     {
2820         notifyActivity();
2821     }
2822     void holdGestureCancelled(std::chrono::microseconds time) override
2823     {
2824         notifyActivity();
2825     }
2826 
2827     void tabletToolEvent(TabletEvent *event) override
2828     {
2829         notifyActivity();
2830     }
2831     void tabletToolButtonEvent(uint button, bool pressed, const TabletToolId &tabletToolId, std::chrono::microseconds time) override
2832     {
2833         notifyActivity();
2834     }
2835     void tabletPadButtonEvent(uint button, bool pressed, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
2836     {
2837         notifyActivity();
2838     }
2839     void tabletPadStripEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
2840     {
2841         notifyActivity();
2842     }
2843     void tabletPadRingEvent(int number, int position, bool isFinger, const TabletPadId &tabletPadId, std::chrono::microseconds time) override
2844     {
2845         notifyActivity();
2846     }
2847 
2848 private:
2849     void notifyActivity()
2850     {
2851         input()->simulateUserActivity();
2852     }
2853 };
2854 
2855 void InputRedirection::setupInputFilters()
2856 {
2857     const bool hasGlobalShortcutSupport = waylandServer()->hasGlobalShortcutSupport();
2858     if (kwinApp()->session()->capabilities() & Session::Capability::SwitchTerminal)
2859         {
2860         installInputEventFilter(new VirtualTerminalFilter);
2861     }
2862     installInputEventSpy(new HideCursorSpy);
2863     installInputEventSpy(new UserActivitySpy);
2864     installInputEventSpy(new WindowInteractedSpy);
2865     if (hasGlobalShortcutSupport) {
2866         installInputEventFilter(new TerminateServerFilter);
2867     }
2868     installInputEventFilter(new DragAndDropInputFilter);
2869     installInputEventFilter(new LockScreenFilter);
2870     m_windowSelector = new WindowSelectorFilter;
2871     installInputEventFilter(m_windowSelector);
2872     if (hasGlobalShortcutSupport) {
2873         installInputEventFilter(new ScreenEdgeInputFilter);
2874     }
2875 #if KWIN_BUILD_TABBOX
2876     installInputEventFilter(new TabBoxInputFilter);
2877 #endif
2878     if (hasGlobalShortcutSupport) {
2879         installInputEventFilter(new GlobalShortcutFilter);
2880     }
2881     installInputEventFilter(new EffectsFilter);
2882     installInputEventFilter(new MoveResizeFilter);
2883     installInputEventFilter(new PopupInputFilter);
2884     installInputEventFilter(new DecorationEventFilter);
2885     installInputEventFilter(new WindowActionInputFilter);
2886     installInputEventFilter(new InternalWindowEventFilter);
2887     installInputEventFilter(new InputKeyboardFilter);
2888     installInputEventFilter(new ForwardInputFilter);
2889     installInputEventFilter(new TabletInputFilter);
2890 }
2891 
2892 void InputRedirection::handleInputConfigChanged(const KConfigGroup &group)
2893 {
2894     if (group.name() == QLatin1String("Keyboard")) {
2895         m_keyboard->reconfigure();
2896     }
2897 }
2898 
2899 void InputRedirection::updateLeds(LEDs leds)
2900 {
2901     if (m_leds != leds) {
2902         m_leds = leds;
2903 
2904         for (InputDevice *device : std::as_const(m_inputDevices)) {
2905             device->setLeds(leds);
2906         }
2907     }
2908 }
2909 
2910 void InputRedirection::addInputDevice(InputDevice *device)
2911 {
2912     connect(device, &InputDevice::keyChanged, m_keyboard, &KeyboardInputRedirection::processKey);
2913 
2914     connect(device, &InputDevice::pointerMotionAbsolute,
2915             m_pointer, &PointerInputRedirection::processMotionAbsolute);
2916     connect(device, &InputDevice::pointerMotion,
2917             m_pointer, &PointerInputRedirection::processMotion);
2918     connect(device, &InputDevice::pointerButtonChanged,
2919             m_pointer, &PointerInputRedirection::processButton);
2920     connect(device, &InputDevice::pointerAxisChanged,
2921             m_pointer, &PointerInputRedirection::processAxis);
2922     connect(device, &InputDevice::pinchGestureBegin,
2923             m_pointer, &PointerInputRedirection::processPinchGestureBegin);
2924     connect(device, &InputDevice::pinchGestureUpdate,
2925             m_pointer, &PointerInputRedirection::processPinchGestureUpdate);
2926     connect(device, &InputDevice::pinchGestureEnd,
2927             m_pointer, &PointerInputRedirection::processPinchGestureEnd);
2928     connect(device, &InputDevice::pinchGestureCancelled,
2929             m_pointer, &PointerInputRedirection::processPinchGestureCancelled);
2930     connect(device, &InputDevice::swipeGestureBegin,
2931             m_pointer, &PointerInputRedirection::processSwipeGestureBegin);
2932     connect(device, &InputDevice::swipeGestureUpdate,
2933             m_pointer, &PointerInputRedirection::processSwipeGestureUpdate);
2934     connect(device, &InputDevice::swipeGestureEnd,
2935             m_pointer, &PointerInputRedirection::processSwipeGestureEnd);
2936     connect(device, &InputDevice::swipeGestureCancelled,
2937             m_pointer, &PointerInputRedirection::processSwipeGestureCancelled);
2938     connect(device, &InputDevice::holdGestureBegin,
2939             m_pointer, &PointerInputRedirection::processHoldGestureBegin);
2940     connect(device, &InputDevice::holdGestureEnd,
2941             m_pointer, &PointerInputRedirection::processHoldGestureEnd);
2942     connect(device, &InputDevice::holdGestureCancelled,
2943             m_pointer, &PointerInputRedirection::processHoldGestureCancelled);
2944 
2945     connect(device, &InputDevice::touchDown, m_touch, &TouchInputRedirection::processDown);
2946     connect(device, &InputDevice::touchUp, m_touch, &TouchInputRedirection::processUp);
2947     connect(device, &InputDevice::touchMotion, m_touch, &TouchInputRedirection::processMotion);
2948     connect(device, &InputDevice::touchCanceled, m_touch, &TouchInputRedirection::cancel);
2949     connect(device, &InputDevice::touchFrame, m_touch, &TouchInputRedirection::frame);
2950 
2951     auto handleSwitchEvent = [this](SwitchEvent::State state, std::chrono::microseconds time, InputDevice *device) {
2952         SwitchEvent event(state, time, device);
2953         processSpies(std::bind(&InputEventSpy::switchEvent, std::placeholders::_1, &event));
2954         processFilters(std::bind(&InputEventFilter::switchEvent, std::placeholders::_1, &event));
2955     };
2956     connect(device, &InputDevice::switchToggledOn, this,
2957             std::bind(handleSwitchEvent, SwitchEvent::State::On, std::placeholders::_1, std::placeholders::_2));
2958     connect(device, &InputDevice::switchToggledOff, this,
2959             std::bind(handleSwitchEvent, SwitchEvent::State::Off, std::placeholders::_1, std::placeholders::_2));
2960 
2961     connect(device, &InputDevice::tabletToolEvent,
2962             m_tablet, &TabletInputRedirection::tabletToolEvent);
2963     connect(device, &InputDevice::tabletToolButtonEvent,
2964             m_tablet, &TabletInputRedirection::tabletToolButtonEvent);
2965     connect(device, &InputDevice::tabletPadButtonEvent,
2966             m_tablet, &TabletInputRedirection::tabletPadButtonEvent);
2967     connect(device, &InputDevice::tabletPadRingEvent,
2968             m_tablet, &TabletInputRedirection::tabletPadRingEvent);
2969     connect(device, &InputDevice::tabletPadStripEvent,
2970             m_tablet, &TabletInputRedirection::tabletPadStripEvent);
2971 
2972     device->setLeds(m_leds);
2973 
2974     m_inputDevices.append(device);
2975     Q_EMIT deviceAdded(device);
2976 
2977     updateAvailableInputDevices();
2978 }
2979 
2980 void InputRedirection::removeInputDevice(InputDevice *device)
2981 {
2982     m_inputDevices.removeOne(device);
2983     Q_EMIT deviceRemoved(device);
2984 
2985     updateAvailableInputDevices();
2986 }
2987 
2988 void InputRedirection::updateAvailableInputDevices()
2989 {
2990     const bool hasKeyboard = std::any_of(m_inputDevices.constBegin(), m_inputDevices.constEnd(), [](InputDevice *device) {
2991         return device->isKeyboard();
2992     });
2993     if (m_hasKeyboard != hasKeyboard) {
2994         m_hasKeyboard = hasKeyboard;
2995         Q_EMIT hasKeyboardChanged(hasKeyboard);
2996     }
2997 
2998     const bool hasAlphaNumericKeyboard = std::any_of(m_inputDevices.constBegin(), m_inputDevices.constEnd(), [](InputDevice *device) {
2999         return device->isAlphaNumericKeyboard();
3000     });
3001     if (m_hasAlphaNumericKeyboard != hasAlphaNumericKeyboard) {
3002         m_hasAlphaNumericKeyboard = hasAlphaNumericKeyboard;
3003         Q_EMIT hasAlphaNumericKeyboardChanged(hasAlphaNumericKeyboard);
3004     }
3005 
3006     const bool hasPointer = std::any_of(m_inputDevices.constBegin(), m_inputDevices.constEnd(), [](InputDevice *device) {
3007         return device->isPointer();
3008     });
3009     if (m_hasPointer != hasPointer) {
3010         m_hasPointer = hasPointer;
3011         Q_EMIT hasPointerChanged(hasPointer);
3012     }
3013 
3014     const bool hasTouch = std::any_of(m_inputDevices.constBegin(), m_inputDevices.constEnd(), [](InputDevice *device) {
3015         return device->isTouch();
3016     });
3017     if (m_hasTouch != hasTouch) {
3018         m_hasTouch = hasTouch;
3019         Q_EMIT hasTouchChanged(hasTouch);
3020     }
3021 
3022     const bool hasTabletModeSwitch = std::any_of(m_inputDevices.constBegin(), m_inputDevices.constEnd(), [](InputDevice *device) {
3023         return device->isTabletModeSwitch();
3024     });
3025     if (m_hasTabletModeSwitch != hasTabletModeSwitch) {
3026         m_hasTabletModeSwitch = hasTabletModeSwitch;
3027         Q_EMIT hasTabletModeSwitchChanged(hasTabletModeSwitch);
3028     }
3029 }
3030 
3031 void InputRedirection::toggleTouchpads()
3032 {
3033     bool changed = false;
3034     m_touchpadsEnabled = !m_touchpadsEnabled;
3035     for (InputDevice *device : std::as_const(m_inputDevices)) {
3036         if (!device->isTouchpad()) {
3037             continue;
3038         }
3039         const bool old = device->isEnabled();
3040         device->setEnabled(m_touchpadsEnabled);
3041         if (old != device->isEnabled()) {
3042             changed = true;
3043         }
3044     }
3045     if (changed) {
3046         // send OSD message
3047         QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("org.kde.plasmashell"),
3048                                                           QStringLiteral("/org/kde/osdService"),
3049                                                           QStringLiteral("org.kde.osdService"),
3050                                                           QStringLiteral("touchpadEnabledChanged"));
3051         msg.setArguments({m_touchpadsEnabled});
3052         QDBusConnection::sessionBus().asyncCall(msg);
3053     }
3054 }
3055 
3056 void InputRedirection::enableTouchpads()
3057 {
3058     if (!m_touchpadsEnabled) {
3059         toggleTouchpads();
3060     }
3061 }
3062 
3063 void InputRedirection::disableTouchpads()
3064 {
3065     if (m_touchpadsEnabled) {
3066         toggleTouchpads();
3067     }
3068 }
3069 
3070 void InputRedirection::addInputBackend(std::unique_ptr<InputBackend> &&inputBackend)
3071 {
3072     connect(inputBackend.get(), &InputBackend::deviceAdded, this, &InputRedirection::addInputDevice);
3073     connect(inputBackend.get(), &InputBackend::deviceRemoved, this, &InputRedirection::removeInputDevice);
3074 
3075     inputBackend->setConfig(InputConfig::self()->inputConfig());
3076     inputBackend->initialize();
3077 
3078     m_inputBackends.push_back(std::move(inputBackend));
3079 }
3080 
3081 void InputRedirection::setupInputBackends()
3082 {
3083     std::unique_ptr<InputBackend> inputBackend = kwinApp()->outputBackend()->createInputBackend();
3084     if (inputBackend) {
3085         addInputBackend(std::move(inputBackend));
3086     }
3087     if (waylandServer()) {
3088         addInputBackend(std::make_unique<FakeInputBackend>());
3089     }
3090 }
3091 
3092 void InputRedirection::setupTouchpadShortcuts()
3093 {
3094     QAction *touchpadToggleAction = new QAction(this);
3095     QAction *touchpadOnAction = new QAction(this);
3096     QAction *touchpadOffAction = new QAction(this);
3097 
3098     const QString touchpadDisplayName = i18n("Touchpad");
3099 
3100     touchpadToggleAction->setObjectName(QStringLiteral("Toggle Touchpad"));
3101     touchpadToggleAction->setProperty("componentName", s_touchpadComponent);
3102     touchpadToggleAction->setProperty("componentDisplayName", touchpadDisplayName);
3103     touchpadOnAction->setObjectName(QStringLiteral("Enable Touchpad"));
3104     touchpadOnAction->setProperty("componentName", s_touchpadComponent);
3105     touchpadOnAction->setProperty("componentDisplayName", touchpadDisplayName);
3106     touchpadOffAction->setObjectName(QStringLiteral("Disable Touchpad"));
3107     touchpadOffAction->setProperty("componentName", s_touchpadComponent);
3108     touchpadOffAction->setProperty("componentDisplayName", touchpadDisplayName);
3109     KGlobalAccel::self()->setDefaultShortcut(touchpadToggleAction, QList<QKeySequence>{Qt::Key_TouchpadToggle, Qt::ControlModifier | Qt::MetaModifier | Qt::Key_Zenkaku_Hankaku});
3110     KGlobalAccel::self()->setShortcut(touchpadToggleAction, QList<QKeySequence>{Qt::Key_TouchpadToggle, Qt::ControlModifier | Qt::MetaModifier | Qt::Key_Zenkaku_Hankaku});
3111     KGlobalAccel::self()->setDefaultShortcut(touchpadOnAction, QList<QKeySequence>{Qt::Key_TouchpadOn});
3112     KGlobalAccel::self()->setShortcut(touchpadOnAction, QList<QKeySequence>{Qt::Key_TouchpadOn});
3113     KGlobalAccel::self()->setDefaultShortcut(touchpadOffAction, QList<QKeySequence>{Qt::Key_TouchpadOff});
3114     KGlobalAccel::self()->setShortcut(touchpadOffAction, QList<QKeySequence>{Qt::Key_TouchpadOff});
3115     connect(touchpadToggleAction, &QAction::triggered, this, &InputRedirection::toggleTouchpads);
3116     connect(touchpadOnAction, &QAction::triggered, this, &InputRedirection::enableTouchpads);
3117     connect(touchpadOffAction, &QAction::triggered, this, &InputRedirection::disableTouchpads);
3118 }
3119 
3120 bool InputRedirection::hasAlphaNumericKeyboard()
3121 {
3122     return m_hasAlphaNumericKeyboard;
3123 }
3124 
3125 bool InputRedirection::hasPointer() const
3126 {
3127     return m_hasPointer;
3128 }
3129 
3130 bool InputRedirection::hasTouch() const
3131 {
3132     return m_hasTouch;
3133 }
3134 
3135 bool InputRedirection::hasTabletModeSwitch()
3136 {
3137     return m_hasTabletModeSwitch;
3138 }
3139 
3140 Qt::MouseButtons InputRedirection::qtButtonStates() const
3141 {
3142     return m_pointer->buttons();
3143 }
3144 
3145 void InputRedirection::simulateUserActivity()
3146 {
3147     for (IdleDetector *idleDetector : std::as_const(m_idleDetectors)) {
3148         idleDetector->activity();
3149     }
3150 }
3151 
3152 void InputRedirection::addIdleDetector(IdleDetector *detector)
3153 {
3154     Q_ASSERT(!m_idleDetectors.contains(detector));
3155     detector->setInhibited(!m_idleInhibitors.isEmpty());
3156     m_idleDetectors.append(detector);
3157 }
3158 
3159 void InputRedirection::removeIdleDetector(IdleDetector *detector)
3160 {
3161     m_idleDetectors.removeOne(detector);
3162 }
3163 
3164 QList<Window *> InputRedirection::idleInhibitors() const
3165 {
3166     return m_idleInhibitors;
3167 }
3168 
3169 void InputRedirection::addIdleInhibitor(Window *inhibitor)
3170 {
3171     if (!m_idleInhibitors.contains(inhibitor)) {
3172         m_idleInhibitors.append(inhibitor);
3173         for (IdleDetector *idleDetector : std::as_const(m_idleDetectors)) {
3174             idleDetector->setInhibited(true);
3175         }
3176     }
3177 }
3178 
3179 void InputRedirection::removeIdleInhibitor(Window *inhibitor)
3180 {
3181     if (m_idleInhibitors.removeOne(inhibitor) && m_idleInhibitors.isEmpty()) {
3182         for (IdleDetector *idleDetector : std::as_const(m_idleDetectors)) {
3183             idleDetector->setInhibited(false);
3184         }
3185     }
3186 }
3187 
3188 Window *InputRedirection::findToplevel(const QPointF &pos)
3189 {
3190     if (!Workspace::self()) {
3191         return nullptr;
3192     }
3193     const bool isScreenLocked = waylandServer() && waylandServer()->isScreenLocked();
3194     if (!isScreenLocked) {
3195         // if an effect overrides the cursor we don't have a window to focus
3196         if (effects && static_cast<EffectsHandlerImpl *>(effects)->isMouseInterception()) {
3197             return nullptr;
3198         }
3199     }
3200     const QList<Window *> &stacking = Workspace::self()->stackingOrder();
3201     if (stacking.isEmpty()) {
3202         return nullptr;
3203     }
3204     auto it = stacking.end();
3205     do {
3206         --it;
3207         Window *window = (*it);
3208         if (window->isDeleted()) {
3209             // a deleted window doesn't get mouse events
3210             continue;
3211         }
3212         if (!window->isOnCurrentActivity() || !window->isOnCurrentDesktop() || window->isMinimized() || window->isHiddenInternal()) {
3213             continue;
3214         }
3215         if (!window->readyForPainting()) {
3216             continue;
3217         }
3218         if (isScreenLocked) {
3219             if (!window->isLockScreen() && !window->isInputMethod() && !window->isLockScreenOverlay()) {
3220                 continue;
3221             }
3222         }
3223         if (window->hitTest(pos)) {
3224             return window;
3225         }
3226     } while (it != stacking.begin());
3227     return nullptr;
3228 }
3229 
3230 Qt::KeyboardModifiers InputRedirection::keyboardModifiers() const
3231 {
3232     return m_keyboard->modifiers();
3233 }
3234 
3235 Qt::KeyboardModifiers InputRedirection::modifiersRelevantForGlobalShortcuts() const
3236 {
3237     return m_keyboard->modifiersRelevantForGlobalShortcuts();
3238 }
3239 
3240 void InputRedirection::registerPointerShortcut(Qt::KeyboardModifiers modifiers, Qt::MouseButton pointerButtons, QAction *action)
3241 {
3242     m_shortcuts->registerPointerShortcut(action, modifiers, pointerButtons);
3243 }
3244 
3245 void InputRedirection::registerAxisShortcut(Qt::KeyboardModifiers modifiers, PointerAxisDirection axis, QAction *action)
3246 {
3247     m_shortcuts->registerAxisShortcut(action, modifiers, axis);
3248 }
3249 
3250 void InputRedirection::registerRealtimeTouchpadSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action, std::function<void(qreal)> cb)
3251 {
3252     m_shortcuts->registerRealtimeTouchpadSwipe(action, cb, direction, fingerCount);
3253 }
3254 
3255 void InputRedirection::registerTouchpadSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action)
3256 {
3257     m_shortcuts->registerTouchpadSwipe(action, direction, fingerCount);
3258 }
3259 
3260 void InputRedirection::registerTouchpadPinchShortcut(PinchDirection direction, uint fingerCount, QAction *action)
3261 {
3262     m_shortcuts->registerTouchpadPinch(action, direction, fingerCount);
3263 }
3264 
3265 void InputRedirection::registerRealtimeTouchpadPinchShortcut(PinchDirection direction, uint fingerCount, QAction *onUp, std::function<void(qreal)> progressCallback)
3266 {
3267     m_shortcuts->registerRealtimeTouchpadPinch(onUp, progressCallback, direction, fingerCount);
3268 }
3269 
3270 void InputRedirection::registerGlobalAccel(KGlobalAccelInterface *interface)
3271 {
3272     m_shortcuts->setKGlobalAccelInterface(interface);
3273 }
3274 
3275 void InputRedirection::registerTouchscreenSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action, std::function<void(qreal)> progressCallback)
3276 {
3277     m_shortcuts->registerTouchscreenSwipe(action, progressCallback, direction, fingerCount);
3278 }
3279 
3280 void InputRedirection::forceRegisterTouchscreenSwipeShortcut(SwipeDirection direction, uint fingerCount, QAction *action, std::function<void(qreal)> progressCallback)
3281 {
3282     m_shortcuts->forceRegisterTouchscreenSwipe(action, progressCallback, direction, fingerCount);
3283 }
3284 
3285 void InputRedirection::warpPointer(const QPointF &pos)
3286 {
3287     m_pointer->warp(pos);
3288 }
3289 
3290 bool InputRedirection::supportsPointerWarping() const
3291 {
3292     return m_pointer->supportsWarping();
3293 }
3294 
3295 QPointF InputRedirection::globalPointer() const
3296 {
3297     return m_pointer->pos();
3298 }
3299 
3300 void InputRedirection::startInteractiveWindowSelection(std::function<void(KWin::Window *)> callback, const QByteArray &cursorName)
3301 {
3302     if (!m_windowSelector || m_windowSelector->isActive()) {
3303         callback(nullptr);
3304         return;
3305     }
3306     m_windowSelector->start(callback);
3307     m_pointer->setWindowSelectionCursor(cursorName);
3308 }
3309 
3310 void InputRedirection::startInteractivePositionSelection(std::function<void(const QPoint &)> callback)
3311 {
3312     if (!m_windowSelector || m_windowSelector->isActive()) {
3313         callback(QPoint(-1, -1));
3314         return;
3315     }
3316     m_windowSelector->start(callback);
3317     m_pointer->setWindowSelectionCursor(QByteArray());
3318 }
3319 
3320 bool InputRedirection::isSelectingWindow() const
3321 {
3322     return m_windowSelector ? m_windowSelector->isActive() : false;
3323 }
3324 
3325 InputDeviceHandler::InputDeviceHandler(InputRedirection *input)
3326     : QObject(input)
3327 {
3328 }
3329 
3330 InputDeviceHandler::~InputDeviceHandler() = default;
3331 
3332 void InputDeviceHandler::init()
3333 {
3334     connect(workspace(), &Workspace::stackingOrderChanged, this, &InputDeviceHandler::update);
3335     connect(workspace(), &Workspace::windowMinimizedChanged, this, &InputDeviceHandler::update);
3336     connect(VirtualDesktopManager::self(), &VirtualDesktopManager::currentChanged, this, &InputDeviceHandler::update);
3337 }
3338 
3339 bool InputDeviceHandler::setHover(Window *window)
3340 {
3341     if (m_hover.window == window) {
3342         return false;
3343     }
3344     auto old = m_hover.window;
3345     disconnect(m_hover.surfaceCreatedConnection);
3346     m_hover.surfaceCreatedConnection = QMetaObject::Connection();
3347 
3348     m_hover.window = window;
3349     return true;
3350 }
3351 
3352 void InputDeviceHandler::setFocus(Window *window)
3353 {
3354     if (m_focus.window != window) {
3355         Window *oldFocus = m_focus.window;
3356         m_focus.window = window;
3357         focusUpdate(oldFocus, m_focus.window);
3358     }
3359 }
3360 
3361 void InputDeviceHandler::setDecoration(Decoration::DecoratedClientImpl *decoration)
3362 {
3363     if (m_focus.decoration != decoration) {
3364         auto oldDeco = m_focus.decoration;
3365         m_focus.decoration = decoration;
3366         cleanupDecoration(oldDeco.data(), m_focus.decoration.data());
3367         Q_EMIT decorationChanged();
3368     }
3369 }
3370 
3371 void InputDeviceHandler::updateFocus()
3372 {
3373     Window *focus = m_hover.window;
3374 
3375     if (m_focus.decoration) {
3376         focus = nullptr;
3377     } else if (m_hover.window && !m_hover.window->surface() && !m_hover.window->isInternal()) {
3378         // The surface has not yet been created (special XWayland case).
3379         // Therefore listen for its creation.
3380         if (!m_hover.surfaceCreatedConnection) {
3381             m_hover.surfaceCreatedConnection = connect(m_hover.window, &Window::surfaceChanged,
3382                                                        this, &InputDeviceHandler::update);
3383         }
3384         focus = nullptr;
3385     }
3386 
3387     setFocus(focus);
3388 }
3389 
3390 void InputDeviceHandler::updateDecoration()
3391 {
3392     Decoration::DecoratedClientImpl *decoration = nullptr;
3393     auto hover = m_hover.window.data();
3394     if (hover && hover->decoratedClient()) {
3395         if (!hover->clientGeometry().toRect().contains(flooredPoint(position()))) {
3396             // input device above decoration
3397             decoration = hover->decoratedClient();
3398         }
3399     }
3400 
3401     setDecoration(decoration);
3402 }
3403 
3404 void InputDeviceHandler::update()
3405 {
3406     if (!m_inited) {
3407         return;
3408     }
3409 
3410     Window *window = nullptr;
3411     if (positionValid()) {
3412         window = input()->findToplevel(position());
3413     }
3414     // Always set the window at the position of the input device.
3415     setHover(window);
3416 
3417     if (focusUpdatesBlocked()) {
3418         workspace()->updateFocusMousePosition(position());
3419         return;
3420     }
3421 
3422     updateDecoration();
3423     updateFocus();
3424 
3425     workspace()->updateFocusMousePosition(position());
3426 }
3427 
3428 Window *InputDeviceHandler::hover() const
3429 {
3430     return m_hover.window.data();
3431 }
3432 
3433 Window *InputDeviceHandler::focus() const
3434 {
3435     return m_focus.window.data();
3436 }
3437 
3438 Decoration::DecoratedClientImpl *InputDeviceHandler::decoration() const
3439 {
3440     return m_focus.decoration;
3441 }
3442 
3443 } // namespace
3444 
3445 #include "input.moc"