on xenial help sign in
Have "make tryFoo" work with Qt 5.5
ceb9a1fDaniel d'Andrada
CMakeLists.txt+10
@@ -128,6 +128,16 @@ if(NOT QUIET_LOGGER)
128 set(STDOUT_LOGGER "-o" "-,txt")
128 set(STDOUT_LOGGER "-o" "-,txt")
129endif()
129endif()
130
130
131+execute_process(COMMAND arch OUTPUT_VARIABLE ARCH)
132+if (NOT ARCH MATCHES "arm*")
133+ set(ENABLE_TOUCH_EMULATION true)
134+ add_definitions(-DUNITY8_ENABLE_TOUCH_EMULATION)
135+ pkg_check_modules(MOUSETOUCHADAPTOR_LIBS REQUIRED x11 xcb xi)
136+else()
137+ set(ENABLE_TOUCH_EMULATION false)
138+ message(STATUS "Touch emulation support disabled.")
139+endif()
140+
131# add subdirectories to build
141# add subdirectories to build
132add_subdirectory(include)
142add_subdirectory(include)
133add_subdirectory(libs)
143add_subdirectory(libs)
debian/control+5−1
@@ -31,7 +31,11 @@ Build-Depends: cmake,
31 libudev-dev,
31 libudev-dev,
32 libunity-api-dev (>= 7.105),
32 libunity-api-dev (>= 7.105),
33 libusermetricsoutput1-dev,
33 libusermetricsoutput1-dev,
34+# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
35+ libx11-dev[!armhf],
34− libxcb1-dev,
36+ libxcb1-dev[!armhf],
37+ libxi-dev[!armhf],
38+# End of X11 libs
35 pkg-config,
39 pkg-config,
36 python3-all:any,
40 python3-all:any,
37 python3-setuptools,
41 python3-setuptools,
src/CMakeLists.txt+13−7
@@ -16,10 +16,9 @@ file(GLOB_RECURSE QML_FILES
16 ${CMAKE_SOURCE_DIR}/tests/*.svg
16 ${CMAKE_SOURCE_DIR}/tests/*.svg
17)
17)
18
18
19−add_executable(${SHELL_APP}
19+set(SOURCE_FILES
20 ApplicationArguments.cpp
20 ApplicationArguments.cpp
21 main.cpp
21 main.cpp
22− MouseTouchAdaptor.cpp
23 CachingNetworkManagerFactory.cpp
22 CachingNetworkManagerFactory.cpp
24 SecondaryWindow.cpp
23 SecondaryWindow.cpp
25 ShellApplication.cpp
24 ShellApplication.cpp
@@ -28,15 +27,22 @@ add_executable(${SHELL_APP}
28 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
27 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
29)
28)
30
29
30+if (ENABLE_TOUCH_EMULATION)
31+ set(SOURCE_FILES ${SOURCE_FILES} MouseTouchAdaptor.cpp)
32+endif()
33+
34+pkg_check_modules(ANDROID_PROPERTIES REQUIRED libandroid-properties)
35+add_executable(${SHELL_APP} ${SOURCE_FILES})
31qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
36qt5_use_modules(${SHELL_APP} Gui Qml Quick Test)
32
37
33−pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
38+if (NOT "${ANDROID_PROPERTIES_INCLUDE_DIRS}" STREQUAL "")
34−if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
35− set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
39+ set_target_properties(${SHELL_APP} PROPERTIES INCLUDE_DIRECTORIES ${ANDROID_PROPERTIES_INCLUDE_DIRS})
36endif()
40endif()
37−target_link_libraries(${SHELL_APP} ${NEEDED_LIBS_LDFLAGS})
41+target_link_libraries(${SHELL_APP} ${ANDROID_PROPERTIES_LDFLAGS} UbuntuGestures connectivity-qt1)
38
42
43+if (ENABLE_TOUCH_EMULATION)
39−target_link_libraries(${SHELL_APP} UbuntuGestures connectivity-qt1)
44+ target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
45+endif()
40
46
41# For it to find libUbuntuGestures.so
47# For it to find libUbuntuGestures.so
42set_target_properties(${SHELL_APP} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
48set_target_properties(${SHELL_APP} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
src/Dash/CMakeLists.txt+8−8
@@ -1,25 +1,25 @@
1set(DASH_SRCS
1set(DASH_SRCS
2 main.cpp
2 main.cpp
3− ../ApplicationArguments.cpp
4− ../MouseTouchAdaptor.cpp
5 ../CachingNetworkManagerFactory.cpp
3 ../CachingNetworkManagerFactory.cpp
6)
4)
7
5
6+if (ENABLE_TOUCH_EMULATION)
7+ set(DASH_SRCS ${DASH_SRCS} ../MouseTouchAdaptor.cpp)
8+endif()
9+
8add_executable(unity8-dash ${DASH_SRCS})
10add_executable(unity8-dash ${DASH_SRCS})
9
11
10qt5_use_modules(unity8-dash Gui Qml Quick Test)
12qt5_use_modules(unity8-dash Gui Qml Quick Test)
11
13
12−pkg_check_modules(NEEDED_LIBS REQUIRED xcb libandroid-properties)
13−if (NOT "${NEEDED_LIBS_INCLUDE_DIRS}" STREQUAL "")
14− set_target_properties(unity8-dash PROPERTIES INCLUDE_DIRECTORIES ${NEEDED_LIBS_INCLUDE_DIRS})
15−endif()
16−target_link_libraries(unity8-dash ${NEEDED_LIBS_LDFLAGS})
17−
18# For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.
14# For it to find libUbuntuGestures.so, needed by Ubuntu.Gestures QML module.
19set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
15set_target_properties(unity8-dash PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
20
16
21target_link_libraries(unity8-dash UbuntuGestures connectivity-qt1)
17target_link_libraries(unity8-dash UbuntuGestures connectivity-qt1)
22
18
19+if (ENABLE_TOUCH_EMULATION)
20+ target_link_libraries(unity8-dash ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
21+endif()
22+
23set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
23set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
24
24
25# install binaries
25# install binaries
src/Dash/main.cpp+9−5
@@ -27,8 +27,9 @@
27#include <libintl.h>
27#include <libintl.h>
28
28
29#include <paths.h>
29#include <paths.h>
30+#ifdef UNITY8_ENABLE_TOUCH_EMULATION
30−#include "../MouseTouchAdaptor.h"
31+ #include "../MouseTouchAdaptor.h"
31−#include "../ApplicationArguments.h"
32+#endif
32#include "../CachingNetworkManagerFactory.h"
33#include "../CachingNetworkManagerFactory.h"
33
34
34int main(int argc, const char *argv[])
35int main(int argc, const char *argv[])
@@ -57,8 +58,6 @@ int main(int argc, const char *argv[])
57 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
58 parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
58 parser.process(*application);
59 parser.process(*application);
59
60
60− ApplicationArguments qmlArgs;
61−
62 if (getenv("QT_LOAD_TESTABILITY")) {
61 if (getenv("QT_LOAD_TESTABILITY")) {
63 QLibrary testLib(QStringLiteral("qttestability"));
62 QLibrary testLib(QStringLiteral("qttestability"));
64 if (testLib.load()) {
63 if (testLib.load()) {
@@ -92,14 +91,15 @@ int main(int argc, const char *argv[])
92 }
91 }
93
92
94 view->setTitle(QStringLiteral("Scopes"));
93 view->setTitle(QStringLiteral("Scopes"));
95− view->rootContext()->setContextProperty(QStringLiteral("applicationArguments"), &qmlArgs);
96
94
95+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
97 // You will need this if you want to interact with touch-only components using a mouse
96 // You will need this if you want to interact with touch-only components using a mouse
98 // Needed only when manually testing on a desktop.
97 // Needed only when manually testing on a desktop.
99 MouseTouchAdaptor *mouseTouchAdaptor = 0;
98 MouseTouchAdaptor *mouseTouchAdaptor = 0;
100 if (parser.isSet(mousetouchOption)) {
99 if (parser.isSet(mousetouchOption)) {
101 mouseTouchAdaptor = MouseTouchAdaptor::instance();
100 mouseTouchAdaptor = MouseTouchAdaptor::instance();
102 }
101 }
102+ #endif
103
103
104 QUrl source(::qmlDirectory() + "/Dash/DashApplication.qml");
104 QUrl source(::qmlDirectory() + "/Dash/DashApplication.qml");
105 prependImportPaths(view->engine(), ::overrideImportPaths());
105 prependImportPaths(view->engine(), ::overrideImportPaths());
@@ -114,7 +114,11 @@ int main(int argc, const char *argv[])
114 int result = application->exec();
114 int result = application->exec();
115
115
116 delete view;
116 delete view;
117+
118+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
117 delete mouseTouchAdaptor;
119 delete mouseTouchAdaptor;
120+ #endif
121+
118 delete application;
122 delete application;
119
123
120 return result;
124 return result;
src/MouseTouchAdaptor.cpp+180−21
@@ -16,14 +16,56 @@
16 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
16 * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
17 */
17 */
18
18
19+
20+/* Some parts of the code were copied from the XCB platform plugin of the Qt Toolkit,
21+ * which is under the following license:
22+ */
23+
24+/****************************************************************************
25+**
26+** Copyright (C) 2015 The Qt Company Ltd.
27+** Contact: http://www.qt.io/licensing/
28+**
29+** This file is part of the .
30+**
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.
39+**
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.
48+**
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.
52+**
53+** $QT_END_LICENSE$
54+**
55+****************************************************************************/
56+
19#include "MouseTouchAdaptor.h"
57#include "MouseTouchAdaptor.h"
20
58
59+#include <qpa/qplatformnativeinterface.h>
21#include <qpa/qwindowsysteminterface.h>
60#include <qpa/qwindowsysteminterface.h>
22
61
23#include <QCoreApplication>
62#include <QCoreApplication>
24#include <QMouseEvent>
63#include <QMouseEvent>
25#include <QTest>
64#include <QTest>
26
65
66+#include <X11/extensions/XInput2.h>
67+#include <X11/extensions/XI2proto.h>
68+
27using QTest::QTouchEventSequence;
69using QTest::QTouchEventSequence;
28
70
29namespace {
71namespace {
@@ -49,6 +91,8 @@ MouseTouchAdaptor::MouseTouchAdaptor()
49 m_touchDevice = new QTouchDevice;
91 m_touchDevice = new QTouchDevice;
50 m_touchDevice->setType(QTouchDevice::TouchScreen);
92 m_touchDevice->setType(QTouchDevice::TouchScreen);
51 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
93 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
94+
95+ fetchXInput2Info();
52}
96}
53
97
54MouseTouchAdaptor::~MouseTouchAdaptor()
98MouseTouchAdaptor::~MouseTouchAdaptor()
@@ -65,9 +109,114 @@ MouseTouchAdaptor* MouseTouchAdaptor::instance()
65 return g_instance;
109 return g_instance;
66}
110}
67
111
112+void MouseTouchAdaptor::fetchXInput2Info()
113+{
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)) {
117+ int xiMajor = 2;
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;
124+ } else
125+ m_xi2Enabled = true;
126+ } else {
127+ m_xi2Enabled = true;
128+ }
129+ }
130+}
131+
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.
138+typedef struct qt_xcb_ge_event_t {
139+ uint8_t response_type;
140+ uint8_t extension;
141+ uint16_t sequence;
142+ uint32_t length;
143+ uint16_t event_type;
144+} qt_xcb_ge_event_t;
145+
146+bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCode)
147+{
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);
157+ return true;
158+ }
159+ return false;
160+}
161+
162+static inline qreal fixed1616ToReal(FP1616 val)
163+{
164+ return qreal(val) / 0x10000;
165+}
166+
167+bool MouseTouchAdaptor::xi2HandleEvent(xcb_ge_event_t *event)
168+{
169+ if (!xi2PrepareXIGenericDeviceEvent(event, m_xiOpCode)) {
170+ return false;
171+ }
172+
173+ xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event);
174+ xXIDeviceEvent *xiDeviceEvent = 0;
175+
176+ switch (xiEvent->evtype) {
177+ case XI_ButtonPress:
178+ case XI_ButtonRelease:
179+ case XI_Motion:
180+ xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
181+ break;
182+ default:
183+ break;
184+ }
185+
186+ if (!xiDeviceEvent) {
187+ return false;
188+ }
189+
190+ switch (xiDeviceEvent->evtype) {
191+ case XI_ButtonPress:
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));
203+ case XI_Motion:
204+ return handleMotionNotify(
205+ static_cast<WId>(xiDeviceEvent->event),
206+ fixed1616ToReal(xiDeviceEvent->event_x),
207+ fixed1616ToReal(xiDeviceEvent->event_y));
208+ return true;
209+ default:
210+ return false;
211+ }
212+}
213+
214+
68bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
215bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
69 void * message, long * /*result*/)
216 void * message, long * /*result*/)
70{
217{
218+ static int eventCount = 0;
219+ eventCount++;
71 if (!m_enabled) {
220 if (!m_enabled) {
72 return false;
221 return false;
73 }
222 }
@@ -81,32 +230,42 @@ bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
81 xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
230 xcb_generic_event_t *xcbEvent = static_cast<xcb_generic_event_t *>(message);
82
231
83 switch (xcbEvent->response_type & ~0x80) {
232 switch (xcbEvent->response_type & ~0x80) {
84− case XCB_BUTTON_PRESS:
233+ case XCB_BUTTON_PRESS: {
85− return handleButtonPress(reinterpret_cast<xcb_button_press_event_t *>(xcbEvent));
234+ auto pressEvent = reinterpret_cast<xcb_button_press_event_t *>(xcbEvent);
86− break;
235+ return handleButtonPress(static_cast<WId>(pressEvent->event), pressEvent->detail,
236+ pressEvent->event_x, pressEvent->event_y);
237+ }
87− case XCB_BUTTON_RELEASE:
238+ case XCB_BUTTON_RELEASE: {
88− return handleButtonRelease(reinterpret_cast<xcb_button_release_event_t *>(xcbEvent));
239+ auto releaseEvent = reinterpret_cast<xcb_button_release_event_t *>(xcbEvent);
89− break;
240+ return handleButtonRelease(static_cast<WId>(releaseEvent->event), releaseEvent->detail,
241+ releaseEvent->event_x, releaseEvent->event_y);
242+ }
90− case XCB_MOTION_NOTIFY:
243+ case XCB_MOTION_NOTIFY: {
91− return handleMotionNotify(reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent));
244+ auto motionEvent = reinterpret_cast<xcb_motion_notify_event_t *>(xcbEvent);
92− break;
245+ return handleMotionNotify(static_cast<WId>(motionEvent->event), motionEvent->event_x, motionEvent->event_y);
246+ }
247+ case XCB_GE_GENERIC:
248+ if (m_xi2Enabled) {
249+ return xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(xcbEvent));
250+ } else {
251+ return false;
252+ }
93 default:
253 default:
94 return false;
254 return false;
95− break;
96 };
255 };
97}
256}
98
257
99−bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
258+bool MouseTouchAdaptor::handleButtonPress(WId windowId, uint32_t detail, int x, int y)
100{
259{
101− Qt::MouseButton button = translateMouseButton(pressEvent->detail);
260+ Qt::MouseButton button = translateMouseButton(detail);
102
261
103 // Just eat the event if it wasn't a left mouse press
262 // Just eat the event if it wasn't a left mouse press
104 if (button != Qt::LeftButton)
263 if (button != Qt::LeftButton)
105 return true;
264 return true;
106
265
107− QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
266+ QWindow *targetWindow = findQWindowWithXWindowID(windowId);
108
267
109− QPoint windowPos(pressEvent->event_x / targetWindow->devicePixelRatio(), pressEvent->event_y / targetWindow->devicePixelRatio());
268+ QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
110
269
111 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
270 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
112 false /* autoCommit */);
271 false /* autoCommit */);
@@ -117,17 +276,17 @@ bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
117 return true;
276 return true;
118}
277}
119
278
120−bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseEvent)
279+bool MouseTouchAdaptor::handleButtonRelease(WId windowId, uint32_t detail, int x, int y)
121{
280{
122− Qt::MouseButton button = translateMouseButton(releaseEvent->detail);
281+ Qt::MouseButton button = translateMouseButton(detail);
123
282
124 // Just eat the event if it wasn't a left mouse release
283 // Just eat the event if it wasn't a left mouse release
125 if (button != Qt::LeftButton)
284 if (button != Qt::LeftButton)
126 return true;
285 return true;
127
286
128− QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
287+ QWindow *targetWindow = findQWindowWithXWindowID(windowId);
129
288
130− QPoint windowPos(releaseEvent->event_x / targetWindow->devicePixelRatio(), releaseEvent->event_y / targetWindow->devicePixelRatio());
289+ QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
131
290
132 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
291 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
133 false /* autoCommit */);
292 false /* autoCommit */);
@@ -138,15 +297,15 @@ bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseE
138 return true;
297 return true;
139}
298}
140
299
141−bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
300+bool MouseTouchAdaptor::handleMotionNotify(WId windowId, int x, int y)
142{
301{
143 if (!m_leftButtonIsPressed) {
302 if (!m_leftButtonIsPressed) {
144 return true;
303 return true;
145 }
304 }
146
305
147− QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
306+ QWindow *targetWindow = findQWindowWithXWindowID(windowId);
148
307
149− QPoint windowPos(event->event_x / targetWindow->devicePixelRatio(), event->event_y / targetWindow->devicePixelRatio());
308+ QPoint windowPos(x / targetWindow->devicePixelRatio(), y / targetWindow->devicePixelRatio());
150
309
151 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
310 QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
152 false /* autoCommit */);
311 false /* autoCommit */);
src/MouseTouchAdaptor.h+10−3
@@ -21,6 +21,7 @@
21
21
22#include <QtCore/QAbstractNativeEventFilter>
22#include <QtCore/QAbstractNativeEventFilter>
23#include <QWindow>
23#include <QWindow>
24+
24#include <xcb/xcb.h>
25#include <xcb/xcb.h>
25
26
26class QMouseEvent;
27class QMouseEvent;
@@ -47,16 +48,22 @@ Q_SIGNALS:
47
48
48private:
49private:
49 MouseTouchAdaptor();
50 MouseTouchAdaptor();
51+ void fetchXInput2Info();
52+ bool xi2HandleEvent(xcb_ge_event_t *event);
50
53
51− bool handleButtonPress(xcb_button_press_event_t *pressEvent);
54+ bool handleButtonPress(WId windowId, uint32_t detail, int x, int y);
52− bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
55+ bool handleButtonRelease(WId windowId, uint32_t detail, int x, int y);
53− bool handleMotionNotify(xcb_motion_notify_event_t *event);
56+ bool handleMotionNotify(WId windowId, int x, int y);
54 QWindow *findQWindowWithXWindowID(WId windowId);
57 QWindow *findQWindowWithXWindowID(WId windowId);
55
58
56 QTouchDevice *m_touchDevice;
59 QTouchDevice *m_touchDevice;
57 bool m_leftButtonIsPressed;
60 bool m_leftButtonIsPressed;
58
61
59 bool m_enabled;
62 bool m_enabled;
63+
64+ bool m_xi2Enabled{false};
65+ int m_xi2Minor{-1};
66+ int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
60};
67};
61
68
62#endif // MOUSE_TOUCH_ADAPTOR_H
69#endif // MOUSE_TOUCH_ADAPTOR_H
src/ShellApplication.cpp+5−5
@@ -28,15 +28,10 @@
28// local
28// local
29#include <paths.h>
29#include <paths.h>
30#include "CachingNetworkManagerFactory.h"
30#include "CachingNetworkManagerFactory.h"
31−#include "MouseTouchAdaptor.h"
32#include "UnityCommandLineParser.h"
31#include "UnityCommandLineParser.h"
33
32
34ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
33ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
35 : QGuiApplication(argc, argv)
34 : QGuiApplication(argc, argv)
36− , m_shellView(nullptr)
37− , m_secondaryWindow(nullptr)
38− , m_mouseTouchAdaptor(nullptr)
39− , m_qmlEngine(nullptr)
40{
35{
41
36
42 setApplicationName(QStringLiteral("unity8"));
37 setApplicationName(QStringLiteral("unity8"));
@@ -89,11 +84,14 @@ ShellApplication::ShellApplication(int & argc, char ** argv, bool isMirServer)
89 m_shellView->setFlags(Qt::FramelessWindowHint);
84 m_shellView->setFlags(Qt::FramelessWindowHint);
90 }
85 }
91
86
87+
88+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
92 // You will need this if you want to interact with touch-only components using a mouse
89 // You will need this if you want to interact with touch-only components using a mouse
93 // Needed only when manually testing on a desktop.
90 // Needed only when manually testing on a desktop.
94 if (parser.hasMouseToTouch()) {
91 if (parser.hasMouseToTouch()) {
95 m_mouseTouchAdaptor = MouseTouchAdaptor::instance();
92 m_mouseTouchAdaptor = MouseTouchAdaptor::instance();
96 }
93 }
94+ #endif
97
95
98
96
99 // Some hard-coded policy for now.
97 // Some hard-coded policy for now.
@@ -134,8 +132,10 @@ void ShellApplication::destroyResources()
134 delete m_secondaryWindow;
132 delete m_secondaryWindow;
135 m_secondaryWindow = nullptr;
133 m_secondaryWindow = nullptr;
136
134
135+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
137 delete m_mouseTouchAdaptor;
136 delete m_mouseTouchAdaptor;
138 m_mouseTouchAdaptor = nullptr;
137 m_mouseTouchAdaptor = nullptr;
138+ #endif
139
139
140 delete m_qmlEngine;
140 delete m_qmlEngine;
141 m_qmlEngine = nullptr;
141 m_qmlEngine = nullptr;
src/ShellApplication.h+12−4
@@ -23,7 +23,11 @@
23#include <QScopedPointer>
23#include <QScopedPointer>
24
24
25#include "ApplicationArguments.h"
25#include "ApplicationArguments.h"
26+
27+#ifdef UNITY8_ENABLE_TOUCH_EMULATION
26#include "MouseTouchAdaptor.h"
28#include "MouseTouchAdaptor.h"
29+#endif
30+
27#include "SecondaryWindow.h"
31#include "SecondaryWindow.h"
28#include "ShellView.h"
32#include "ShellView.h"
29
33
@@ -46,10 +50,14 @@ private:
46 void setupQmlEngine(bool isMirServer);
50 void setupQmlEngine(bool isMirServer);
47 QString m_deviceName;
51 QString m_deviceName;
48 ApplicationArguments m_qmlArgs;
52 ApplicationArguments m_qmlArgs;
49− ShellView *m_shellView;
53+ ShellView *m_shellView{nullptr};
50− SecondaryWindow *m_secondaryWindow;
54+ SecondaryWindow *m_secondaryWindow{nullptr};
55+
56+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
51− MouseTouchAdaptor *m_mouseTouchAdaptor;
57+ MouseTouchAdaptor *m_mouseTouchAdaptor{nullptr};
58+ #endif
59+
52− QQmlEngine *m_qmlEngine;
60+ QQmlEngine *m_qmlEngine{nullptr};
53};
61};
54
62
55#endif // SHELLAPPLICATION_H
63#endif // SHELLAPPLICATION_H
src/UnityCommandLineParser.cpp+6
@@ -37,9 +37,11 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
37 QStringLiteral("Run without window borders"));
37 QStringLiteral("Run without window borders"));
38 parser.addOption(framelessOption);
38 parser.addOption(framelessOption);
39
39
40+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
40 QCommandLineOption mousetouchOption(QStringLiteral("mousetouch"),
41 QCommandLineOption mousetouchOption(QStringLiteral("mousetouch"),
41 QStringLiteral("Allow the mouse to provide touch input"));
42 QStringLiteral("Allow the mouse to provide touch input"));
42 parser.addOption(mousetouchOption);
43 parser.addOption(mousetouchOption);
44+ #endif
43
45
44 QCommandLineOption windowGeometryOption(QStringList() << QStringLiteral("windowgeometry"),
46 QCommandLineOption windowGeometryOption(QStringList() << QStringLiteral("windowgeometry"),
45 QStringLiteral("Specify the window geometry as [<width>x<height>]"), QStringLiteral("windowgeometry"), QStringLiteral("1"));
47 QStringLiteral("Specify the window geometry as [<width>x<height>]"), QStringLiteral("windowgeometry"), QStringLiteral("1"));
@@ -75,7 +77,11 @@ UnityCommandLineParser::UnityCommandLineParser(const QCoreApplication &app)
75
77
76 m_hasTestability = parser.isSet(testabilityOption);
78 m_hasTestability = parser.isSet(testabilityOption);
77 m_hasFrameless = parser.isSet(framelessOption);
79 m_hasFrameless = parser.isSet(framelessOption);
80+
81+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
78 m_hasMouseToTouch = parser.isSet(mousetouchOption);
82 m_hasMouseToTouch = parser.isSet(mousetouchOption);
83+ #endif
84+
79 m_hasFullscreen = parser.isSet(fullscreenOption);
85 m_hasFullscreen = parser.isSet(fullscreenOption);
80 m_deviceName = parser.value(devicenameOption);
86 m_deviceName = parser.value(devicenameOption);
81 resolveMode(parser, modeOption);
87 resolveMode(parser, modeOption);
src/UnityCommandLineParser.h+8
@@ -28,7 +28,11 @@ public:
28 QSize windowGeometry() const { return m_windowGeometry; }
28 QSize windowGeometry() const { return m_windowGeometry; }
29 bool hasTestability() const { return m_hasTestability; }
29 bool hasTestability() const { return m_hasTestability; }
30 bool hasFrameless() const { return m_hasFrameless; }
30 bool hasFrameless() const { return m_hasFrameless; }
31+
32+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
31 bool hasMouseToTouch() const { return m_hasMouseToTouch; }
33 bool hasMouseToTouch() const { return m_hasMouseToTouch; }
34+ #endif
35+
32 bool hasFullscreen() const { return m_hasFullscreen; }
36 bool hasFullscreen() const { return m_hasFullscreen; }
33 QString deviceName() const { return m_deviceName; }
37 QString deviceName() const { return m_deviceName; }
34 QString mode() const { return m_mode; }
38 QString mode() const { return m_mode; }
@@ -43,7 +47,11 @@ private:
43 QSize m_windowGeometry;
47 QSize m_windowGeometry;
44 bool m_hasTestability;
48 bool m_hasTestability;
45 bool m_hasFrameless;
49 bool m_hasFrameless;
50+
51+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
46 bool m_hasMouseToTouch;
52 bool m_hasMouseToTouch;
53+ #endif
54+
47 bool m_hasFullscreen;
55 bool m_hasFullscreen;
48 QString m_deviceName;
56 QString m_deviceName;
49 QString m_mode;
57 QString m_mode;
tests/qmltests/CMakeLists.txt+1−1
@@ -87,4 +87,4 @@ add_unity8_qmltest(Stages WindowResizeArea)
87add_unity8_qmltest(Stages Splash)
87add_unity8_qmltest(Stages Splash)
88add_unity8_qmltest(Tutorial Tutorial LIGHTDM)
88add_unity8_qmltest(Tutorial Tutorial LIGHTDM)
89add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
89add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
90−add_unity8_qmlunittest(utils/Unity/Test UnityTest)
90+add_unity8_qmltest(utils/Unity/Test UnityTest)
tests/utils/modules/Unity/Test/CMakeLists.txt+8−1
@@ -13,12 +13,19 @@ set(UnityTestQML_SOURCES
13 testutil.cpp
13 testutil.cpp
14 plugin.cpp
14 plugin.cpp
15 TouchEventSequenceWrapper.cpp
15 TouchEventSequenceWrapper.cpp
16− ${CMAKE_SOURCE_DIR}/src/MouseTouchAdaptor.cpp
17)
16)
18
17
18+if (ENABLE_TOUCH_EMULATION)
19+ set(UnityTestQML_SOURCES ${UnityTestQML_SOURCES} ${CMAKE_SOURCE_DIR}/src/MouseTouchAdaptor.cpp)
20+endif()
21+
19add_library(UnityTestQml MODULE ${UnityTestQML_SOURCES})
22add_library(UnityTestQml MODULE ${UnityTestQML_SOURCES})
20target_link_libraries(UnityTestQml UbuntuGestures)
23target_link_libraries(UnityTestQml UbuntuGestures)
21
24
25+if (ENABLE_TOUCH_EMULATION)
26+ target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
27+endif()
28+
22qt5_use_modules(UnityTestQml Core Quick Test)
29qt5_use_modules(UnityTestQml Core Quick Test)
23
30
24export_qmlfiles(Unity.Test Unity/Test)
31export_qmlfiles(Unity.Test Unity/Test)
tests/utils/modules/Unity/Test/plugin.cpp+13−3
@@ -17,7 +17,11 @@
17
17
18#include "plugin.h"
18#include "plugin.h"
19#include "testutil.h"
19#include "testutil.h"
20+
21+#ifdef UNITY8_ENABLE_TOUCH_EMULATION
20#include <MouseTouchAdaptor.h>
22#include <MouseTouchAdaptor.h>
23+#endif
24+
21#include "TouchEventSequenceWrapper.h"
25#include "TouchEventSequenceWrapper.h"
22
26
23#include <qqml.h>
27#include <qqml.h>
@@ -27,23 +31,29 @@ QObject *testutil_provider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine
27{
31{
28 return new TestUtil();
32 return new TestUtil();
29}
33}
34+
35+#ifdef UNITY8_ENABLE_TOUCH_EMULATION
30QObject *getMouseTouchAdaptorQMLSingleton(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
36QObject *getMouseTouchAdaptorQMLSingleton(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
31{
37{
32 return MouseTouchAdaptor::instance();
38 return MouseTouchAdaptor::instance();
33}
39}
40+#endif
41+
34} // anonymous namespace
42} // anonymous namespace
35
43
36void UnityTestPlugin::registerTypes(const char *uri)
44void UnityTestPlugin::registerTypes(const char *uri)
37{
45{
38 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Test"));
46 Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Test"));
39
47
40− // Ensure the instance gets created
41− MouseTouchAdaptor::instance();
42−
43 // @uri Unity.Test
48 // @uri Unity.Test
44 qmlRegisterSingletonType<TestUtil>(uri, 0, 1, "Util", testutil_provider);
49 qmlRegisterSingletonType<TestUtil>(uri, 0, 1, "Util", testutil_provider);
45 qmlRegisterUncreatableType<TouchEventSequenceWrapper>(uri, 0, 1, "TouchEventSequence",
50 qmlRegisterUncreatableType<TouchEventSequenceWrapper>(uri, 0, 1, "TouchEventSequence",
46 "You cannot directly create a TouchEventSequence object.");
51 "You cannot directly create a TouchEventSequence object.");
52+
53+ #ifdef UNITY8_ENABLE_TOUCH_EMULATION
54+ // Ensure the instance gets created
55+ MouseTouchAdaptor::instance();
47 qmlRegisterSingletonType<MouseTouchAdaptor>(uri, 0, 1, "MouseTouchAdaptor",
56 qmlRegisterSingletonType<MouseTouchAdaptor>(uri, 0, 1, "MouseTouchAdaptor",
48 getMouseTouchAdaptorQMLSingleton);
57 getMouseTouchAdaptorQMLSingleton);
58+ #endif
49}
59}