File indexing completed on 2024-11-10 04:57:57
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2019 Aleix Pol Gonzalez <aleixpol@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "tablet_input.h" 0010 #include "decorations/decoratedclient.h" 0011 #include "input_event.h" 0012 #include "input_event_spy.h" 0013 #include "pointer_input.h" 0014 #include "wayland/seat.h" 0015 #include "wayland/surface.h" 0016 #include "wayland_server.h" 0017 #include "window.h" 0018 #include "workspace.h" 0019 // KDecoration 0020 #include <KDecoration2/Decoration> 0021 // Qt 0022 #include <QHoverEvent> 0023 #include <QWindow> 0024 0025 namespace KWin 0026 { 0027 TabletInputRedirection::TabletInputRedirection(InputRedirection *parent) 0028 : InputDeviceHandler(parent) 0029 { 0030 } 0031 0032 TabletInputRedirection::~TabletInputRedirection() = default; 0033 0034 void TabletInputRedirection::init() 0035 { 0036 Q_ASSERT(!inited()); 0037 setInited(true); 0038 InputDeviceHandler::init(); 0039 0040 connect(workspace(), &QObject::destroyed, this, [this] { 0041 setInited(false); 0042 }); 0043 connect(waylandServer(), &QObject::destroyed, this, [this] { 0044 setInited(false); 0045 }); 0046 } 0047 0048 void TabletInputRedirection::tabletToolEvent(KWin::InputRedirection::TabletEventType type, const QPointF &pos, 0049 qreal pressure, int xTilt, int yTilt, qreal rotation, bool tipDown, 0050 bool tipNear, const TabletToolId &tabletToolId, 0051 std::chrono::microseconds time) 0052 { 0053 if (!inited()) { 0054 return; 0055 } 0056 input()->setLastInputHandler(this); 0057 m_lastPosition = pos; 0058 0059 QEvent::Type t; 0060 switch (type) { 0061 case InputRedirection::Axis: 0062 t = QEvent::TabletMove; 0063 break; 0064 case InputRedirection::Tip: 0065 t = tipDown ? QEvent::TabletPress : QEvent::TabletRelease; 0066 break; 0067 case InputRedirection::Proximity: 0068 t = tipNear ? QEvent::TabletEnterProximity : QEvent::TabletLeaveProximity; 0069 break; 0070 } 0071 0072 update(); 0073 workspace()->setActiveCursorOutput(pos); 0074 0075 const auto button = m_tipDown ? Qt::LeftButton : Qt::NoButton; 0076 0077 // TODO: Not correct, but it should work fine. In long term, we need to stop using QTabletEvent. 0078 const QPointingDevice *dev = QPointingDevice::primaryPointingDevice(); 0079 TabletEvent ev(t, dev, pos, pos, pressure, 0080 xTilt, yTilt, 0081 0, // tangentialPressure 0082 rotation, 0083 0, // z 0084 Qt::NoModifier, button, button, tabletToolId); 0085 0086 ev.setTimestamp(std::chrono::duration_cast<std::chrono::milliseconds>(time).count()); 0087 input()->processSpies(std::bind(&InputEventSpy::tabletToolEvent, std::placeholders::_1, &ev)); 0088 input()->processFilters( 0089 std::bind(&InputEventFilter::tabletToolEvent, std::placeholders::_1, &ev)); 0090 0091 m_tipDown = tipDown; 0092 m_tipNear = tipNear; 0093 } 0094 0095 void KWin::TabletInputRedirection::tabletToolButtonEvent(uint button, bool isPressed, 0096 const TabletToolId &tabletToolId, std::chrono::microseconds time) 0097 { 0098 input()->processSpies(std::bind(&InputEventSpy::tabletToolButtonEvent, 0099 std::placeholders::_1, button, isPressed, tabletToolId, time)); 0100 input()->processFilters(std::bind(&InputEventFilter::tabletToolButtonEvent, 0101 std::placeholders::_1, button, isPressed, tabletToolId, time)); 0102 input()->setLastInputHandler(this); 0103 } 0104 0105 void KWin::TabletInputRedirection::tabletPadButtonEvent(uint button, bool isPressed, 0106 const TabletPadId &tabletPadId, std::chrono::microseconds time) 0107 { 0108 input()->processSpies(std::bind(&InputEventSpy::tabletPadButtonEvent, 0109 std::placeholders::_1, button, isPressed, tabletPadId, time)); 0110 input()->processFilters(std::bind(&InputEventFilter::tabletPadButtonEvent, 0111 std::placeholders::_1, button, isPressed, tabletPadId, time)); 0112 input()->setLastInputHandler(this); 0113 } 0114 0115 void KWin::TabletInputRedirection::tabletPadStripEvent(int number, int position, bool isFinger, 0116 const TabletPadId &tabletPadId, std::chrono::microseconds time) 0117 { 0118 input()->processSpies(std::bind(&InputEventSpy::tabletPadStripEvent, 0119 std::placeholders::_1, number, position, isFinger, tabletPadId, time)); 0120 input()->processFilters(std::bind(&InputEventFilter::tabletPadStripEvent, 0121 std::placeholders::_1, number, position, isFinger, tabletPadId, time)); 0122 input()->setLastInputHandler(this); 0123 } 0124 0125 void KWin::TabletInputRedirection::tabletPadRingEvent(int number, int position, bool isFinger, 0126 const TabletPadId &tabletPadId, std::chrono::microseconds time) 0127 { 0128 input()->processSpies(std::bind(&InputEventSpy::tabletPadRingEvent, 0129 std::placeholders::_1, number, position, isFinger, tabletPadId, time)); 0130 input()->processFilters(std::bind(&InputEventFilter::tabletPadRingEvent, 0131 std::placeholders::_1, number, position, isFinger, tabletPadId, time)); 0132 input()->setLastInputHandler(this); 0133 } 0134 0135 bool TabletInputRedirection::focusUpdatesBlocked() 0136 { 0137 return input()->isSelectingWindow(); 0138 } 0139 0140 void TabletInputRedirection::cleanupDecoration(Decoration::DecoratedClientImpl *old, 0141 Decoration::DecoratedClientImpl *now) 0142 { 0143 disconnect(m_decorationGeometryConnection); 0144 m_decorationGeometryConnection = QMetaObject::Connection(); 0145 0146 disconnect(m_decorationDestroyedConnection); 0147 m_decorationDestroyedConnection = QMetaObject::Connection(); 0148 0149 if (old) { 0150 // send leave event to old decoration 0151 QHoverEvent event(QEvent::HoverLeave, QPointF(), QPointF()); 0152 QCoreApplication::instance()->sendEvent(old->decoration(), &event); 0153 } 0154 if (!now) { 0155 // left decoration 0156 return; 0157 } 0158 0159 const auto pos = m_lastPosition - now->window()->pos(); 0160 QHoverEvent event(QEvent::HoverEnter, pos, pos); 0161 QCoreApplication::instance()->sendEvent(now->decoration(), &event); 0162 now->window()->processDecorationMove(pos, m_lastPosition); 0163 0164 m_decorationGeometryConnection = connect( 0165 decoration()->window(), &Window::frameGeometryChanged, this, [this]() { 0166 // ensure maximize button gets the leave event when maximizing/restore a window, see BUG 385140 0167 const auto oldDeco = decoration(); 0168 update(); 0169 if (oldDeco && oldDeco == decoration() && !decoration()->window()->isInteractiveMove() && !decoration()->window()->isInteractiveResize()) { 0170 // position of window did not change, we need to send HoverMotion manually 0171 const QPointF p = m_lastPosition - decoration()->window()->pos(); 0172 QHoverEvent event(QEvent::HoverMove, p, p); 0173 QCoreApplication::instance()->sendEvent(decoration()->decoration(), &event); 0174 } 0175 }, 0176 Qt::QueuedConnection); 0177 0178 // if our decoration gets destroyed whilst it has focus, we pass focus on to the same client 0179 m_decorationDestroyedConnection = connect(now, &QObject::destroyed, this, &TabletInputRedirection::update, Qt::QueuedConnection); 0180 } 0181 0182 void TabletInputRedirection::focusUpdate(Window *focusOld, Window *focusNow) 0183 { 0184 // This method is left blank intentionally. 0185 } 0186 0187 } 0188 0189 #include "moc_tablet_input.cpp"