Merge lp:~dandrader/qtmir/missingTouchEnd-lp1295623 into lp:qtmir
- missingTouchEnd-lp1295623
- Merge into trunk
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 | ||||
Related bugs: |
|
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:/
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:/
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:/
* 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.
PS Jenkins bot (ps-jenkins) wrote : | # |
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/
+ class QtWindowSystem {
This is actually a interface, please call it QtWindowSystemI
+++ src/platforms/
+ 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(
I think a dedicated logging category for this would make sense. QTMIR_INPUT_
+void QtEventFeederTe
+{
+ EXPECT_
+ .Times(AnyNumber())
+ .WillRepeatedly
+ EXPECT_
+ .Times(AnyNumber())
+ .WillRepeatedly
+}
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.
+ setIrrelevantMo
why do you keep calling this? You use .Times(
+TEST_F(
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
Gerry Boland (gerboland) wrote : | # |
Desktop tests ok
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.
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/QtWindowSyste
m/QtWindowSyste mInterface - 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 QtEventFeederTe
st::GenerateMis singTouchEnd
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? 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/
> + class QtWindowSystem {
> This is actually a interface, please call it QtWindowSystemI
> hopefully it doesn't clash with Qt's defined one. Else
> QtMirWindowSyst
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/
> + 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(
> I think a dedicated logging category for this would make sense.
> QTMIR_INPUT_
Done.
>
> +void QtEventFeederTe
> +{
> + EXPECT_
> + .Times(AnyNumber())
> + .WillRepeatedly
> + EXPECT_
> + .Times(AnyNumber())
> + .WillRepeatedly
> +}
> 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::VerifyAnd
>
> + .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...
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:244
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:245
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Perfect, thank you
Preview Diff
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 |
PASSED: Continuous integration, rev:240 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 40/ jenkins. qa.ubuntu. com/job/ qtmir-utopic- amd64-ci/ 40 jenkins. qa.ubuntu. com/job/ qtmir-utopic- armhf-ci/ 40
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/40/rebuild
http://