2 * Copyright (C) 2013,2015 Canonical, Ltd.
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.
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.
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/>.
16 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
20/* Some parts of the code were copied from the XCB platform plugin of the Qt Toolkit,
21 * which is under the following license:
24/****************************************************************************
26** Copyright (C) 2015 The Qt Company Ltd.
27** Contact: http://www.qt.io/licensing/
29** This file is part of the .
31** $QT_BEGIN_LICENSE:LGPL21$
32** Commercial License Usage
33** Licensees holding valid commercial Qt licenses may use this file in
34** accordance with the commercial license agreement provided with the
35** Software or, alternatively, in accordance with the terms contained in
36** a written agreement between you and The Qt Company. For licensing terms
37** and conditions see http://www.qt.io/terms-conditions. For further
38** information use the contact form at http://www.qt.io/contact-us.
40** GNU Lesser General Public License Usage
41** Alternatively, this file may be used under the terms of the GNU Lesser
42** General Public License version 2.1 or version 3 as published by the Free
43** Software Foundation and appearing in the file LICENSE.LGPLv21 and
44** LICENSE.LGPLv3 included in the packaging of this file. Please review the
45** following information to ensure the GNU Lesser General Public License
46** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
47** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
49** As a special exception, The Qt Company gives you certain additional
50** rights. These rights are described in The Qt Company LGPL Exception
51** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
55****************************************************************************/
57#include "MouseTouchAdaptor.h"
59#include <qpa/qplatformnativeinterface.h>
60#include <qpa/qwindowsysteminterface.h>
62#include <QCoreApplication>
66#include <X11/extensions/XInput2.h>
67#include <X11/extensions/XI2proto.h>
69using QTest::QTouchEventSequence;
72MouseTouchAdaptor *g_instance = nullptr;
74Qt::MouseButton translateMouseButton(xcb_button_t detail)
77 case 1: return Qt::LeftButton;
78 case 2: return Qt::MidButton;
79 case 3: return Qt::RightButton;
80 // Button values 4-7 are Wheel events
81 default: return Qt::NoButton;
84} // end of anonymous namespace
86MouseTouchAdaptor::MouseTouchAdaptor()
87 : QObject(nullptr), m_leftButtonIsPressed(false), m_enabled(true)
89 QCoreApplication::instance()->installNativeEventFilter(this);
91 m_touchDevice = new QTouchDevice;
92 m_touchDevice->setType(QTouchDevice::TouchScreen);
93 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
98MouseTouchAdaptor::~MouseTouchAdaptor()
100 g_instance = nullptr;
103MouseTouchAdaptor* MouseTouchAdaptor::instance()
106 g_instance = new MouseTouchAdaptor;
112void MouseTouchAdaptor::fetchXInput2Info()
114 QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
115 Display *xDisplay = static_cast<Display*>(nativeInterface->nativeResourceForIntegration("Display"));
116 if (xDisplay && XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
118 m_xi2Minor = 2; // try 2.2 first, needed for TouchBegin/Update/End
119 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
120 m_xi2Minor = 1; // for smooth scrolling 2.1 is enough
121 if (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) == BadRequest) {
122 m_xi2Minor = 0; // for tablet support 2.0 is enough
123 m_xi2Enabled = XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor) != BadRequest;
132// Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed:
133// - "pad0" became "extension"
134// - "pad1" and "pad" became "pad0"
135// New and old version of this struct share the following fields:
136// NOTE: API might change again in the next release of xcb in which case this comment will
137// need to be updated to reflect the reality.
138typedef struct qt_xcb_ge_event_t {
139 uint8_t response_type;
146bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode)
148 qt_xcb_ge_event_t *event = (qt_xcb_ge_event_t *)ev;
149 // xGenericEvent has "extension" on the second byte, the same is true for xcb_ge_event_t starting from
150 // the xcb version 1.9.3, prior to that it was called "pad0".
151 if (event->extension == opCode) {
152 // xcb event structs contain stuff that wasn't on the wire, the full_sequence field
153 // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
154 // Move this data back to have the same layout in memory as it was on the wire
155 // and allow casting, overwriting the full_sequence field.
156 memmove((char*) event + 32, (char*) event + 36, event->length * 4);
162static inline qreal fixed1616ToReal(FP1616 val)
164 return qreal(val) / 0x10000;
167bool MouseTouchAdaptor::xi2HandleEvent(xcb_ge_event_t *event)
169 if (!xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
173 xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
174 xXIDeviceEvent *xiDeviceEvent = 0;
176 switch (xiEvent->evtype) {
178 case XI_ButtonRelease:
180 xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
186 if (!xiDeviceEvent) {
190 switch (xiDeviceEvent->evtype) {
192 return handleButtonPress(
193 static_cast<WId>(xiDeviceEvent->event),
194 xiDeviceEvent->detail,
195 fixed1616ToReal(xiDeviceEvent->event_x),
196 fixed1616ToReal(xiDeviceEvent->event_y));
197 case XI_ButtonRelease:
198 return handleButtonRelease(
199 static_cast<WId>(xiDeviceEvent->event),
200 xiDeviceEvent->detail,
201 fixed1616ToReal(xiDeviceEvent->event_x),
202 fixed1616ToReal(xiDeviceEvent->event_y));
204 return handleMotionNotify(
205 static_cast<WId>(xiDeviceEvent->event),
206 fixed1616ToReal(xiDeviceEvent->event_x),
207 fixed1616ToReal(xiDeviceEvent->event_y));
215bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
216 void * message, long * /*result*/)
218 static int eventCount = 0;
224 if (eventType != "xcb_generic_event_t") {
226 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
230 xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
232 switch (xcbEvent->response_type & ~0x80) {
233 case XCB_BUTTON_PRESS: {
234 auto pressEvent = reinterpret_cast<xcb_button_press_event_t *>(xcbEvent);
235 return handleButtonPress(static_cast<WId>(pressEvent->event), pressEvent->detail,
236 pressEvent->event_x, pressEvent->event_y);
238 case XCB_BUTTON_RELEASE: {
239 auto releaseEvent = reinterpret_cast<xcb_button_release_event_t *>(xcbEvent);
240 return handleButtonRelease(static_cast<WId>(releaseEvent->event), releaseEvent->detail,
241 releaseEvent->event_x, releaseEvent->event_y);
243 case XCB_MOTION_NOTIFY: {
244 auto motionEvent = reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent);
245 return handleMotionNotify(static_cast<WId>(motionEvent->event), motionEvent->event_x, motionEvent->event_y);
249 return xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(xcbEvent));
258bool MouseTouchAdaptor::handleButtonPress(WId windowId, uint32_t detail, int x, int y)
260 Qt::MouseButton button = translateMouseButton(detail);
262 // Just eat the event if it wasn't a left mouse press
263 if (button != Qt::LeftButton)
266 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
268 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
270 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
271 false /* autoCommit */);
272 touchEvent.press(0 /* touchId */, windowPos);
273 touchEvent.commit(false /* processEvents */);
275 m_leftButtonIsPressed = true;
279bool MouseTouchAdaptor::handleButtonRelease(WId windowId, uint32_t detail, int x, int y)
281 Qt::MouseButton button = translateMouseButton(detail);
283 // Just eat the event if it wasn't a left mouse release
284 if (button != Qt::LeftButton)
287 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
289 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
291 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
292 false /* autoCommit */);
293 touchEvent.release(0 /* touchId */, windowPos);
294 touchEvent.commit(false /* processEvents */);
296 m_leftButtonIsPressed = false;
300bool MouseTouchAdaptor::handleMotionNotify(WId windowId, int x, int y)
302 if (!m_leftButtonIsPressed) {
306 QWindow *targetWindow = findQWindowWithXWindowID(windowId);
308 QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
310 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
311 false /* autoCommit */);
312 touchEvent.move(0 /* touchId */, windowPos);
313 touchEvent.commit(false /* processEvents */);
318QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
320 QWindowList windowList = QGuiApplication::topLevelWindows();
321 QWindow *foundWindow = nullptr;
324 while (!foundWindow && i < windowList.count()) {
325 QWindow *window = windowList[i];
326 if (window->winId() == windowId) {
327 foundWindow = window;
333 Q_ASSERT(foundWindow);
337bool MouseTouchAdaptor::enabled() const
342void MouseTouchAdaptor::setEnabled(bool value)
344 if (value != m_enabled) {
346 Q_EMIT enabledChanged(value);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list