on c7cb640 help sign in
unity8/src/MouseTouchAdaptor.cpp
189 lines 5.8 kB history raw
1/*
2 * Copyright (C) 2013,2015 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
17 */
19#include "MouseTouchAdaptor.h"
21#include <qpa/qwindowsysteminterface.h>
23#include <QCoreApplication>
24#include <QMouseEvent>
25#include <QTest>
27using QTest::QTouchEventSequence;
29namespace {
30MouseTouchAdaptor *g_instance = nullptr;
32Qt::MouseButton translateMouseButton(xcb_button_t detail)
34 switch (detail) {
35 case 1: return Qt::LeftButton;
36 case 2: return Qt::MidButton;
37 case 3: return Qt::RightButton;
38 // Button values 4-7 are Wheel events
39 default: return Qt::NoButton;
40 }
42} // end of anonymous namespace
44MouseTouchAdaptor::MouseTouchAdaptor()
45 : QObject(nullptr), m_leftButtonIsPressed(false), m_enabled(true)
47 QCoreApplication::instance()->installNativeEventFilter(this);
49 m_touchDevice = new QTouchDevice;
50 m_touchDevice->setType(QTouchDevice::TouchScreen);
51 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
54MouseTouchAdaptor::~MouseTouchAdaptor()
56 g_instance = nullptr;
59MouseTouchAdaptor* MouseTouchAdaptor::instance()
61 if (!g_instance) {
62 g_instance = new MouseTouchAdaptor;
63 }
65 return g_instance;
68bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
69 void * message, long * /*result*/)
71 if (!m_enabled) {
72 return false;
73 }
75 if (eventType != "xcb_generic_event_t") {
76 // wrong backend.
77 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
78 return false;
79 }
81 xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
83 switch (xcbEvent->response_type & ~0x80) {
84 case XCB_BUTTON_PRESS:
85 return handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(xcbEvent));
86 break;
87 case XCB_BUTTON_RELEASE:
88 return handleButtonRelease(reinterpret_cast<xcb_button_release_event_t *>(xcbEvent));
89 break;
90 case XCB_MOTION_NOTIFY:
91 return handleMotionNotify(reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent));
92 break;
93 default:
94 return false;
95 break;
96 };
99bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
101 Qt::MouseButton button = translateMouseButton(pressEvent->detail);
103 // Just eat the event if it wasn't a left mouse press
104 if (button != Qt::LeftButton)
105 return true;
107 QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
109 QPoint windowPos(pressEvent->event_x / targetWindow->devicePixelRatio(), pressEvent->event_y / targetWindow->devicePixelRatio());
111 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
112 false /* autoCommit */);
113 touchEvent.press(0 /* touchId */, windowPos);
114 touchEvent.commit(false /* processEvents */);
116 m_leftButtonIsPressed = true;
117 return true;
120bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseEvent)
122 Qt::MouseButton button = translateMouseButton(releaseEvent->detail);
124 // Just eat the event if it wasn't a left mouse release
125 if (button != Qt::LeftButton)
126 return true;
128 QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
130 QPoint windowPos(releaseEvent->event_x / targetWindow->devicePixelRatio(), releaseEvent->event_y / targetWindow->devicePixelRatio());
132 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
133 false /* autoCommit */);
134 touchEvent.release(0 /* touchId */, windowPos);
135 touchEvent.commit(false /* processEvents */);
137 m_leftButtonIsPressed = false;
138 return true;
141bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
143 if (!m_leftButtonIsPressed) {
144 return true;
145 }
147 QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
149 QPoint windowPos(event->event_x / targetWindow->devicePixelRatio(), event->event_y / targetWindow->devicePixelRatio());
151 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
152 false /* autoCommit */);
153 touchEvent.move(0 /* touchId */, windowPos);
154 touchEvent.commit(false /* processEvents */);
156 return true;
159QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
161 QWindowList windowList = QGuiApplication::topLevelWindows();
162 QWindow *foundWindow = nullptr;
164 int i = 0;
165 while (!foundWindow && i < windowList.count()) {
166 QWindow *window = windowList[i];
167 if (window->winId() == windowId) {
168 foundWindow = window;
169 } else {
170 ++i;
171 }
172 }
174 Q_ASSERT(foundWindow);
175 return foundWindow;
178bool MouseTouchAdaptor::enabled() const
180 return m_enabled;
183void MouseTouchAdaptor::setEnabled(bool value)
185 if (value != m_enabled) {
186 m_enabled = value;
187 Q_EMIT enabledChanged(value);
188 }