Merge lp:~dandrader/qtmir/missingTouchEnd-lp1295623 into lp:qtmir

Proposed by Daniel d'Andrada
Status: Merged
Approved by: Gerry Boland
Approved revision: 245
Merged at revision: 244
Proposed branch: lp:~dandrader/qtmir/missingTouchEnd-lp1295623
Merge into: lp:qtmir
Diff against target: 984 lines (+608/-62)
18 files modified
src/common/debughelpers.cpp (+38/-6)
src/common/debughelpers.h (+2/-1)
src/modules/Unity/Application/Application.pro (+3/-3)
src/modules/Unity/Application/application.cpp (+3/-1)
src/modules/Unity/Application/mirsurfaceitem.cpp (+3/-1)
src/modules/Unity/Application/mirsurfacemanager.cpp (+3/-1)
src/platforms/mirserver/logging.h (+1/-0)
src/platforms/mirserver/mirserver.pro (+4/-0)
src/platforms/mirserver/qteventfeeder.cpp (+175/-18)
src/platforms/mirserver/qteventfeeder.h (+31/-1)
tests/google-mock.pri (+24/-0)
tests/mirserver/QtEventFeeder/QtEventFeeder.pro (+16/-0)
tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h (+65/-0)
tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp (+224/-0)
tests/mirserver/mirserver.pro (+2/-0)
tests/modules/common/common.pri (+4/-29)
tests/test-includes.pri (+9/-0)
tests/tests.pro (+1/-1)
To merge this branch: bzr merge lp:~dandrader/qtmir/missingTouchEnd-lp1295623
Reviewer Review Type Date Requested Status
Gerry Boland (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+232410@code.launchpad.net

Commit message

QtEventFeeder: validate touches before sending them to Qt

Make sure we send a tidy touch event stream to Qt as some of it
(QQuickWindow) is vulnerable to things like missing touch releases.

Also properly ignore unsupported motion event actions such as hovering.

Description of the change

Should fix https://launchpad.net/bugs/1295623

There's also this simple desktop application that exemplifies the situation that makes QQuickWindow stop generating mouse events, which is believed to be the cause of the bug above.
https://code.launchpad.net/~dandrader/+junk/touchToMouse

It captures raw mouse events and send synthesized touch events to the QQuickWindow out of them.
- Left button mouse clicks are translated to touch taps.
- Middle button mouse clicks are translated to touch taps as well with the difference that it omits the corresponding TouchEnd (thus emulating the bogus situation).

Left-click all rectangles and see that they happily blink. Then middle-click once a MouseArea. From that point onwards no mouse area will *ever* react to any left-click anymore. They get stuck forever. The touch area though will continue working normally.

I've made a patch for Qt to make QQuickWindow more robust, thus avoid entering in such bogus state, but I decided to solve it in the platform abstraction level as the qt patch is not a crowd pleaser.
https://codereview.qt-project.org/93002

* Are there any related MPs required for this MP to build/function as expected? Please list.
No.

* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes.

* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Things I'd like clarified in a big comment in this code:
1. this is a workaround for a bug in Qt? If yes, please add the QTBUG number, plus a short textual description of that bug. It/when it gets fixed upstream, presumably we can remove this?
2. is this also processing slightly screwed up events from Mir so that they make sense to Qt? Other toolkits may also choke on this, so we should have a Mir bug on this topic - and reference it in this code too.

Code review:
+++ src/platforms/mirserver/qteventfeeder.h
+ class QtWindowSystem {
This is actually a interface, please call it QtWindowSystemInterface - hopefully it doesn't clash with Qt's defined one. Else QtMirWindowSystemInterface maybe? Is it a Window really? :)

+++ src/platforms/mirserver/qteventfeeder.cpp
+ class RealQtWindowSystem
if you do the above rename, then you can remove "Real" from the name - it confused me when I saw it first (though I understand now you mean not-Mock)

Class is very single-monitor specific, please add a "FIXME - won't work with multimonitor" somewhere - I know that the QtEventFeeder has the same issue, but I just want to document it clearly for ourselves when we start thinking about desktop.

+ int mirMotionAction = event.action & MirEventActionMask;
const?

+ // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
+ // any insanity.
Add QTBUG here perhaps?

+ qCWarning(QTMIR_MIR_MESSAGES)
I think a dedicated logging category for this would make sense. QTMIR_INPUT_PROCESSING -> qtmir.mir.input maybe?

+void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
+{
+ EXPECT_CALL(*mockWindowSystem, hasTargetWindow())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())
+ .Times(AnyNumber())
+ .WillRepeatedly(Return(QRect(0,0,100,100)));
+}
Nice method name :D They're not exactly irrelevant though. Since you call it before tests run, can't it be run as part of SetUp()?

+ .Times(1);
I don't like it alone on it's own line. Almost looks like a statement of its own.

+ setIrrelevantMockWindowSystemExpectations();
why do you keep calling this? You use .Times(AnyNumber()).WillRepeatedly(Return(true)) so it should not need resetting

+TEST_F(QtEventFeederTest, GenerateMissingTouchEnd)
This test generates a Press event at (10,10). You check press event passed to Qt. Next generate Press event at (20, 20). You ensure this event also generates a Release event for the previous event.
- would help to add this comment to the test. Sorry, but I'm considering somebody other than you or I reading this code!

Otherwise looks good.

Will do functional testing now

review: Needs Fixing (code)
Revision history for this message
Gerry Boland (gerboland) wrote :

Desktop tests ok

Revision history for this message
Gerry Boland (gerboland) wrote :

I don't see any regression on the phone either.

I still can make apps hang by doing lots of stupid multi-finger gestures. Which confuses me, as I expected your event processing to fix that.

review: Approve
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> I don't see any regression on the phone either.
>
> I still can make apps hang by doing lots of stupid multi-finger gestures.
> Which confuses me, as I expected your event processing to fix that.

That patch ensures that *unity8* receives a clean stream of touch events.
But whether unity8 on its part sends a clean stream of touch events to applications, that's another story

241. By Daniel d'Andrada

QtEventFeeder: s/QtWindowSystem/QtWindowSystemInterface

242. By Daniel d'Andrada

Add a TODO notice to that new internal interface

243. By Daniel d'Andrada

Declare mirMotionAction a const as it's not meant to be changed

244. By Daniel d'Andrada

Using a new logging category

245. By Daniel d'Andrada

Comment/explain QtEventFeederTest::GenerateMissingTouchEnd

Revision history for this message
Daniel d'Andrada (dandrader) wrote :
Download full text (4.1 KiB)

> Things I'd like clarified in a big comment in this code:
> 1. this is a workaround for a bug in Qt? If yes, please add the QTBUG number,
> plus a short textual description of that bug. It/when it gets fixed upstream,
> presumably we can remove this?
> 2. is this also processing slightly screwed up events from Mir so that they
> make sense to Qt? Other toolkits may also choke on this, so we should have a
> Mir bug on this topic - and reference it in this code too.
>
>
> Code review:
> +++ src/platforms/mirserver/qteventfeeder.h
> + class QtWindowSystem {
> This is actually a interface, please call it QtWindowSystemInterface -
> hopefully it doesn't clash with Qt's defined one. Else
> QtMirWindowSystemInterface maybe? Is it a Window really? :)

It's impossible to have a clash with anything coming with because it's defined *inside* QtEventFeeder class. So it's inside QtEventFeeder's namespace sort of. It's also prefixed with "Qt", whereas Qt itself uses just "Q" for prefixing its classes.

Changed it to adhere to the "FooInterface" convention.

>
> +++ src/platforms/mirserver/qteventfeeder.cpp
> + class RealQtWindowSystem
> if you do the above rename, then you can remove "Real" from the name - it
> confused me when I saw it first (though I understand now you mean not-Mock)

Done.

>
> Class is very single-monitor specific, please add a "FIXME - won't work with
> multimonitor" somewhere - I know that the QtEventFeeder has the same issue,
> but I just want to document it clearly for ourselves when we start thinking
> about desktop.

Done.

>
> + int mirMotionAction = event.action & MirEventActionMask;
> const?
>

Done.

> + // Qt needs a happy, sane stream of touch events. So let's make sure we're
> not forwarding
> + // any insanity.
> Add QTBUG here perhaps?

hmm... Not necessarily a bug as you cannot really assume that Qt should cope with a messed up platform abstraction. It would be great if it did, but not a necessity.

>
> + qCWarning(QTMIR_MIR_MESSAGES)
> I think a dedicated logging category for this would make sense.
> QTMIR_INPUT_PROCESSING -> qtmir.mir.input maybe?

Done.

>
> +void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
> +{
> + EXPECT_CALL(*mockWindowSystem, hasTargetWindow())
> + .Times(AnyNumber())
> + .WillRepeatedly(Return(true));
> + EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())
> + .Times(AnyNumber())
> + .WillRepeatedly(Return(QRect(0,0,100,100)));
> +}
> Nice method name :D They're not exactly irrelevant though. Since you call it
> before tests run, can't it be run as part of SetUp()?

They are irrelevant because the tests don't care about them. They are like uninteresting implementation details needed to get things working, from the tests point of view.

They can't be part of SetUp() because they have to be done more than once during a test. Everytime Mock::VerifyAndClearExpectations(mockWindowSystem) is called, all expectations are cleared/removed, as the method name says. So you have to set those expectations again after it.

>
> + .Times(1);
> I don't like it alone on it's own line. Almost looks like a statement of its
> own.

It's standard google mock coding style but ok, changed...

Read more...

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Things I'd like clarified in a big comment in this code:
> 1. this is a workaround for a bug in Qt?

I wouldn't say it's a bug in Qt. It's just that Qt is more sensible to garbage coming from platform abstraction than we would like. So it would be a nice improvement if it would be more resilient/robust.

> If yes, please add the QTBUG number,
> plus a short textual description of that bug. It/when it gets fixed upstream,
> presumably we can remove this?
> 2. is this also processing slightly screwed up events from Mir so that they
> make sense to Qt? Other toolkits may also choke on this, so we should have a
> Mir bug on this topic - and reference it in this code too.

It's not only about protecting against possible garbage coming from Mir, but also about sanity checking what QtEventFeeder itself does before finally sending the generated touch events down to Qt. Previously, for instance, there was a good chance that QtEventFeeder was sending some (possibly inconsistent) touch events in reaction to mir hover events.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

Perfect, thank you

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'src/common'
2=== renamed file 'src/modules/Unity/Application/debughelpers.cpp' => 'src/common/debughelpers.cpp'
3--- src/modules/Unity/Application/debughelpers.cpp 2014-07-25 15:29:20 +0000
4+++ src/common/debughelpers.cpp 2014-08-28 13:13:15 +0000
5@@ -17,22 +17,24 @@
6 #include "debughelpers.h"
7 #include <QTouchEvent>
8
9+#include <mir_toolkit/event.h>
10+
11 // Unity API
12 #include <unity/shell/application/ApplicationInfoInterface.h>
13
14-QString touchPointStateToString(Qt::TouchPointState state)
15+const char *touchPointStateToString(Qt::TouchPointState state)
16 {
17 switch (state) {
18 case Qt::TouchPointPressed:
19- return QString("pressed");
20+ return "pressed";
21 case Qt::TouchPointMoved:
22- return QString("moved");
23+ return "moved";
24 case Qt::TouchPointStationary:
25- return QString("stationary");
26+ return "stationary";
27 case Qt::TouchPointReleased:
28- return QString("released");
29+ return "released";
30 default:
31- return QString("UNKNOWN!");
32+ return "UNKNOWN!";
33 }
34 }
35
36@@ -174,6 +176,36 @@
37 }
38 }
39
40+const char *mirMotionActionToStr(int value)
41+{
42+ switch (value) {
43+ case mir_motion_action_move:
44+ return "move";
45+ case mir_motion_action_down:
46+ return "down";
47+ case mir_motion_action_up:
48+ return "up";
49+ case mir_motion_action_pointer_down:
50+ return "pointer_down";
51+ case mir_motion_action_cancel:
52+ return "cancel";
53+ case mir_motion_action_pointer_up:
54+ return "pointer_up";
55+ case mir_motion_action_outside:
56+ return "outside";
57+ case mir_motion_action_hover_move:
58+ return "hover_move";
59+ case mir_motion_action_scroll:
60+ return "scroll";
61+ case mir_motion_action_hover_enter:
62+ return "hover_enter";
63+ case mir_motion_action_hover_exit:
64+ return "hover_exit";
65+ default:
66+ return "???";
67+ }
68+}
69+
70 using namespace unity::shell::application;
71
72 const char *applicationStateToStr(int state)
73
74=== renamed file 'src/modules/Unity/Application/debughelpers.h' => 'src/common/debughelpers.h'
75--- src/modules/Unity/Application/debughelpers.h 2014-07-25 15:29:20 +0000
76+++ src/common/debughelpers.h 2014-08-28 13:13:15 +0000
77@@ -23,7 +23,7 @@
78
79 class QTouchEvent;
80
81-QString touchPointStateToString(Qt::TouchPointState state);
82+const char *touchPointStateToString(Qt::TouchPointState state);
83 QString touchEventToString(const QTouchEvent *ev);
84
85 QString mirSurfaceAttribAndValueToString(MirSurfaceAttrib attrib, int value);
86@@ -31,6 +31,7 @@
87 const char *mirSurfaceStateToStr(int value);
88 const char *mirSurfaceFocusStateToStr(int value);
89 const char *mirSurfaceVisibilityToStr(int value);
90+const char *mirMotionActionToStr(int value);
91
92 const char *applicationStateToStr(int state);
93
94
95=== modified file 'src/modules/Unity/Application/Application.pro'
96--- src/modules/Unity/Application/Application.pro 2014-08-05 09:14:13 +0000
97+++ src/modules/Unity/Application/Application.pro 2014-08-28 13:13:15 +0000
98@@ -12,7 +12,7 @@
99
100 PKGCONFIG += mirserver glib-2.0 process-cpp ubuntu-app-launch-2
101
102-INCLUDEPATH += ../../../platforms/mirserver
103+INCLUDEPATH += ../../../platforms/mirserver ../../../common
104 LIBS += -L../../../platforms/mirserver -lqpa-mirserver
105 QMAKE_RPATHDIR += $$[QT_INSTALL_PLUGINS]/platforms # where libqpa-mirserver.so is installed
106
107@@ -24,7 +24,7 @@
108
109 SOURCES += application_manager.cpp \
110 application.cpp \
111- debughelpers.cpp \
112+ ../../../common/debughelpers.cpp \
113 desktopfilereader.cpp \
114 plugin.cpp \
115 applicationscreenshotprovider.cpp \
116@@ -42,7 +42,7 @@
117 HEADERS += application_manager.h \
118 applicationcontroller.h \
119 application.h \
120- debughelpers.h \
121+ ../../../common/debughelpers.h \
122 desktopfilereader.h \
123 applicationscreenshotprovider.h \
124 dbuswindowstack.h \
125
126=== modified file 'src/modules/Unity/Application/application.cpp'
127--- src/modules/Unity/Application/application.cpp 2014-08-22 22:45:47 +0000
128+++ src/modules/Unity/Application/application.cpp 2014-08-28 13:13:15 +0000
129@@ -17,10 +17,12 @@
130 // local
131 #include "application.h"
132 #include "application_manager.h"
133-#include "debughelpers.h"
134 #include "desktopfilereader.h"
135 #include "taskcontroller.h"
136
137+// common
138+#include <debughelpers.h>
139+
140 // QPA mirserver
141 #include "logging.h"
142
143
144=== modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp'
145--- src/modules/Unity/Application/mirsurfaceitem.cpp 2014-08-12 18:23:06 +0000
146+++ src/modules/Unity/Application/mirsurfaceitem.cpp 2014-08-28 13:13:15 +0000
147@@ -20,11 +20,13 @@
148
149 // local
150 #include "application.h"
151-#include "debughelpers.h"
152 #include "mirbuffersgtexture.h"
153 #include "mirsurfaceitem.h"
154 #include "logging.h"
155
156+// common
157+#include <debughelpers.h>
158+
159 // Qt
160 #include <QDebug>
161 #include <QQmlEngine>
162
163=== modified file 'src/modules/Unity/Application/mirsurfacemanager.cpp'
164--- src/modules/Unity/Application/mirsurfacemanager.cpp 2014-08-08 10:37:50 +0000
165+++ src/modules/Unity/Application/mirsurfacemanager.cpp 2014-08-28 13:13:15 +0000
166@@ -19,10 +19,12 @@
167 #include <QMutexLocker>
168
169 // local
170-#include "debughelpers.h"
171 #include "mirsurfacemanager.h"
172 #include "application_manager.h"
173
174+// common
175+#include <debughelpers.h>
176+
177 // QPA mirserver
178 #include "nativeinterface.h"
179 #include "mirserverconfiguration.h"
180
181=== modified file 'src/platforms/mirserver/logging.h'
182--- src/platforms/mirserver/logging.h 2014-07-01 13:38:06 +0000
183+++ src/platforms/mirserver/logging.h 2014-08-28 13:13:15 +0000
184@@ -21,5 +21,6 @@
185 Q_DECLARE_LOGGING_CATEGORY(QTMIR_APPLICATIONS)
186 Q_DECLARE_LOGGING_CATEGORY(QTMIR_SURFACES)
187 Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES)
188+Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT)
189
190 #endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H
191
192=== modified file 'src/platforms/mirserver/mirserver.pro'
193--- src/platforms/mirserver/mirserver.pro 2014-08-05 09:14:13 +0000
194+++ src/platforms/mirserver/mirserver.pro 2014-08-28 13:13:15 +0000
195@@ -14,6 +14,8 @@
196 QMAKE_CXXFLAGS = -std=c++11 -Werror -Wall
197 QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined
198
199+INCLUDEPATH += ../../common
200+
201 CONFIG += link_pkgconfig
202 PKGCONFIG += mirserver protobuf egl xkbcommon url-dispatcher-1
203
204@@ -21,6 +23,7 @@
205
206 SOURCES += \
207 connectioncreator.cpp \
208+ ../../common/debughelpers.cpp \
209 focussetter.cpp \
210 qteventfeeder.cpp \
211 plugin.cpp \
212@@ -47,6 +50,7 @@
213
214 HEADERS += \
215 connectioncreator.h \
216+ ../../common/debughelpers.h \
217 focussetter.h \
218 qteventfeeder.h \
219 plugin.h \
220
221=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
222--- src/platforms/mirserver/qteventfeeder.cpp 2014-07-29 15:01:34 +0000
223+++ src/platforms/mirserver/qteventfeeder.cpp 2014-08-28 13:13:15 +0000
224@@ -18,10 +18,10 @@
225 */
226
227 #include "qteventfeeder.h"
228+#include "logging.h"
229
230 #include <qpa/qplatforminputcontext.h>
231 #include <qpa/qplatformintegration.h>
232-#include <qpa/qwindowsysteminterface.h>
233 #include <QGuiApplication>
234 #include <private/qguiapplication_p.h>
235
236@@ -30,6 +30,8 @@
237
238 #include <QDebug>
239
240+Q_LOGGING_CATEGORY(QTMIR_MIR_INPUT, "qtmir.mir.input")
241+
242 // from android-input AMOTION_EVENT_ACTION_*, hidden inside mir bowels
243 // mir headers should define them
244 const int QtEventFeeder::MirEventActionMask = 0xff;
245@@ -133,9 +135,61 @@
246 return toupper(sym);
247 }
248
249-
250-QtEventFeeder::QtEventFeeder()
251+namespace {
252+
253+class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
254+
255+ bool hasTargetWindow() override
256+ {
257+ if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) {
258+ mTopLevelWindow = QGuiApplication::topLevelWindows().first();
259+ }
260+ return !mTopLevelWindow.isNull();
261+ }
262+
263+ QRect targetWindowGeometry() override
264+ {
265+ Q_ASSERT(!mTopLevelWindow.isNull());
266+ return mTopLevelWindow->geometry();
267+ }
268+
269+ void registerTouchDevice(QTouchDevice *device) override
270+ {
271+ QWindowSystemInterface::registerTouchDevice(device);
272+ }
273+
274+ void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,
275+ Qt::KeyboardModifiers modifiers,
276+ quint32 nativeScanCode, quint32 nativeVirtualKey,
277+ quint32 nativeModifiers,
278+ const QString& text, bool autorep, ushort count) override
279+ {
280+ Q_ASSERT(!mTopLevelWindow.isNull());
281+ QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers,
282+ nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
283+ }
284+
285+ void handleTouchEvent(ulong timestamp, QTouchDevice *device,
286+ const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override
287+ {
288+ Q_ASSERT(!mTopLevelWindow.isNull());
289+ QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods);
290+ }
291+private:
292+ QPointer<QWindow> mTopLevelWindow;
293+};
294+
295+} // anonymous namespace
296+
297+
298+QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem)
299 {
300+ if (windowSystem) {
301+ mQtWindowSystem = windowSystem;
302+ } else {
303+ mQtWindowSystem = new QtWindowSystem;
304+ }
305+
306 // Initialize touch device. Hardcoded just like in qtubuntu
307 // TODO: Create them from info gathered from Mir and store things like device id and source
308 // in a QTouchDevice-derived class created by us. So that we can properly assemble back
309@@ -145,7 +199,12 @@
310 mTouchDevice->setCapabilities(
311 QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |
312 QTouchDevice::NormalizedPosition);
313- QWindowSystemInterface::registerTouchDevice(mTouchDevice);
314+ mQtWindowSystem->registerTouchDevice(mTouchDevice);
315+}
316+
317+QtEventFeeder::~QtEventFeeder()
318+{
319+ delete mQtWindowSystem;
320 }
321
322 void QtEventFeeder::dispatch(MirEvent const& event)
323@@ -171,11 +230,9 @@
324
325 void QtEventFeeder::dispatchKey(MirKeyEvent const& event)
326 {
327- if (QGuiApplication::topLevelWindows().isEmpty())
328+ if (!mQtWindowSystem->hasTargetWindow())
329 return;
330
331- QWindow *window = QGuiApplication::topLevelWindows().first();
332-
333 ulong timestamp = event.event_time / 1000000;
334 xkb_keysym_t xk_sym = static_cast<xkb_keysym_t>(event.key_code);
335
336@@ -221,20 +278,33 @@
337 }
338 }
339
340- QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, keyType, keyCode, modifiers, event.scan_code, event.key_code, event.modifiers, text);
341+ mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers,
342+ event.scan_code, event.key_code, event.modifiers, text);
343 }
344
345 void QtEventFeeder::dispatchMotion(MirMotionEvent const& event)
346 {
347- if (QGuiApplication::topLevelWindows().isEmpty())
348- return;
349-
350- QWindow *window = QGuiApplication::topLevelWindows().first();
351+ if (!mQtWindowSystem->hasTargetWindow())
352+ return;
353+
354+ const int mirMotionAction = event.action & MirEventActionMask;
355+
356+ // Ignore the events that do not interest us (or that we currently don't support or know
357+ // how to translate into Qt events)
358+ if (mirMotionAction != mir_motion_action_move
359+ && mirMotionAction != mir_motion_action_down
360+ && mirMotionAction != mir_motion_action_up
361+ && mirMotionAction != mir_motion_action_pointer_down
362+ && mirMotionAction != mir_motion_action_pointer_up
363+ && mirMotionAction != mir_motion_action_cancel) {
364+ return;
365+ }
366+
367
368 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
369 // needs to be fixed as soon as the compat input lib adds query support.
370 const float kMaxPressure = 1.28;
371- const QRect kWindowGeometry = window->geometry();
372+ const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry();
373 QList<QWindowSystemInterface::TouchPoint> touchPoints;
374
375 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
376@@ -257,7 +327,7 @@
377 touchPoints.append(touchPoint);
378 }
379
380- switch (event.action & MirEventActionMask) {
381+ switch (mirMotionAction) {
382 case mir_motion_action_move:
383 // No extra work needed.
384 break;
385@@ -291,13 +361,17 @@
386 case mir_motion_action_scroll:
387 case mir_motion_action_hover_enter:
388 case mir_motion_action_hover_exit:
389- default:
390- qWarning() << "unhandled motion event action" << (int)(event.action & MirEventActionMask);
391+ default:
392+ // Should never reach this point. If so, it's a programming error.
393+ qFatal("Trying to handle unsupported motion event action");
394 }
395
396+ // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
397+ // any insanity.
398+ validateTouches(touchPoints);
399+
400 // Touch event propagation.
401- QWindowSystemInterface::handleTouchEvent(
402- window,
403+ mQtWindowSystem->handleTouchEvent(
404 event.event_time / 1000000, //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
405 mTouchDevice,
406 touchPoints);
407@@ -323,3 +397,86 @@
408 Q_UNUSED(device_id);
409 Q_UNUSED(when);
410 }
411+
412+void QtEventFeeder::validateTouches(QList<QWindowSystemInterface::TouchPoint> &touchPoints)
413+{
414+ QSet<int> updatedTouches;
415+
416+ {
417+ int i = 0;
418+ while (i < touchPoints.count()) {
419+ bool mustDiscardTouch = !validateTouch(touchPoints[i]);
420+ if (mustDiscardTouch) {
421+ touchPoints.removeAt(i);
422+ } else {
423+ updatedTouches.insert(touchPoints.at(i).id);
424+ ++i;
425+ }
426+ }
427+ }
428+
429+ // Release all unmentioned touches.
430+ {
431+ QHash<int, QWindowSystemInterface::TouchPoint>::iterator it = mActiveTouches.begin();
432+ while (it != mActiveTouches.end()) {
433+ if (!updatedTouches.contains(it.key())) {
434+ qCWarning(QTMIR_MIR_INPUT)
435+ << "There's a touch (id =" << it.key() << ") missing. Releasing it.";
436+ it.value().state = Qt::TouchPointReleased;
437+ touchPoints.append(it.value());
438+ it = mActiveTouches.erase(it);
439+ } else {
440+ ++it;
441+ }
442+ }
443+ }
444+}
445+
446+bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)
447+{
448+ bool ok = true;
449+
450+ switch (touchPoint.state) {
451+ case Qt::TouchPointPressed:
452+ if (mActiveTouches.contains(touchPoint.id)) {
453+ qCWarning(QTMIR_MIR_INPUT)
454+ << "Would press an already existing touch (id =" << touchPoint.id
455+ << "). Making it move instead.";
456+ touchPoint.state = Qt::TouchPointMoved;
457+ }
458+ mActiveTouches[touchPoint.id] = touchPoint;
459+ break;
460+ case Qt::TouchPointMoved:
461+ if (!mActiveTouches.contains(touchPoint.id)) {
462+ qCWarning(QTMIR_MIR_INPUT)
463+ << "Would move a touch that wasn't pressed before (id =" << touchPoint.id
464+ << "). Making it press instead.";
465+ touchPoint.state = Qt::TouchPointPressed;
466+ }
467+ mActiveTouches[touchPoint.id] = touchPoint;
468+ break;
469+ case Qt::TouchPointStationary:
470+ if (!mActiveTouches.contains(touchPoint.id)) {
471+ qCWarning(QTMIR_MIR_INPUT)
472+ << "There's an stationary touch that wasn't pressed before (id =" << touchPoint.id
473+ << "). Making it press instead.";
474+ touchPoint.state = Qt::TouchPointPressed;
475+ }
476+ mActiveTouches[touchPoint.id] = touchPoint;
477+ break;
478+ case Qt::TouchPointReleased:
479+ if (!mActiveTouches.contains(touchPoint.id)) {
480+ qCWarning(QTMIR_MIR_INPUT)
481+ << "Would release a touch that wasn't pressed before (id =" << touchPoint.id
482+ << "). Ignoring it.";
483+ ok = false;
484+ } else {
485+ mActiveTouches.remove(touchPoint.id);
486+ }
487+ break;
488+ default:
489+ qFatal("QtEventFeeder: invalid touch state");
490+ }
491+
492+ return ok;
493+}
494
495=== modified file 'src/platforms/mirserver/qteventfeeder.h'
496--- src/platforms/mirserver/qteventfeeder.h 2014-07-18 20:23:35 +0000
497+++ src/platforms/mirserver/qteventfeeder.h 2014-08-28 13:13:15 +0000
498@@ -22,6 +22,8 @@
499 #include <mir/input/input_dispatcher.h>
500 #include <mir/shell/input_targeter.h>
501
502+#include <qpa/qwindowsysteminterface.h>
503+
504 class QTouchDevice;
505
506 /*
507@@ -30,7 +32,29 @@
508 class QtEventFeeder : public mir::input::InputDispatcher
509 {
510 public:
511- QtEventFeeder();
512+ // Interface between QtEventFeeder and the actual QWindowSystemInterface functions
513+ // and other related Qt methods and objects to enable replacing them with mocks in
514+ // pure unit tests.
515+ // TODO - Make it work with multimonitor scenarios
516+ class QtWindowSystemInterface {
517+ public:
518+ virtual ~QtWindowSystemInterface() {}
519+ virtual bool hasTargetWindow() = 0;
520+ virtual QRect targetWindowGeometry() = 0;
521+ virtual void registerTouchDevice(QTouchDevice *device) = 0;
522+ virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,
523+ Qt::KeyboardModifiers modifiers,
524+ quint32 nativeScanCode, quint32 nativeVirtualKey,
525+ quint32 nativeModifiers,
526+ const QString& text = QString(), bool autorep = false,
527+ ushort count = 1) = 0;
528+ virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device,
529+ const QList<struct QWindowSystemInterface::TouchPoint> &points,
530+ Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;
531+ };
532+
533+ QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr);
534+ virtual ~QtEventFeeder();
535
536 static const int MirEventActionMask;
537 static const int MirEventActionPointerIndexMask;
538@@ -45,8 +69,14 @@
539 private:
540 void dispatchKey(MirKeyEvent const& event);
541 void dispatchMotion(MirMotionEvent const& event);
542+ void validateTouches(QList<QWindowSystemInterface::TouchPoint> &touchPoints);
543+ bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);
544
545 QTouchDevice *mTouchDevice;
546+ QtWindowSystemInterface *mQtWindowSystem;
547+
548+ // Maps the id of an active touch to its last known state
549+ QHash<int, QWindowSystemInterface::TouchPoint> mActiveTouches;
550 };
551
552 #endif // MIR_QT_EVENT_FEEDER_H
553
554=== added file 'tests/google-mock.pri'
555--- tests/google-mock.pri 1970-01-01 00:00:00 +0000
556+++ tests/google-mock.pri 2014-08-28 13:13:15 +0000
557@@ -0,0 +1,24 @@
558+GMOCK_SOURCES = /usr/src/gmock/src/gmock-all.cc \
559+ /usr/src/gmock/src/gmock_main.cc \
560+ /usr/src/gtest/src/gtest-all.cc
561+
562+QMAKE_EXTRA_COMPILERS += gmock_compiler
563+gmock_compiler.input = GMOCK_SOURCES
564+gmock_compiler.output = $${OUT_PWD}/${QMAKE_FILE_BASE}.o
565+gmock_compiler.commands = g++ \
566+ -I/usr/src/gtest \
567+ -I/usr/src/gmock \
568+ -c ${QMAKE_FILE_IN} \
569+ -o ${QMAKE_FILE_OUT}
570+gmock_compiler.CONFIG = no_link
571+
572+QMAKE_EXTRA_COMPILERS += gmock_linker
573+gmock_linker.depends = $${OUT_PWD}/gmock-all.o \
574+ $${OUT_PWD}/gmock_main.o \
575+ $${OUT_PWD}/gtest-all.o
576+gmock_linker.input = GMOCK_SOURCES
577+gmock_linker.output = $${OUT_PWD}/libgmock.a
578+gmock_linker.commands = ar -rv ${QMAKE_FILE_OUT} $${OUT_PWD}/gmock-all.o $${OUT_PWD}/gmock_main.o $${OUT_PWD}/gtest-all.o
579+gmock_linker.CONFIG = combine explicit_dependencies no_link target_predeps
580+
581+LIBS += $${OUT_PWD}/libgmock.a
582
583=== added directory 'tests/mirserver'
584=== added directory 'tests/mirserver/QtEventFeeder'
585=== added file 'tests/mirserver/QtEventFeeder/QtEventFeeder.pro'
586--- tests/mirserver/QtEventFeeder/QtEventFeeder.pro 1970-01-01 00:00:00 +0000
587+++ tests/mirserver/QtEventFeeder/QtEventFeeder.pro 2014-08-28 13:13:15 +0000
588@@ -0,0 +1,16 @@
589+include(../../test-includes.pri)
590+
591+TARGET = QtEventFeederTest
592+
593+QT += gui-private
594+
595+INCLUDEPATH += \
596+ ../../../src/platforms/mirserver \
597+ ../../../src/common
598+
599+SOURCES += \
600+ qteventfeeder_test.cpp \
601+ ../../../src/common/debughelpers.cpp
602+
603+LIBS += -Wl,-rpath,$${OUT_PWD}/../../../src/platforms/mirserver \
604+ -L../../../src/platforms/mirserver -lqpa-mirserver
605
606=== added file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h'
607--- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 1970-01-01 00:00:00 +0000
608+++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2014-08-28 13:13:15 +0000
609@@ -0,0 +1,65 @@
610+/*
611+ * Copyright (C) 2014 Canonical, Ltd.
612+ *
613+ * This program is free software: you can redistribute it and/or modify it under
614+ * the terms of the GNU Lesser General Public License version 3, as published by
615+ * the Free Software Foundation.
616+ *
617+ * This program is distributed in the hope that it will be useful, but WITHOUT
618+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
619+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
620+ * Lesser General Public License for more details.
621+ *
622+ * You should have received a copy of the GNU Lesser General Public License
623+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
624+ *
625+ */
626+
627+#ifndef MOCK_QTWINDOWSYSTEM_H
628+#define MOCK_QTWINDOWSYSTEM_H
629+
630+#include <qteventfeeder.h>
631+
632+class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
633+public:
634+ MOCK_METHOD0(hasTargetWindow, bool());
635+ MOCK_METHOD0(targetWindowGeometry, QRect());
636+ MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device));
637+ MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key,
638+ Qt::KeyboardModifiers modifiers,
639+ quint32 nativeScanCode, quint32 nativeVirtualKey,
640+ quint32 nativeModifiers,
641+ const QString& text, bool autorep,
642+ ushort count));
643+ MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device,
644+ const QList<struct QWindowSystemInterface::TouchPoint> &points,
645+ Qt::KeyboardModifiers mods));
646+};
647+
648+namespace testing
649+{
650+
651+MATCHER(IsPressed, std::string(negation ? "isn't" : "is") + " pressed")
652+{
653+ return arg.state == Qt::TouchPointPressed;
654+}
655+
656+MATCHER(IsReleased, std::string(negation ? "isn't" : "is") + " released")
657+{
658+ return arg.state == Qt::TouchPointReleased;
659+}
660+
661+MATCHER(StateIsMoved, "state " + std::string(negation ? "isn't" : "is") + " 'moved'")
662+{
663+ return arg.state == Qt::TouchPointMoved;
664+}
665+
666+MATCHER_P(HasId, expectedId, "id " + std::string(negation ? "isn't " : "is ") + PrintToString(expectedId))
667+{
668+ return arg.id == expectedId;
669+}
670+
671+} // namespace testing
672+
673+
674+#endif // MOCK_QTWINDOWSYSTEM_H
675
676=== added file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp'
677--- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 1970-01-01 00:00:00 +0000
678+++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2014-08-28 13:13:15 +0000
679@@ -0,0 +1,224 @@
680+/*
681+ * Copyright (C) 2014 Canonical, Ltd.
682+ *
683+ * This program is free software: you can redistribute it and/or modify it under
684+ * the terms of the GNU Lesser General Public License version 3, as published by
685+ * the Free Software Foundation.
686+ *
687+ * This program is distributed in the hope that it will be useful, but WITHOUT
688+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
689+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
690+ * Lesser General Public License for more details.
691+ *
692+ * You should have received a copy of the GNU Lesser General Public License
693+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
694+ *
695+ */
696+
697+#include <gmock/gmock.h>
698+#include <gtest/gtest.h>
699+
700+#include <qteventfeeder.h>
701+#include <debughelpers.h>
702+
703+#include <QGuiApplication>
704+#include <QWindow>
705+
706+#include "mock_qtwindowsystem.h"
707+
708+using ::testing::_;
709+using ::testing::AllOf;
710+using ::testing::AnyNumber;
711+using ::testing::Contains;
712+using ::testing::AtLeast;
713+using ::testing::InSequence;
714+using ::testing::Mock;
715+using ::testing::SizeIs;
716+using ::testing::Return;
717+
718+// own gmock extensions
719+using ::testing::IsPressed;
720+using ::testing::IsReleased;
721+using ::testing::HasId;
722+using ::testing::StateIsMoved;
723+
724+void PrintTo(const struct QWindowSystemInterface::TouchPoint& touchPoint, ::std::ostream* os) {
725+ *os << "TouchPoint("
726+ << "id=" << touchPoint.id
727+ << "," << touchPointStateToString(touchPoint.state)
728+ << ")";
729+}
730+
731+class QtEventFeederTest : public ::testing::Test {
732+protected:
733+ void SetUp() override;
734+ void TearDown() override;
735+
736+ void setIrrelevantMockWindowSystemExpectations();
737+
738+ MockQtWindowSystem *mockWindowSystem;
739+ QtEventFeeder *qtEventFeeder;
740+};
741+
742+void QtEventFeederTest::SetUp()
743+{
744+ mockWindowSystem = new MockQtWindowSystem;
745+
746+ EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));
747+
748+ qtEventFeeder = new QtEventFeeder(mockWindowSystem);
749+
750+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
751+}
752+
753+void QtEventFeederTest::TearDown()
754+{
755+ // mockWindowSystem will be deleted by QtEventFeeder
756+ delete qtEventFeeder;
757+}
758+
759+void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
760+{
761+ EXPECT_CALL(*mockWindowSystem, hasTargetWindow())
762+ .Times(AnyNumber())
763+ .WillRepeatedly(Return(true));
764+ EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())
765+ .Times(AnyNumber())
766+ .WillRepeatedly(Return(QRect(0,0,100,100)));
767+}
768+
769+
770+/*
771+ Mir sends a MirEvent([touch(id=0,state=pressed)]. QtEventFeeder happily forwards that to Qt.
772+
773+ Then, Mir sends a MirEvent([touch(id=1,state=pressed)]). In MirEvents, every single active touch
774+ point must be listed in the event even if it didn't change at all in the meantime. So that's a bug.
775+ But instead of crashing or forwarding the bogus event stream down to Qt, QtEventFeeder should attempt
776+ to fix the situation by synthesizing a touch[id=1,state=released] to be send along with the
777+ touch(id=1,state=pressed) it got. So that Qt receives a correct touch event stream.
778+ */
779+TEST_F(QtEventFeederTest, GenerateMissingTouchEnd)
780+{
781+
782+ setIrrelevantMockWindowSystemExpectations();
783+
784+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
785+ Contains(AllOf(HasId(0),
786+ IsPressed()))),_)).Times(1);
787+
788+ MirEvent mirEvent;
789+ mirEvent.type = mir_event_type_motion;
790+ mirEvent.motion.pointer_count = 1;
791+ mirEvent.motion.pointer_coordinates[0].id = 0;
792+ mirEvent.motion.pointer_coordinates[0].x = 10;
793+ mirEvent.motion.pointer_coordinates[0].y = 10;
794+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
795+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
796+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
797+ mirEvent.motion.action = mir_motion_action_down;
798+ mirEvent.motion.event_time = 123 * 1000000;
799+
800+ qtEventFeeder->dispatch(mirEvent);
801+
802+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
803+
804+ setIrrelevantMockWindowSystemExpectations();
805+
806+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(2),
807+ Contains(AllOf(HasId(0),IsReleased())),
808+ Contains(AllOf(HasId(1),IsPressed()))
809+ ),_)).Times(1);
810+
811+ mirEvent.type = mir_event_type_motion;
812+ mirEvent.motion.pointer_count = 1;
813+ mirEvent.motion.pointer_coordinates[0].id = 1;
814+ mirEvent.motion.pointer_coordinates[0].x = 20;
815+ mirEvent.motion.pointer_coordinates[0].y = 20;
816+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
817+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
818+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
819+ mirEvent.motion.action = mir_motion_action_down;
820+ mirEvent.motion.event_time = 125 * 1000000;
821+
822+ qtEventFeeder->dispatch(mirEvent);
823+
824+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
825+}
826+
827+TEST_F(QtEventFeederTest, PressSameTouchTwice)
828+{
829+ setIrrelevantMockWindowSystemExpectations();
830+
831+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
832+ Contains(AllOf(HasId(0),
833+ IsPressed()))),_)).Times(1);
834+
835+ MirEvent mirEvent;
836+ mirEvent.type = mir_event_type_motion;
837+ mirEvent.motion.pointer_count = 1;
838+ mirEvent.motion.pointer_coordinates[0].id = 0;
839+ mirEvent.motion.pointer_coordinates[0].x = 10;
840+ mirEvent.motion.pointer_coordinates[0].y = 10;
841+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
842+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
843+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
844+ mirEvent.motion.action = mir_motion_action_down;
845+ mirEvent.motion.event_time = 123 * 1000000;
846+
847+ qtEventFeeder->dispatch(mirEvent);
848+
849+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
850+
851+ setIrrelevantMockWindowSystemExpectations();
852+
853+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
854+ Contains(AllOf(HasId(0), StateIsMoved()))
855+ ),_)).Times(1);
856+
857+ mirEvent.type = mir_event_type_motion;
858+ mirEvent.motion.pointer_count = 1;
859+ mirEvent.motion.pointer_coordinates[0].id = 0;
860+ mirEvent.motion.pointer_coordinates[0].x = 20;
861+ mirEvent.motion.pointer_coordinates[0].y = 20;
862+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
863+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
864+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
865+ mirEvent.motion.action = mir_motion_action_down;
866+ mirEvent.motion.event_time = 125 * 1000000;
867+
868+ qtEventFeeder->dispatch(mirEvent);
869+
870+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
871+}
872+
873+TEST_F(QtEventFeederTest, IgnoreHovering)
874+{
875+ setIrrelevantMockWindowSystemExpectations();
876+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,_)).Times(0);
877+
878+ MirEvent mirEvent;
879+ mirEvent.type = mir_event_type_motion;
880+ mirEvent.motion.pointer_count = 1;
881+ mirEvent.motion.pointer_coordinates[0].id = 0;
882+ mirEvent.motion.pointer_coordinates[0].x = 10;
883+ mirEvent.motion.pointer_coordinates[0].y = 10;
884+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
885+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
886+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
887+ mirEvent.motion.action = mir_motion_action_hover_enter;
888+ mirEvent.motion.event_time = 123 * 1000000;
889+
890+ qtEventFeeder->dispatch(mirEvent);
891+
892+ mirEvent.motion.pointer_coordinates[0].x = 20;
893+ mirEvent.motion.pointer_coordinates[0].y = 20;
894+ mirEvent.motion.action = mir_motion_action_hover_move;
895+ mirEvent.motion.event_time = 125 * 1000000;
896+
897+ qtEventFeeder->dispatch(mirEvent);
898+
899+ mirEvent.motion.action = mir_motion_action_hover_exit;
900+ mirEvent.motion.event_time = 127 * 1000000;
901+
902+ qtEventFeeder->dispatch(mirEvent);
903+}
904
905=== added file 'tests/mirserver/mirserver.pro'
906--- tests/mirserver/mirserver.pro 1970-01-01 00:00:00 +0000
907+++ tests/mirserver/mirserver.pro 2014-08-28 13:13:15 +0000
908@@ -0,0 +1,2 @@
909+TEMPLATE = subdirs
910+SUBDIRS = QtEventFeeder
911
912=== modified file 'tests/modules/common/common.pri'
913--- tests/modules/common/common.pri 2014-08-14 15:38:15 +0000
914+++ tests/modules/common/common.pri 2014-08-28 13:13:15 +0000
915@@ -1,8 +1,7 @@
916-CONFIG += link_pkgconfig no_keywords # keywords clash with ProcessC++
917-PKGCONFIG += mirserver process-cpp ubuntu-app-launch-2
918+CONFIG += no_keywords # keywords clash with ProcessC++
919+PKGCONFIG += process-cpp ubuntu-app-launch-2
920
921-QT += quick testlib
922-QMAKE_CXXFLAGS = -std=c++11
923+QT += quick
924
925 HEADERS += ../common/mock_application_controller.h \
926 ../common/mock_desktop_file_reader.h \
927@@ -19,31 +18,7 @@
928 INCLUDEPATH += ../../../src/modules \
929 ../common
930
931-
932-GMOCK_SOURCES = /usr/src/gmock/src/gmock-all.cc \
933- /usr/src/gmock/src/gmock_main.cc \
934- /usr/src/gtest/src/gtest-all.cc
935-
936-QMAKE_EXTRA_COMPILERS += gmock_compiler
937-gmock_compiler.input = GMOCK_SOURCES
938-gmock_compiler.output = $${OUT_PWD}/${QMAKE_FILE_BASE}.o
939-gmock_compiler.commands = g++ \
940- -I/usr/src/gtest \
941- -I/usr/src/gmock \
942- -c ${QMAKE_FILE_IN} \
943- -o ${QMAKE_FILE_OUT}
944-gmock_compiler.CONFIG = no_link
945-
946-QMAKE_EXTRA_COMPILERS += gmock_linker
947-gmock_linker.depends = $${OUT_PWD}/gmock-all.o \
948- $${OUT_PWD}/gmock_main.o \
949- $${OUT_PWD}/gtest-all.o
950-gmock_linker.input = GMOCK_SOURCES
951-gmock_linker.output = $${OUT_PWD}/libgmock.a
952-gmock_linker.commands = ar -rv ${QMAKE_FILE_OUT} $${OUT_PWD}/gmock-all.o $${OUT_PWD}/gmock_main.o $${OUT_PWD}/gtest-all.o
953-gmock_linker.CONFIG = combine explicit_dependencies no_link target_predeps
954-
955-LIBS += $${OUT_PWD}/libgmock.a \
956+LIBS += \
957 -Wl,-rpath,$${OUT_PWD}/../../../src/modules/Unity/Application \
958 -L$${OUT_PWD}/../../../src/modules/Unity/Application -lunityapplicationplugin \
959 -Wl,-rpath,$${OUT_PWD}/../../../src/platforms/mirserver \
960
961=== modified file 'tests/test-includes.pri'
962--- tests/test-includes.pri 2014-07-07 19:33:56 +0000
963+++ tests/test-includes.pri 2014-08-28 13:13:15 +0000
964@@ -4,3 +4,12 @@
965 # adds a 'make install' that installs the test cases, which we do not want.
966 # Can configure it not to do that with 'no_testcase_installs'
967 CONFIG += testcase no_testcase_installs
968+
969+QMAKE_CXXFLAGS = -std=c++11
970+
971+QT += testlib
972+
973+CONFIG += link_pkgconfig
974+PKGCONFIG += mirserver
975+
976+include(google-mock.pri)
977
978=== modified file 'tests/tests.pro'
979--- tests/tests.pro 2014-07-01 13:38:06 +0000
980+++ tests/tests.pro 2014-08-28 13:13:15 +0000
981@@ -1,2 +1,2 @@
982 TEMPLATE = subdirs
983-SUBDIRS = modules
984+SUBDIRS = modules mirserver

Subscribers

People subscribed via source and target branches