File indexing completed on 2025-04-27 11:32:59

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include "x11_standalone_effects_mouse_interception_filter.h"
0010 #include "effects.h"
0011 #include "utils/common.h"
0012 
0013 #include <QMouseEvent>
0014 
0015 namespace KWin
0016 {
0017 
0018 EffectsMouseInterceptionX11Filter::EffectsMouseInterceptionX11Filter(xcb_window_t window, EffectsHandlerImpl *effects)
0019     : X11EventFilter(QVector<int>{XCB_BUTTON_PRESS, XCB_BUTTON_RELEASE, XCB_MOTION_NOTIFY})
0020     , m_effects(effects)
0021     , m_window(window)
0022 {
0023 }
0024 
0025 bool EffectsMouseInterceptionX11Filter::event(xcb_generic_event_t *event)
0026 {
0027     const uint8_t eventType = event->response_type & ~0x80;
0028     if (eventType == XCB_BUTTON_PRESS || eventType == XCB_BUTTON_RELEASE) {
0029         auto *me = reinterpret_cast<xcb_button_press_event_t *>(event);
0030         if (m_window == me->event) {
0031             const bool isWheel = me->detail >= 4 && me->detail <= 7;
0032             if (isWheel) {
0033                 if (eventType != XCB_BUTTON_PRESS) {
0034                     return false;
0035                 }
0036                 QPoint angleDelta;
0037                 switch (me->detail) {
0038                 case 4:
0039                     angleDelta.setY(120);
0040                     break;
0041                 case 5:
0042                     angleDelta.setY(-120);
0043                     break;
0044                 case 6:
0045                     angleDelta.setX(120);
0046                     break;
0047                 case 7:
0048                     angleDelta.setX(-120);
0049                     break;
0050                 }
0051 
0052                 const Qt::MouseButtons buttons = x11ToQtMouseButtons(me->state);
0053                 const Qt::KeyboardModifiers modifiers = x11ToQtKeyboardModifiers(me->state);
0054 
0055                 if (modifiers & Qt::AltModifier) {
0056                     int x = angleDelta.x();
0057                     int y = angleDelta.y();
0058 
0059                     angleDelta.setX(y);
0060                     angleDelta.setY(x);
0061                     // After Qt > 5.14 simplify to
0062                     // angleDelta = angleDelta.transposed();
0063                 }
0064 
0065                 QWheelEvent ev(QPoint(me->event_x, me->event_y), QCursor::pos(), QPoint(), angleDelta, buttons, modifiers, Qt::NoScrollPhase, false);
0066                 ev.setTimestamp(me->time);
0067                 return m_effects->checkInputWindowEvent(&ev);
0068             }
0069             const Qt::MouseButton button = x11ToQtMouseButton(me->detail);
0070             Qt::MouseButtons buttons = x11ToQtMouseButtons(me->state);
0071             const QEvent::Type type = (eventType == XCB_BUTTON_PRESS) ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
0072             if (type == QEvent::MouseButtonPress) {
0073                 buttons |= button;
0074             } else {
0075                 buttons &= ~button;
0076             }
0077             QMouseEvent ev(type, QPoint(me->event_x, me->event_y), QPoint(me->root_x, me->root_y),
0078                            button, buttons, x11ToQtKeyboardModifiers(me->state));
0079             ev.setTimestamp(me->time);
0080             return m_effects->checkInputWindowEvent(&ev);
0081         }
0082     } else if (eventType == XCB_MOTION_NOTIFY) {
0083         const auto *me = reinterpret_cast<xcb_motion_notify_event_t *>(event);
0084         if (m_window == me->event) {
0085             QMouseEvent ev(QEvent::MouseMove, QPoint(me->event_x, me->event_y), QPoint(me->root_x, me->root_y),
0086                            Qt::NoButton, x11ToQtMouseButtons(me->state), x11ToQtKeyboardModifiers(me->state));
0087             ev.setTimestamp(me->time);
0088             return m_effects->checkInputWindowEvent(&ev);
0089         }
0090     }
0091     return false;
0092 }
0093 
0094 }