Merge lp:~gerboland/qtmir/desktopFileReader into lp:~dandrader/qtmir/parse_splash_from_desktop_file

Proposed by Gerry Boland
Status: Superseded
Proposed branch: lp:~gerboland/qtmir/desktopFileReader
Merge into: lp:~dandrader/qtmir/parse_splash_from_desktop_file
Diff against target: 3963 lines (+2079/-471)
58 files modified
README (+1/-1)
debian/changelog (+25/-0)
debian/control (+3/-0)
src/common/debughelpers.cpp (+38/-6)
src/common/debughelpers.h (+2/-1)
src/lttng-compiler.pri (+25/-0)
src/modules/Unity/Application/Application.pro (+11/-5)
src/modules/Unity/Application/application.cpp (+6/-4)
src/modules/Unity/Application/application.h (+7/-6)
src/modules/Unity/Application/application_manager.cpp (+14/-6)
src/modules/Unity/Application/desktopfilereader.cpp (+164/-114)
src/modules/Unity/Application/desktopfilereader.h (+22/-40)
src/modules/Unity/Application/gscopedpointer.h (+113/-0)
src/modules/Unity/Application/mirsurfaceitem.cpp (+138/-31)
src/modules/Unity/Application/mirsurfaceitem.h (+38/-7)
src/modules/Unity/Application/mirsurfacemanager.cpp (+13/-7)
src/modules/Unity/Application/plugin.cpp (+1/-0)
src/modules/Unity/Application/session.cpp (+21/-19)
src/modules/Unity/Application/session.h (+35/-63)
src/modules/Unity/Application/session_interface.h (+106/-0)
src/modules/Unity/Application/sessionmanager.cpp (+8/-8)
src/modules/Unity/Application/sessionmanager.h (+4/-4)
src/modules/Unity/Application/sessionmodel.h (+2/-2)
src/modules/Unity/Application/tracepoints.tp (+9/-0)
src/platforms/mirserver/logging.h (+1/-0)
src/platforms/mirserver/mirplacementstrategy.cpp (+5/-0)
src/platforms/mirserver/mirserver.pro (+8/-0)
src/platforms/mirserver/mirserverconfiguration.cpp (+12/-1)
src/platforms/mirserver/qteventfeeder.cpp (+175/-18)
src/platforms/mirserver/qteventfeeder.h (+31/-1)
src/platforms/mirserver/sessionauthorizer.cpp (+4/-0)
src/platforms/mirserver/sessionlistener.cpp (+5/-0)
src/platforms/mirserver/tracepoints.tp (+10/-0)
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/ApplicationManager/application_manager_test.cpp (+3/-2)
tests/modules/DesktopFileReader/DesktopFileReader.pro (+15/-0)
tests/modules/DesktopFileReader/calculator.desktop (+227/-0)
tests/modules/DesktopFileReader/desktopfilereader_test.cpp (+128/-0)
tests/modules/MirSurfaceItem/MirSurfaceItem.pro (+13/-0)
tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp (+113/-0)
tests/modules/SessionManager/session_manager_test.cpp (+10/-9)
tests/modules/SessionManager/session_test.cpp (+5/-6)
tests/modules/common/common.pri (+5/-29)
tests/modules/common/mock_focus_controller.h (+9/-6)
tests/modules/common/mock_mir_session.h (+14/-13)
tests/modules/common/mock_prompt_session.h (+7/-4)
tests/modules/common/mock_prompt_session_manager.h (+21/-18)
tests/modules/common/mock_renderable.h (+9/-6)
tests/modules/common/mock_session.h (+65/-0)
tests/modules/common/mock_surface.h (+24/-23)
tests/modules/common/qtmir_test.h (+12/-9)
tests/modules/modules.pro (+1/-1)
tests/test-includes.pri (+9/-0)
tests/tests.pro (+1/-1)
To merge this branch: bzr merge lp:~gerboland/qtmir/desktopFileReader
Reviewer Review Type Date Requested Status
Daniel d'Andrada Pending
Review via email: mp+235222@code.launchpad.net

Commit message

Rewrite DesktopFileReader to use GDesktopAppInfo, enables reading localized keys

Description of the change

Rewrite DesktopFileReader to use GDesktopAppInfo, enables reading localized keys

 * Are there any related MPs required for this MP to build/function as expected? Please list.
N
 * Did you perform an exploratory manual test run of your code change and any related functionality?
Y
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

To post a comment you must log in.
259. By Gerry Boland

Oops, revert naughty change

260. By Gerry Boland

Typos

261. By Gerry Boland

Fix typos

262. By Gerry Boland

Sssh, not so noisy

263. By Gerry Boland

Use qCWarning

264. By Gerry Boland

Merge trunk

265. By Gerry Boland

Fix compiler unused warning

266. By Gerry Boland

GDesktopInfo actually checks that the binary specified by the Exec line is installed. So need to change calculator.desktop to definitely use an installed binary

267. By Gerry Boland

Add more verbose error message if desktop file not valid or missing

268. By Gerry Boland

Missing !, debug statement now makes sense

Unmerged revisions

268. By Gerry Boland

Missing !, debug statement now makes sense

267. By Gerry Boland

Add more verbose error message if desktop file not valid or missing

266. By Gerry Boland

GDesktopInfo actually checks that the binary specified by the Exec line is installed. So need to change calculator.desktop to definitely use an installed binary

265. By Gerry Boland

Fix compiler unused warning

264. By Gerry Boland

Merge trunk

263. By Gerry Boland

Use qCWarning

262. By Gerry Boland

Sssh, not so noisy

261. By Gerry Boland

Fix typos

260. By Gerry Boland

Typos

259. By Gerry Boland

Oops, revert naughty change

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2014-06-30 15:49:02 +0000
3+++ README 2014-09-18 22:57:30 +0000
4@@ -1,7 +1,7 @@
5 This repo contains a QPA plugin to make Qt a Mir server.
6
7 Handy way to grab dependencies is with:
8-$ sudo mk-build-dep -ir debian/control
9+$ sudo mk-build-deps -ir debian/control
10
11 To use, compile and install with:
12 $ qmake
13
14=== modified file 'debian/changelog'
15--- debian/changelog 2014-09-03 08:03:52 +0000
16+++ debian/changelog 2014-09-18 22:57:30 +0000
17@@ -1,3 +1,28 @@
18+qtmir (0.4.3+14.10.20140915-0ubuntu1) utopic; urgency=low
19+
20+ [ Daniel d'Andrada ]
21+ * MirSurfaceItem: Ensure all touch sequences sent to Mir surface are
22+ properly ended.
23+
24+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 15 Sep 2014 14:50:16 +0000
25+
26+qtmir (0.4.3+14.10.20140907-0ubuntu1) utopic; urgency=low
27+
28+ [ Daniel d'Andrada ]
29+ * QtEventFeeder: validate touches before sending them to Qt
30+
31+ [ josharenson ]
32+ * Fix a small typo in the README file
33+
34+ [ Alan Griffiths ]
35+ * Provide Mir with a handler for any command-line arguments it fails
36+ to parse. For the moment, these are simply ignored.
37+
38+ [ Gerry Boland ]
39+ * Add LTTng tracepoints
40+
41+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Sun, 07 Sep 2014 19:42:56 +0000
42+
43 qtmir (0.4.3+14.10.20140903-0ubuntu1) utopic; urgency=medium
44
45 [ Nick Dedekind ]
46
47=== modified file 'debian/control'
48--- debian/control 2014-09-08 21:05:38 +0000
49+++ debian/control 2014-09-18 22:57:30 +0000
50@@ -11,6 +11,7 @@
51 libboost-system-dev,
52 libfontconfig1-dev,
53 libglib2.0-dev,
54+ liblttng-ust-dev,
55 libmirclient-dev (>= 0.6.0),
56 libmirserver-dev (>= 0.6.0),
57 libprocess-cpp-dev,
58@@ -25,6 +26,8 @@
59 libmircommon-dev,
60 pkg-config,
61 protobuf-compiler,
62+# lttng-gen-ts needs python3, but doesn't depend on it itself: bug 1359147
63+ python3:any,
64 qt5-default,
65 qtbase5-dev,
66 qtbase5-private-dev,
67
68=== added directory 'src/common'
69=== renamed file 'src/modules/Unity/Application/debughelpers.cpp' => 'src/common/debughelpers.cpp'
70--- src/modules/Unity/Application/debughelpers.cpp 2014-07-25 15:29:20 +0000
71+++ src/common/debughelpers.cpp 2014-09-18 22:57:30 +0000
72@@ -17,22 +17,24 @@
73 #include "debughelpers.h"
74 #include <QTouchEvent>
75
76+#include <mir_toolkit/event.h>
77+
78 // Unity API
79 #include <unity/shell/application/ApplicationInfoInterface.h>
80
81-QString touchPointStateToString(Qt::TouchPointState state)
82+const char *touchPointStateToString(Qt::TouchPointState state)
83 {
84 switch (state) {
85 case Qt::TouchPointPressed:
86- return QString("pressed");
87+ return "pressed";
88 case Qt::TouchPointMoved:
89- return QString("moved");
90+ return "moved";
91 case Qt::TouchPointStationary:
92- return QString("stationary");
93+ return "stationary";
94 case Qt::TouchPointReleased:
95- return QString("released");
96+ return "released";
97 default:
98- return QString("UNKNOWN!");
99+ return "UNKNOWN!";
100 }
101 }
102
103@@ -174,6 +176,36 @@
104 }
105 }
106
107+const char *mirMotionActionToStr(int value)
108+{
109+ switch (value) {
110+ case mir_motion_action_move:
111+ return "move";
112+ case mir_motion_action_down:
113+ return "down";
114+ case mir_motion_action_up:
115+ return "up";
116+ case mir_motion_action_pointer_down:
117+ return "pointer_down";
118+ case mir_motion_action_cancel:
119+ return "cancel";
120+ case mir_motion_action_pointer_up:
121+ return "pointer_up";
122+ case mir_motion_action_outside:
123+ return "outside";
124+ case mir_motion_action_hover_move:
125+ return "hover_move";
126+ case mir_motion_action_scroll:
127+ return "scroll";
128+ case mir_motion_action_hover_enter:
129+ return "hover_enter";
130+ case mir_motion_action_hover_exit:
131+ return "hover_exit";
132+ default:
133+ return "???";
134+ }
135+}
136+
137 using namespace unity::shell::application;
138
139 const char *applicationStateToStr(int state)
140
141=== renamed file 'src/modules/Unity/Application/debughelpers.h' => 'src/common/debughelpers.h'
142--- src/modules/Unity/Application/debughelpers.h 2014-07-25 15:29:20 +0000
143+++ src/common/debughelpers.h 2014-09-18 22:57:30 +0000
144@@ -23,7 +23,7 @@
145
146 class QTouchEvent;
147
148-QString touchPointStateToString(Qt::TouchPointState state);
149+const char *touchPointStateToString(Qt::TouchPointState state);
150 QString touchEventToString(const QTouchEvent *ev);
151
152 QString mirSurfaceAttribAndValueToString(MirSurfaceAttrib attrib, int value);
153@@ -31,6 +31,7 @@
154 const char *mirSurfaceStateToStr(int value);
155 const char *mirSurfaceFocusStateToStr(int value);
156 const char *mirSurfaceVisibilityToStr(int value);
157+const char *mirMotionActionToStr(int value);
158
159 const char *applicationStateToStr(int state);
160
161
162=== added file 'src/lttng-compiler.pri'
163--- src/lttng-compiler.pri 1970-01-01 00:00:00 +0000
164+++ src/lttng-compiler.pri 2014-09-18 22:57:30 +0000
165@@ -0,0 +1,25 @@
166+# Add extra compiler to handle LTTng TP files
167+# Append the files to the LTTNG_TP_FILES list
168+
169+# Note by Gerry (Aug 2014) - I tried to have lttng-gen-tp generate an object file but it failed to link with
170+# the shared library we want. If there's a way to pass -fPIC to lttng-gen-tp, this workaround can be avoided
171+QMAKE_EXTRA_COMPILERS += lttng_gen_tp_header
172+lttng_gen_tp_header.name = "Generating headers .TP files and adding to HEADERS list"
173+lttng_gen_tp_header.input = LTTNG_TP_FILES
174+lttng_gen_tp_header.output = $${OUT_PWD}/${QMAKE_FILE_BASE}.h
175+lttng_gen_tp_header.commands = lttng-gen-tp -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
176+lttng_gen_tp_header.dependency_type = TYPE_H
177+lttng_gen_tp_header.variable_out = HEADERS #appends the generated file name to the HEADERS list
178+lttng_gen_tp_header.CONFIG = no_link target_predeps
179+
180+QMAKE_EXTRA_COMPILERS += lttng_gen_tp_sources
181+lttng_gen_tp_sources.name = "Generating sources from .TP files and adding to SOURCES list"
182+lttng_gen_tp_sources.input = LTTNG_TP_FILES
183+lttng_gen_tp_sources.output = $${OUT_PWD}/${QMAKE_FILE_BASE}.c
184+lttng_gen_tp_sources.commands = lttng-gen-tp -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
185+lttng_gen_tp_sources.dependency_type = TYPE_C
186+lttng_gen_tp_sources.variable_out = SOURCES #appends the generated file name to the SOURCES list
187+lttng_gen_tp_sources.CONFIG = no_link target_predeps
188+
189+CONFIG += link_pkgconfig
190+PKGCONFIG += lttng-ust
191
192=== modified file 'src/modules/Unity/Application/Application.pro'
193--- src/modules/Unity/Application/Application.pro 2014-08-29 11:15:51 +0000
194+++ src/modules/Unity/Application/Application.pro 2014-09-18 22:57:30 +0000
195@@ -1,3 +1,5 @@
196+include(../../../lttng-compiler.pri)
197+
198 TARGET = unityapplicationplugin
199 TEMPLATE = lib
200
201@@ -10,9 +12,9 @@
202 QMAKE_CXXFLAGS = -std=c++11 -Werror -Wall
203 QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined
204
205-PKGCONFIG += mirserver glib-2.0 process-cpp ubuntu-app-launch-2
206+PKGCONFIG += mirserver glib-2.0 gio-unix-2.0 process-cpp ubuntu-app-launch-2
207
208-INCLUDEPATH += ../../../platforms/mirserver
209+INCLUDEPATH += ../../../platforms/mirserver ../../../common
210 LIBS += -L../../../platforms/mirserver -lqpa-mirserver
211 QMAKE_RPATHDIR += $$[QT_INSTALL_PLUGINS]/platforms # where libqpa-mirserver.so is installed
212
213@@ -24,7 +26,7 @@
214
215 SOURCES += application_manager.cpp \
216 application.cpp \
217- debughelpers.cpp \
218+ ../../../common/debughelpers.cpp \
219 desktopfilereader.cpp \
220 plugin.cpp \
221 applicationscreenshotprovider.cpp \
222@@ -44,7 +46,7 @@
223 HEADERS += application_manager.h \
224 applicationcontroller.h \
225 application.h \
226- debughelpers.h \
227+ ../../../common/debughelpers.h \
228 desktopfilereader.h \
229 applicationscreenshotprovider.h \
230 dbuswindowstack.h \
231@@ -61,8 +63,12 @@
232 processcontroller.h \
233 proc_info.h \
234 session.h \
235+ session_interface.h \
236 sessionmodel.h \
237- upstart/applicationcontroller.h
238+ upstart/applicationcontroller.h \
239+ gscopedpointer.h
240+
241+LTTNG_TP_FILES += tracepoints.tp
242
243 installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
244
245
246=== modified file 'src/modules/Unity/Application/application.cpp'
247--- src/modules/Unity/Application/application.cpp 2014-09-15 19:06:47 +0000
248+++ src/modules/Unity/Application/application.cpp 2014-09-18 22:57:30 +0000
249@@ -17,11 +17,13 @@
250 // local
251 #include "application.h"
252 #include "application_manager.h"
253-#include "debughelpers.h"
254 #include "desktopfilereader.h"
255 #include "session.h"
256 #include "taskcontroller.h"
257
258+// common
259+#include <debughelpers.h>
260+
261 // QPA mirserver
262 #include "logging.h"
263
264@@ -256,9 +258,9 @@
265 m_session->setApplication(this);
266 m_session->setState(state());
267
268- connect(m_session, &Session::suspended, this, &Application::onSessionSuspended);
269- connect(m_session, &Session::resumed, this, &Application::onSessionResumed);
270- connect(m_session, &Session::fullscreenChanged, this, &Application::fullscreenChanged);
271+ connect(m_session, &SessionInterface::suspended, this, &Application::onSessionSuspended);
272+ connect(m_session, &SessionInterface::resumed, this, &Application::onSessionResumed);
273+ connect(m_session, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged);
274
275 if (oldFullscreen != fullscreen())
276 Q_EMIT fullscreenChanged(fullscreen());
277
278=== modified file 'src/modules/Unity/Application/application.h'
279--- src/modules/Unity/Application/application.h 2014-09-08 21:42:56 +0000
280+++ src/modules/Unity/Application/application.h 2014-09-18 22:57:30 +0000
281@@ -21,6 +21,7 @@
282 #include <memory>
283
284 //Qt
285+#include <QColor>
286 #include <QtCore/QtCore>
287 #include <QImage>
288 #include <QSharedPointer>
289@@ -82,12 +83,12 @@
290 Stage stage() const override;
291 State state() const override;
292 bool focused() const override;
293- QString splashTitle() const override;
294- QUrl splashImage() const override;
295- bool splashShowHeader() const override;
296- QColor splashColor() const override;
297- QColor splashColorHeader() const override;
298- QColor splashColorFooter() const override;
299+ QString splashTitle() const;
300+ QUrl splashImage() const;
301+ bool splashShowHeader() const;
302+ QColor splashColor() const;
303+ QColor splashColorHeader() const;
304+ QColor splashColorFooter() const;
305
306 void setStage(Stage stage);
307 void setState(State state);
308
309=== modified file 'src/modules/Unity/Application/application_manager.cpp'
310--- src/modules/Unity/Application/application_manager.cpp 2014-09-08 21:05:15 +0000
311+++ src/modules/Unity/Application/application_manager.cpp 2014-09-18 22:57:30 +0000
312@@ -23,7 +23,7 @@
313 #include "proc_info.h"
314 #include "taskcontroller.h"
315 #include "upstart/applicationcontroller.h"
316-
317+#include "tracepoints.h" // generated from tracepoints.tp
318
319 // mirserver
320 #include "mirserverconfiguration.h"
321@@ -424,6 +424,7 @@
322 Application *ApplicationManager::startApplication(const QString &inputAppId, ExecFlags flags,
323 const QStringList &arguments)
324 {
325+ tracepoint(qtmir, startApplication);
326 QString appId = toShortAppIdIfPossible(inputAppId);
327 qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::startApplication - this=" << this << "appId" << qPrintable(appId);
328
329@@ -461,6 +462,7 @@
330
331 void ApplicationManager::onProcessStarting(const QString &appId)
332 {
333+ tracepoint(qtmir, onProcessStarting);
334 qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting - appId=" << appId;
335
336 Application *application = findApplication(appId);
337@@ -562,6 +564,7 @@
338
339 void ApplicationManager::onProcessStopped(const QString &appId)
340 {
341+ tracepoint(qtmir, onProcessStopped);
342 qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - appId=" << appId;
343 Application *application = findApplication(appId);
344
345@@ -637,16 +640,21 @@
346
347 void ApplicationManager::authorizeSession(const quint64 pid, bool &authorized)
348 {
349+ tracepoint(qtmir, authorizeSession);
350 authorized = false; //to be proven wrong
351
352 qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::authorizeSession - pid=" << pid;
353
354 for (Application *app : m_applications) {
355- if (app->state() == Application::Starting
356- && m_taskController->appIdHasProcessId(app->appId(), pid)) {
357- app->setPid(pid);
358- authorized = true;
359- return;
360+ if (app->state() == Application::Starting) {
361+ tracepoint(qtmir, appIdHasProcessId_start);
362+ if (m_taskController->appIdHasProcessId(app->appId(), pid)) {
363+ app->setPid(pid);
364+ authorized = true;
365+ tracepoint(qtmir, appIdHasProcessId_end, 1); //found
366+ return;
367+ }
368+ tracepoint(qtmir, appIdHasProcessId_end, 0); // not found
369 }
370 }
371
372
373=== modified file 'src/modules/Unity/Application/desktopfilereader.cpp'
374--- src/modules/Unity/Application/desktopfilereader.cpp 2014-08-07 18:15:45 +0000
375+++ src/modules/Unity/Application/desktopfilereader.cpp 2014-09-18 22:57:30 +0000
376@@ -16,142 +16,192 @@
377
378 // local
379 #include "desktopfilereader.h"
380+#include "gscopedpointer.h"
381 #include "logging.h"
382
383 // Qt
384 #include <QFile>
385+#include <QLocale>
386+
387+// GIO
388+#include <gio/gdesktopappinfo.h>
389
390 namespace qtmir
391 {
392
393-DesktopFileReader::Factory::Factory()
394-{
395-}
396-
397-DesktopFileReader::Factory::~Factory()
398-{
399-}
400
401 DesktopFileReader* DesktopFileReader::Factory::createInstance(const QString &appId, const QFileInfo& fi)
402 {
403 return new DesktopFileReader(appId, fi);
404 }
405
406-// Retrieves the size of an array at compile time.
407-#define ARRAY_SIZE(a) \
408- ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
409+typedef GObjectScopedPointer<GAppInfo> GAppInfoPointer;
410+
411+struct DesktopFileReaderPrivate
412+{
413+ DesktopFileReaderPrivate(DesktopFileReader *parent):
414+ q_ptr( parent )
415+ {}
416+
417+ QString getKey(const char *key) const
418+ {
419+ if (!loaded()) return QString();
420+
421+ return QString::fromUtf8(g_desktop_app_info_get_string((GDesktopAppInfo*)appInfo.data(), key));
422+ }
423+
424+ bool loaded() const
425+ {
426+ return !appInfo.isNull();
427+ }
428+
429+ DesktopFileReader * const q_ptr;
430+ Q_DECLARE_PUBLIC(DesktopFileReader)
431+
432+ QString appId;
433+ QString file;
434+ GAppInfoPointer appInfo; // GAppInfo is actually implemented by GDesktopAppInfo
435+};
436+
437
438 DesktopFileReader::DesktopFileReader(const QString &appId, const QFileInfo &desktopFile)
439- : appId_(appId)
440- , entries_(DesktopFileReader::kNumberOfEntries, "")
441+ : d_ptr(new DesktopFileReaderPrivate(this))
442 {
443 qCDebug(QTMIR_APPLICATIONS) << "DesktopFileReader::DesktopFileReader - this=" << this << "appId=" << appId;
444-
445- file_ = desktopFile.absoluteFilePath();
446- loaded_ = loadDesktopFile(file_);
447+ Q_D(DesktopFileReader);
448+
449+ d->appId = appId;
450+ d->file = desktopFile.absoluteFilePath();
451+ d->appInfo.reset((GAppInfo*) g_desktop_app_info_new_from_filename(d->file.toUtf8().constData()));
452+
453+ if (!d->loaded()) {
454+ qWarning() << "Desktop file for appId:" << appId << "at:" << d->file << "does not exist, or is not valid";
455+ }
456 }
457
458 DesktopFileReader::~DesktopFileReader()
459 {
460- qCDebug(QTMIR_APPLICATIONS) << "DesktopFileReader::~DesktopFileReader";
461- entries_.clear();
462-}
463-
464-bool DesktopFileReader::loadDesktopFile(QString desktopFile)
465-{
466- qCDebug(QTMIR_APPLICATIONS) << "DesktopFileReader::loadDesktopFile - this=" << this << "desktopFile=" << desktopFile;
467-
468- if (this->file().isNull() || this->file().isEmpty()) {
469- qCritical() << "No desktop file found for appId:" << appId_;
470- return false;
471- }
472-
473- Q_ASSERT(desktopFile != NULL);
474- const struct { const char* const name; int size; unsigned int flag; } kEntryNames[] = {
475- { "Name=", sizeof("Name=") - 1, 1 << DesktopFileReader::kNameIndex },
476- { "Comment=", sizeof("Comment=") - 1, 1 << DesktopFileReader::kCommentIndex },
477- { "Icon=", sizeof("Icon=") - 1, 1 << DesktopFileReader::kIconIndex },
478- { "Exec=", sizeof("Exec=") - 1, 1 << DesktopFileReader::kExecIndex },
479- { "Path=", sizeof("Path=") - 1, 1 << DesktopFileReader::kPathIndex },
480- { "X-Ubuntu-StageHint=", sizeof("X-Ubuntu-StageHint=") - 1, 1 << DesktopFileReader::kStageHintIndex },
481- { "X-Ubuntu-Splash-Title=", sizeof("X-Ubuntu-Splash-Title=") - 1, 1 << DesktopFileReader::kSplashTitleIndex },
482- { "X-Ubuntu-Splash-Image=", sizeof("X-Ubuntu-Splash-Image=") - 1, 1 << DesktopFileReader::kSplashImageIndex },
483- { "X-Ubuntu-Splash-Show-Header=", sizeof("X-Ubuntu-Splash-Show-Header=") - 1, 1 << DesktopFileReader::kSplashShowHeaderIndex },
484- { "X-Ubuntu-Splash-Color=", sizeof("X-Ubuntu-Splash-Color=") - 1, 1 << DesktopFileReader::kSplashColorIndex },
485- { "X-Ubuntu-Splash-Color-Header=", sizeof("X-Ubuntu-Splash-Color-Header=") - 1, 1 << DesktopFileReader::kSplashColorHeaderIndex },
486- { "X-Ubuntu-Splash-Color-Footer=", sizeof("X-Ubuntu-Splash-Color-Footer=") - 1, 1 << DesktopFileReader::kSplashColorFooterIndex }
487- };
488- const unsigned int kAllEntriesMask =
489- (1 << DesktopFileReader::kNameIndex) | (1 << DesktopFileReader::kCommentIndex)
490- | (1 << DesktopFileReader::kIconIndex) | (1 << DesktopFileReader::kExecIndex)
491- | (1 << DesktopFileReader::kPathIndex) | (1 << DesktopFileReader::kStageHintIndex)
492- | (1 << DesktopFileReader::kSplashTitleIndex) | (1 << DesktopFileReader::kSplashImageIndex)
493- | (1 << DesktopFileReader::kSplashShowHeaderIndex) | (1 << DesktopFileReader::kSplashColorIndex)
494- | (1 << DesktopFileReader::kSplashColorHeaderIndex) | (1 << DesktopFileReader::kSplashColorFooterIndex);
495- const unsigned int kMandatoryEntriesMask =
496- (1 << DesktopFileReader::kNameIndex) | (1 << DesktopFileReader::kIconIndex)
497- | (1 << DesktopFileReader::kExecIndex);
498- const int kEntriesCount = ARRAY_SIZE(kEntryNames);
499- const int kBufferSize = 256;
500- static char buffer[kBufferSize];
501- QFile file(desktopFile);
502-
503- // Open file.
504- if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
505- qWarning() << "Can't open file:" << file.errorString();
506- return false;
507- }
508-
509- // Validate "magic key" (standard group header).
510- if (file.readLine(buffer, kBufferSize) != -1) {
511- if (strncmp(buffer, "[Desktop Entry]", sizeof("[Desktop Entry]") - 1)) {
512- qWarning() << "not a desktop file, unable to read it";
513- return false;
514- }
515- }
516-
517- int length;
518- unsigned int entryFlags = 0;
519- while ((length = file.readLine(buffer, kBufferSize)) != -1) {
520- // Skip empty lines.
521- if (length > 1) {
522- // Stop when reaching unsupported next group header.
523- if (buffer[0] == '[') {
524- qWarning() << "reached next group header, leaving loop";
525- break;
526- }
527- // Lookup entries ignoring duplicates if any.
528- for (int i = 0; i < kEntriesCount; i++) {
529- if (!strncmp(buffer, kEntryNames[i].name, kEntryNames[i].size)) {
530- if (~entryFlags & kEntryNames[i].flag) {
531- buffer[length-1] = '\0';
532- entries_[i] = QString::fromUtf8(&buffer[kEntryNames[i].size]);
533- entryFlags |= kEntryNames[i].flag;
534- break;
535- }
536- }
537- }
538- // Stop when matching the right number of entries.
539- if (entryFlags == kAllEntriesMask) {
540- break;
541- }
542- }
543- }
544-
545- // Check that the mandatory entries are set.
546- if ((entryFlags & kMandatoryEntriesMask) == kMandatoryEntriesMask) {
547- qDebug("loaded desktop file with name='%s', comment='%s', icon='%s', exec='%s', path='%s', stagehint='%s'",
548- qPrintable(entries_[DesktopFileReader::kNameIndex]),
549- qPrintable(entries_[DesktopFileReader::kCommentIndex]),
550- qPrintable(entries_[DesktopFileReader::kIconIndex]),
551- qPrintable(entries_[DesktopFileReader::kExecIndex]),
552- qPrintable(entries_[DesktopFileReader::kPathIndex]),
553- qPrintable(entries_[DesktopFileReader::kStageHintIndex]));
554- return true;
555- } else {
556- qWarning() << "not a valid desktop file, missing mandatory entries in the standard group header";
557- return false;
558- }
559+ Q_D(const DesktopFileReader);
560+ qCDebug(QTMIR_APPLICATIONS) << "DesktopFileReader::~DesktopFileReader - this=" << this << "appId=" << d->appId;
561+ delete d_ptr;
562+}
563+
564+QString DesktopFileReader::file() const
565+{
566+ Q_D(const DesktopFileReader);
567+ return d->file;
568+}
569+
570+QString DesktopFileReader::appId() const
571+{
572+ Q_D(const DesktopFileReader);
573+ return d->appId;
574+}
575+
576+QString DesktopFileReader::name() const
577+{
578+ Q_D(const DesktopFileReader);
579+ if (!d->loaded()) return QString();
580+
581+ return QString::fromUtf8(g_app_info_get_name(d->appInfo.data()));
582+}
583+
584+QString DesktopFileReader::comment() const
585+{
586+ Q_D(const DesktopFileReader);
587+ if (!d->loaded()) return QString();
588+
589+ return QString::fromUtf8(g_app_info_get_description(d->appInfo.data()));
590+}
591+
592+QString DesktopFileReader::icon() const
593+{
594+ Q_D(const DesktopFileReader);
595+ return d->getKey("Icon");
596+}
597+
598+QString DesktopFileReader::exec() const
599+{
600+ Q_D(const DesktopFileReader);
601+ if (!d->loaded()) return QString();
602+
603+ return QString::fromUtf8(g_app_info_get_commandline(d->appInfo.data()));
604+}
605+
606+QString DesktopFileReader::path() const
607+{
608+ Q_D(const DesktopFileReader);
609+ return d->getKey("Path");
610+}
611+
612+QString DesktopFileReader::stageHint() const
613+{
614+ Q_D(const DesktopFileReader);
615+ return d->getKey("X-Ubuntu-StageHint");
616+}
617+
618+QString DesktopFileReader::splashTitle() const
619+{
620+ Q_D(const DesktopFileReader);
621+ if (!d->loaded()) return QString();
622+
623+ /* Sadly GDesktopAppInfo only considers Name, GenericName, Comments and Keywords to be keys
624+ * which can have locale-specific entries. So we need to work to make X-Ubuntu-Splash-Title
625+ * locale-aware, but generating a locale-correct key name and seeing if that exists. If yes,
626+ * get and return it. Else fallback to the non-localized key.
627+ */
628+ GDesktopAppInfo *info = (GDesktopAppInfo*)d->appInfo.data();
629+ QLocale defaultLocale;
630+ QStringList locales = defaultLocale.uiLanguages();
631+
632+ QString keyTemplate("X-Ubuntu-Splash-Title[%1]");
633+ for (QString locale: locales) {
634+ // Desktop files use local specifiers with underscore separaters but Qt uses hyphens
635+ locale = locale.replace('-', '_');
636+ const char* key = keyTemplate.arg(locale).toUtf8().constData();
637+ if (g_desktop_app_info_has_key(info, key)) {
638+ return d->getKey(key);
639+ }
640+ }
641+
642+ // Fallback to the non-localized string, if available
643+ return d->getKey("X-Ubuntu-Splash-Title");
644+}
645+
646+QString DesktopFileReader::splashImage() const
647+{
648+ Q_D(const DesktopFileReader);
649+ return d->getKey("X-Ubuntu-Splash-Image");
650+}
651+
652+QString DesktopFileReader::splashShowHeader() const
653+{
654+ Q_D(const DesktopFileReader);
655+ return d->getKey("X-Ubuntu-Splash-Show-Header");
656+}
657+
658+QString DesktopFileReader::splashColor() const
659+{
660+ Q_D(const DesktopFileReader);
661+ return d->getKey("X-Ubuntu-Splash-Color");
662+}
663+
664+QString DesktopFileReader::splashColorHeader() const
665+{
666+ Q_D(const DesktopFileReader);
667+ return d->getKey("X-Ubuntu-Splash-Color-Header");
668+}
669+
670+QString DesktopFileReader::splashColorFooter() const
671+{
672+ Q_D(const DesktopFileReader);
673+ return d->getKey("X-Ubuntu-Splash-Color-Footer");
674+}
675+
676+bool DesktopFileReader::loaded() const
677+{
678+ Q_D(const DesktopFileReader);
679+ return d->loaded();
680 }
681
682 } // namespace qtmir
683
684=== modified file 'src/modules/Unity/Application/desktopfilereader.h'
685--- src/modules/Unity/Application/desktopfilereader.h 2014-08-07 18:15:45 +0000
686+++ src/modules/Unity/Application/desktopfilereader.h 2014-09-18 22:57:30 +0000
687@@ -18,20 +18,19 @@
688 #define DESKTOPFILEREADER_H
689
690 #include <QString>
691-#include <QVector>
692 #include <QFileInfo>
693
694 namespace qtmir
695 {
696
697+class DesktopFileReaderPrivate;
698 class DesktopFileReader {
699 public:
700 class Factory
701 {
702 public:
703- Factory();
704+ Factory() = default;
705 Factory(const Factory&) = delete;
706- virtual ~Factory();
707
708 Factory& operator=(const Factory&) = delete;
709
710@@ -40,48 +39,31 @@
711
712 virtual ~DesktopFileReader();
713
714- virtual QString file() const { return file_; }
715- virtual QString appId() const { return appId_; }
716- virtual QString name() const { return entries_[kNameIndex]; }
717- virtual QString comment() const { return entries_[kCommentIndex]; }
718- virtual QString icon() const { return entries_[kIconIndex]; }
719- virtual QString exec() const { return entries_[kExecIndex]; }
720- virtual QString path() const { return entries_[kPathIndex]; }
721- virtual QString stageHint() const { return entries_[kStageHintIndex]; }
722- virtual QString splashTitle() const { return entries_[kSplashTitleIndex]; }
723- virtual QString splashImage() const { return entries_[kSplashImageIndex]; }
724- virtual QString splashShowHeader() const { return entries_[kSplashShowHeaderIndex]; }
725- virtual QString splashColor() const { return entries_[kSplashColorIndex]; }
726- virtual QString splashColorHeader() const { return entries_[kSplashColorHeaderIndex]; }
727- virtual QString splashColorFooter() const { return entries_[kSplashColorFooterIndex]; }
728- virtual bool loaded() const { return loaded_; }
729+ virtual QString file() const;
730+ virtual QString appId() const;
731+ virtual QString name() const;
732+ virtual QString comment() const;
733+ virtual QString icon() const;
734+ virtual QString exec() const;
735+ virtual QString path() const;
736+ virtual QString stageHint() const;
737+ virtual QString splashTitle() const;
738+ virtual QString splashImage() const;
739+ virtual QString splashShowHeader() const;
740+ virtual QString splashColor() const;
741+ virtual QString splashColorHeader() const;
742+ virtual QString splashColorFooter() const;
743+ virtual bool loaded() const;
744
745 protected:
746+ DesktopFileReader(const QString &appId, const QFileInfo &desktopFile);
747+
748+ DesktopFileReaderPrivate * const d_ptr;
749+
750 friend class DesktopFileReaderFactory;
751
752- DesktopFileReader(const QString &appId, const QFileInfo &desktopFile);
753-
754 private:
755- static const int kNameIndex = 0,
756- kCommentIndex = 1,
757- kIconIndex = 2,
758- kExecIndex = 3,
759- kPathIndex = 4,
760- kStageHintIndex = 5,
761- kSplashTitleIndex = 6,
762- kSplashImageIndex = 7,
763- kSplashShowHeaderIndex = 8,
764- kSplashColorIndex = 9,
765- kSplashColorHeaderIndex = 10,
766- kSplashColorFooterIndex = 11,
767- kNumberOfEntries = 12;
768-
769- virtual bool loadDesktopFile(QString desktopFile);
770-
771- QString appId_;
772- QString file_;
773- QVector<QString> entries_;
774- bool loaded_;
775+ Q_DECLARE_PRIVATE(DesktopFileReader)
776 };
777
778 } // namespace qtmir
779
780=== added file 'src/modules/Unity/Application/gscopedpointer.h'
781--- src/modules/Unity/Application/gscopedpointer.h 1970-01-01 00:00:00 +0000
782+++ src/modules/Unity/Application/gscopedpointer.h 2014-09-18 22:57:30 +0000
783@@ -0,0 +1,113 @@
784+/*
785+ * Copyright (C) 2011-2014 Canonical, Ltd.
786+ *
787+ * This program is free software: you can redistribute it and/or modify it under
788+ * the terms of the GNU Lesser General Public License version 3, as published by
789+ * the Free Software Foundation.
790+ *
791+ * This program is distributed in the hope that it will be useful, but WITHOUT
792+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
793+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
794+ * Lesser General Public License for more details.
795+ *
796+ * You should have received a copy of the GNU Lesser General Public License
797+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
798+ *
799+ * Authors:
800+ * - Aurélien Gâteau <aurelien.gateau@canonical.com>
801+ */
802+
803+#ifndef GSCOPEDPOINTER_H
804+#define GSCOPEDPOINTER_H
805+
806+// Local
807+
808+// Qt
809+#include <QScopedPointer>
810+
811+// GLib
812+#include <glib-object.h>
813+
814+/**
815+ * Helper class for GScopedPointer
816+ */
817+template <class T, void (*cleanup_fcn)(T*)>
818+class GScopedPointerDeleter
819+{
820+public:
821+ static void cleanup(T* ptr)
822+ {
823+ if (ptr) {
824+ cleanup_fcn(ptr);
825+ }
826+ }
827+};
828+
829+/**
830+ * A GScopedPointer works like a QScopedPointer, except the cleanup static
831+ * method is replaced with a cleanup function, making it useful to handle C
832+ * structs whose cleanup function prototype is "void cleanup(T*)"
833+ *
834+ * Best way to use it is to define a typedef for your C struct, like this:
835+ *
836+ * typedef GScopedPointer<Foo, foo_free> GFooPointer;
837+ */
838+template <class T, void (*cleanup)(T*)>
839+class GScopedPointer : public QScopedPointer<T, GScopedPointerDeleter<T, cleanup> >
840+{
841+public:
842+ GScopedPointer(T* ptr = 0)
843+ : QScopedPointer<T, GScopedPointerDeleter<T, cleanup> >(ptr)
844+ {}
845+};
846+
847+
848+/**
849+ * Helper class for GObjectScopedPointer
850+ */
851+template <class T, void (*cleanup_fcn)(gpointer)>
852+class GObjectScopedPointerDeleter
853+{
854+public:
855+ static void cleanup(T* ptr)
856+ {
857+ if (ptr) {
858+ cleanup_fcn(ptr);
859+ }
860+ }
861+};
862+
863+/**
864+ * A GObjectScopedPointer is similar to a GScopedPointer. The only difference
865+ * is its cleanup function signature is "void cleanup(gpointer)" and defaults to
866+ * g_object_unref(), making it useful for GObject-based classes.
867+ *
868+ * You can use it directly like this:
869+ *
870+ * GObjectScopedPointer<GFoo> foo;
871+ *
872+ * Or define a typedef for your class:
873+ *
874+ * typedef GObjectScopedPointer<GFoo> GFooPointer;
875+ *
876+ * Note: GObjectScopedPointer does *not* call gobject_ref() when assigned a
877+ * pointer.
878+ */
879+template <class T, void (*cleanup)(gpointer) = g_object_unref>
880+class GObjectScopedPointer : public QScopedPointer<T, GObjectScopedPointerDeleter<T, cleanup> >
881+{
882+public:
883+ GObjectScopedPointer(T* ptr = 0)
884+ : QScopedPointer<T, GObjectScopedPointerDeleter<T, cleanup> >(ptr)
885+ {}
886+};
887+
888+// A Generic GObject pointer
889+typedef GObjectScopedPointer<GObject> GObjectPointer;
890+
891+// Take advantage of the cleanup signature of GObjectScopedPointer to define
892+// a GCharPointer
893+typedef GObjectScopedPointer<gchar, g_free> GCharPointer;
894+
895+#endif /* GSCOPEDPOINTER_H */
896+
897
898=== modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp'
899--- src/modules/Unity/Application/mirsurfaceitem.cpp 2014-08-29 14:58:07 +0000
900+++ src/modules/Unity/Application/mirsurfaceitem.cpp 2014-09-18 22:57:30 +0000
901@@ -20,12 +20,14 @@
902
903 // local
904 #include "application.h"
905-#include "debughelpers.h"
906 #include "mirbuffersgtexture.h"
907 #include "session.h"
908 #include "mirsurfaceitem.h"
909 #include "logging.h"
910
911+// common
912+#include <debughelpers.h>
913+
914 // Qt
915 #include <QDebug>
916 #include <QQmlEngine>
917@@ -85,7 +87,10 @@
918 return true;
919 }
920
921-bool fillInMirEvent(MirEvent &mirEvent, QTouchEvent *qtEvent)
922+bool fillInMirEvent(MirEvent &mirEvent,
923+ const QList<QTouchEvent::TouchPoint> &qtTouchPoints,
924+ Qt::TouchPointStates qtTouchPointStates,
925+ ulong qtTimestamp)
926 {
927 mirEvent.type = mir_event_type_motion;
928
929@@ -97,14 +102,14 @@
930 // NB: it's assumed that touch points are pressed and released
931 // one at a time.
932
933- if (qtEvent->touchPointStates().testFlag(Qt::TouchPointPressed)) {
934- if (qtEvent->touchPoints().count() > 1) {
935+ if (qtTouchPointStates.testFlag(Qt::TouchPointPressed)) {
936+ if (qtTouchPoints.count() > 1) {
937 mirEvent.motion.action = mir_motion_action_pointer_down;
938 } else {
939 mirEvent.motion.action = mir_motion_action_down;
940 }
941- } else if (qtEvent->touchPointStates().testFlag(Qt::TouchPointReleased)) {
942- if (qtEvent->touchPoints().count() > 1) {
943+ } else if (qtTouchPointStates.testFlag(Qt::TouchPointReleased)) {
944+ if (qtTouchPoints.count() > 1) {
945 mirEvent.motion.action = mir_motion_action_pointer_up;
946 } else {
947 mirEvent.motion.action = mir_motion_action_up;
948@@ -136,18 +141,17 @@
949
950 // Note: QtEventFeeder scales the event time down, scale it back up - precision is
951 // lost but the time difference should still be accurate to milliseconds
952- mirEvent.motion.event_time = static_cast<nsecs_t>(qtEvent->timestamp()) * 1000000;
953-
954- mirEvent.motion.pointer_count = qtEvent->touchPoints().count();
955-
956- auto touchPoints = qtEvent->touchPoints();
957- for (int i = 0; i < touchPoints.count(); ++i) {
958- auto touchPoint = touchPoints.at(i);
959+ mirEvent.motion.event_time = static_cast<nsecs_t>(qtTimestamp) * 1000000;
960+
961+ mirEvent.motion.pointer_count = qtTouchPoints.count();
962+
963+ for (int i = 0; i < qtTouchPoints.count(); ++i) {
964+ auto touchPoint = qtTouchPoints.at(i);
965 auto &pointer = mirEvent.motion.pointer_coordinates[i];
966
967 // FIXME: https://bugs.launchpad.net/mir/+bug/1311699
968 // When multiple touch points are transmitted with a MirEvent
969- // and one of them (only one is allowed) indicates a pressed
970+ // and one of them (only one is allowed) indicates a presse
971 // state change the index is encoded in the second byte of the
972 // action value.
973 const int mir_motion_event_pointer_index_shift = 8;
974@@ -232,7 +236,7 @@
975 UbuntuKeyboardInfo *MirSurfaceItem::m_ubuntuKeyboardInfo = nullptr;
976
977 MirSurfaceItem::MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface,
978- QPointer<Session> session,
979+ SessionInterface* session,
980 QQuickItem *parent)
981 : QQuickItem(parent)
982 , m_surface(surface)
983@@ -240,6 +244,7 @@
984 , m_firstFrameDrawn(false)
985 , m_live(true)
986 , m_textureProvider(nullptr)
987+ , m_lastTouchEvent(nullptr)
988 {
989 qCDebug(QTMIR_SURFACES) << "MirSurfaceItem::MirSurfaceItem";
990
991@@ -314,6 +319,8 @@
992 m_surface->remove_observer(m_surfaceObserver);
993 if (m_textureProvider)
994 m_textureProvider->deleteLater();
995+
996+ delete m_lastTouchEvent;
997 }
998
999 // For QML to destroy this surface
1000@@ -327,7 +334,7 @@
1001 deleteLater();
1002 }
1003
1004-Session* MirSurfaceItem::session() const
1005+SessionInterface* MirSurfaceItem::session() const
1006 {
1007 return m_session.data();
1008 }
1009@@ -476,31 +483,115 @@
1010 }
1011 }
1012
1013+QString MirSurfaceItem::appId() const
1014+{
1015+ QString appId;
1016+ if (session() && session()->application()) {
1017+ appId = session()->application()->appId();
1018+ } else {
1019+ appId.append("-");
1020+ }
1021+ return appId;
1022+}
1023+
1024+void MirSurfaceItem::endCurrentTouchSequence(ulong timestamp)
1025+{
1026+ MirEvent mirEvent;
1027+
1028+ Q_ASSERT(m_lastTouchEvent);
1029+ Q_ASSERT(m_lastTouchEvent->type != QEvent::TouchEnd);
1030+ Q_ASSERT(m_lastTouchEvent->touchPoints.count() > 0);
1031+
1032+ TouchEvent touchEvent = *m_lastTouchEvent;
1033+ touchEvent.timestamp = timestamp;
1034+
1035+ // Remove all already released touch points
1036+ int i = 0;
1037+ while (i < touchEvent.touchPoints.count()) {
1038+ if (touchEvent.touchPoints[i].state() == Qt::TouchPointReleased) {
1039+ touchEvent.touchPoints.removeAt(i);
1040+ } else {
1041+ ++i;
1042+ }
1043+ }
1044+
1045+ // And release the others one by one as Mir expects one press/release per event
1046+ while (touchEvent.touchPoints.count() > 0) {
1047+ touchEvent.touchPoints[0].setState(Qt::TouchPointReleased);
1048+
1049+ touchEvent.updateTouchPointStatesAndType();
1050+
1051+ if (fillInMirEvent(mirEvent, touchEvent.touchPoints,
1052+ touchEvent.touchPointStates, touchEvent.timestamp)) {
1053+ m_surface->consume(mirEvent);
1054+ }
1055+ *m_lastTouchEvent = touchEvent;
1056+
1057+ touchEvent.touchPoints.removeAt(0);
1058+ }
1059+}
1060+
1061+void MirSurfaceItem::validateAndDeliverTouchEvent(int eventType,
1062+ ulong timestamp,
1063+ const QList<QTouchEvent::TouchPoint> &touchPoints,
1064+ Qt::TouchPointStates touchPointStates)
1065+{
1066+ MirEvent mirEvent;
1067+
1068+ if (eventType == QEvent::TouchBegin && m_lastTouchEvent && m_lastTouchEvent->type != QEvent::TouchEnd) {
1069+ qCWarning(QTMIR_SURFACES) << qPrintable(QString("MirSurfaceItem(%1) - Got a QEvent::TouchBegin while "
1070+ "there's still an active/unfinished touch sequence.").arg(appId()));
1071+ // Qt forgot to end the last touch sequence. Let's do it ourselves.
1072+ endCurrentTouchSequence(timestamp);
1073+ }
1074+
1075+ if (fillInMirEvent(mirEvent, touchPoints, touchPointStates, timestamp)) {
1076+ m_surface->consume(mirEvent);
1077+ }
1078+
1079+ if (!m_lastTouchEvent) {
1080+ m_lastTouchEvent = new TouchEvent;
1081+ }
1082+ m_lastTouchEvent->type = eventType;
1083+ m_lastTouchEvent->timestamp = timestamp;
1084+ m_lastTouchEvent->touchPoints = touchPoints;
1085+ m_lastTouchEvent->touchPointStates = touchPointStates;
1086+}
1087+
1088 void MirSurfaceItem::touchEvent(QTouchEvent *event)
1089 {
1090- MirEvent mirEvent;
1091- if (type() == InputMethod && event->type() == QEvent::TouchBegin) {
1092+ bool accepted = processTouchEvent(event->type(),
1093+ event->timestamp(),
1094+ event->touchPoints(),
1095+ event->touchPointStates());
1096+ event->setAccepted(accepted);
1097+}
1098+
1099+bool MirSurfaceItem::processTouchEvent(
1100+ int eventType,
1101+ ulong timestamp,
1102+ const QList<QTouchEvent::TouchPoint> &touchPoints,
1103+ Qt::TouchPointStates touchPointStates)
1104+{
1105+ bool accepted = true;
1106+ if (type() == InputMethod && eventType == QEvent::TouchBegin) {
1107 // FIXME: Hack to get the VKB use case working while we don't have the proper solution in place.
1108- if (hasTouchInsideUbuntuKeyboard(event)) {
1109- if (fillInMirEvent(mirEvent, event)) {
1110- m_surface->consume(mirEvent);
1111- }
1112+ if (hasTouchInsideUbuntuKeyboard(touchPoints)) {
1113+ validateAndDeliverTouchEvent(eventType, timestamp, touchPoints, touchPointStates);
1114 } else {
1115- event->ignore();
1116+ accepted = false;
1117 }
1118
1119 } else {
1120 // NB: If we are getting QEvent::TouchUpdate or QEvent::TouchEnd it's because we've
1121 // previously accepted the corresponding QEvent::TouchBegin
1122- if (fillInMirEvent(mirEvent, event)) {
1123- m_surface->consume(mirEvent);
1124- }
1125+ validateAndDeliverTouchEvent(eventType, timestamp, touchPoints, touchPointStates);
1126 }
1127+ return accepted;
1128 }
1129
1130-bool MirSurfaceItem::hasTouchInsideUbuntuKeyboard(QTouchEvent *event)
1131+bool MirSurfaceItem::hasTouchInsideUbuntuKeyboard(const QList<QTouchEvent::TouchPoint> &touchPoints)
1132 {
1133- const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
1134 for (int i = 0; i < touchPoints.count(); ++i) {
1135 QPoint pos = touchPoints.at(i).pos().toPoint();
1136 if (pos.x() >= m_ubuntuKeyboardInfo->x()
1137@@ -637,15 +728,15 @@
1138 m_frameDropperTimer.start();
1139 }
1140
1141-void MirSurfaceItem::setSession(Session *session)
1142+void MirSurfaceItem::setSession(SessionInterface *session)
1143 {
1144 m_session = session;
1145 }
1146
1147-void MirSurfaceItem::onSessionStateChanged(Session::State state)
1148+void MirSurfaceItem::onSessionStateChanged(SessionInterface::State state)
1149 {
1150 switch (state) {
1151- case Session::State::Running:
1152+ case SessionInterface::State::Running:
1153 syncSurfaceSizeWithItemSize();
1154 break;
1155 default:
1156@@ -674,6 +765,22 @@
1157 || !m_session;
1158 }
1159
1160+void MirSurfaceItem::TouchEvent::updateTouchPointStatesAndType()
1161+{
1162+ touchPointStates = 0;
1163+ for (int i = 0; i < touchPoints.count(); ++i) {
1164+ touchPointStates |= touchPoints.at(i).state();
1165+ }
1166+
1167+ if (touchPointStates == Qt::TouchPointReleased) {
1168+ type = QEvent::TouchEnd;
1169+ } else if (touchPointStates == Qt::TouchPointPressed) {
1170+ type = QEvent::TouchBegin;
1171+ } else {
1172+ type = QEvent::TouchUpdate;
1173+ }
1174+}
1175+
1176 } // namespace qtmir
1177
1178 #include "mirsurfaceitem.moc"
1179
1180=== modified file 'src/modules/Unity/Application/mirsurfaceitem.h'
1181--- src/modules/Unity/Application/mirsurfaceitem.h 2014-08-29 14:58:07 +0000
1182+++ src/modules/Unity/Application/mirsurfaceitem.h 2014-09-18 22:57:30 +0000
1183@@ -32,7 +32,7 @@
1184 #include <mir/scene/surface_observer.h>
1185 #include <mir_toolkit/common.h>
1186
1187-#include "session.h"
1188+#include "session_interface.h"
1189 #include "ubuntukeyboardinfo.h"
1190
1191 namespace qtmir {
1192@@ -78,7 +78,7 @@
1193
1194 public:
1195 explicit MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface,
1196- QPointer<Session> session,
1197+ SessionInterface* session,
1198 QQuickItem *parent = 0);
1199 ~MirSurfaceItem();
1200
1201@@ -107,7 +107,7 @@
1202 State state() const;
1203 QString name() const;
1204 bool live() const;
1205- Session *session() const;
1206+ SessionInterface *session() const;
1207
1208 Q_INVOKABLE void release();
1209
1210@@ -120,7 +120,13 @@
1211
1212 bool isFirstFrameDrawn() const { return m_firstFrameDrawn; }
1213
1214- void setSession(Session *app);
1215+ void setSession(SessionInterface *app);
1216+
1217+ // to allow easy touch event injection from tests
1218+ bool processTouchEvent(int eventType,
1219+ ulong timestamp,
1220+ const QList<QTouchEvent::TouchPoint> &touchPoints,
1221+ Qt::TouchPointStates touchPointStates);
1222
1223 Q_SIGNALS:
1224 void typeChanged();
1225@@ -130,7 +136,7 @@
1226 void firstFrameDrawn(MirSurfaceItem *item);
1227
1228 protected Q_SLOTS:
1229- void onSessionStateChanged(Session::State state);
1230+ void onSessionStateChanged(SessionInterface::State state);
1231
1232 protected:
1233 void mousePressEvent(QMouseEvent *event) override;
1234@@ -167,15 +173,22 @@
1235 void setAttribute(const MirSurfaceAttrib, const int);
1236 void setSurfaceValid(const bool);
1237
1238- bool hasTouchInsideUbuntuKeyboard(QTouchEvent *event);
1239+ bool hasTouchInsideUbuntuKeyboard(const QList<QTouchEvent::TouchPoint> &touchPoints);
1240 void syncSurfaceSizeWithItemSize();
1241
1242 bool clientIsRunning() const;
1243
1244+ QString appId() const;
1245+ void endCurrentTouchSequence(ulong timestamp);
1246+ void validateAndDeliverTouchEvent(int eventType,
1247+ ulong timestamp,
1248+ const QList<QTouchEvent::TouchPoint> &touchPoints,
1249+ Qt::TouchPointStates touchPointStates);
1250+
1251 QMutex m_mutex;
1252
1253 std::shared_ptr<mir::scene::Surface> m_surface;
1254- QPointer<Session> m_session;
1255+ QPointer<SessionInterface> m_session;
1256 bool m_firstFrameDrawn;
1257 bool m_live;
1258
1259@@ -189,6 +202,24 @@
1260
1261 QTimer m_updateMirSurfaceSizeTimer;
1262
1263+ class TouchEvent {
1264+ public:
1265+ TouchEvent &operator= (const QTouchEvent &qtEvent) {
1266+ type = qtEvent.type();
1267+ timestamp = qtEvent.timestamp();
1268+ touchPoints = qtEvent.touchPoints();
1269+ touchPointStates = qtEvent.touchPointStates();
1270+ return *this;
1271+ }
1272+
1273+ void updateTouchPointStatesAndType();
1274+
1275+ int type;
1276+ ulong timestamp;
1277+ QList<QTouchEvent::TouchPoint> touchPoints;
1278+ Qt::TouchPointStates touchPointStates;
1279+ } *m_lastTouchEvent;
1280+
1281 friend class MirSurfaceManager;
1282 };
1283
1284
1285=== modified file 'src/modules/Unity/Application/mirsurfacemanager.cpp'
1286--- src/modules/Unity/Application/mirsurfacemanager.cpp 2014-08-29 14:58:07 +0000
1287+++ src/modules/Unity/Application/mirsurfacemanager.cpp 2014-09-18 22:57:30 +0000
1288@@ -19,10 +19,13 @@
1289 #include <QMutexLocker>
1290
1291 // local
1292-#include "debughelpers.h"
1293 #include "mirsurfacemanager.h"
1294 #include "sessionmanager.h"
1295 #include "application_manager.h"
1296+#include "tracepoints.h" // generated from tracepoints.tp
1297+
1298+// common
1299+#include <debughelpers.h>
1300
1301 // QPA mirserver
1302 #include "nativeinterface.h"
1303@@ -96,24 +99,25 @@
1304 m_mirSurfaceToItemHash.clear();
1305 }
1306
1307-void MirSurfaceManager::onSessionCreatedSurface(const mir::scene::Session *session,
1308+void MirSurfaceManager::onSessionCreatedSurface(const mir::scene::Session *mirSession,
1309 const std::shared_ptr<mir::scene::Surface> &surface)
1310 {
1311- qCDebug(QTMIR_SURFACES) << "MirSurfaceManager::onSessionCreatedSurface - session=" << session
1312+ qCDebug(QTMIR_SURFACES) << "MirSurfaceManager::onSessionCreatedSurface - mirSession=" << mirSession
1313 << "surface=" << surface.get() << "surface.name=" << surface->name().c_str();
1314
1315- Session* sessionItem = m_sessionManager->findSession(session);
1316- auto qmlSurface = new MirSurfaceItem(surface, sessionItem);
1317+ SessionInterface* session = m_sessionManager->findSession(mirSession);
1318+ auto qmlSurface = new MirSurfaceItem(surface, session);
1319 {
1320 QMutexLocker lock(&m_mutex);
1321 m_mirSurfaceToItemHash.insert(surface.get(), qmlSurface);
1322 }
1323
1324- if (sessionItem)
1325- sessionItem->setSurface(qmlSurface);
1326+ if (session)
1327+ session->setSurface(qmlSurface);
1328
1329 // Only notify QML of surface creation once it has drawn its first frame.
1330 connect(qmlSurface, &MirSurfaceItem::firstFrameDrawn, this, [&](MirSurfaceItem *item) {
1331+ tracepoint(qtmir, firstFrameDrawn);
1332 Q_EMIT surfaceCreated(item);
1333
1334 insert(0, item);
1335@@ -128,7 +132,9 @@
1336 }
1337
1338 remove(mirSurfaceItem);
1339+ tracepoint(qtmir, surfaceDestroyed);
1340 });
1341+ tracepoint(qtmir, surfaceCreated);
1342 }
1343
1344 void MirSurfaceManager::onSessionDestroyingSurface(const mir::scene::Session *session,
1345
1346=== modified file 'src/modules/Unity/Application/plugin.cpp'
1347--- src/modules/Unity/Application/plugin.cpp 2014-09-01 16:07:27 +0000
1348+++ src/modules/Unity/Application/plugin.cpp 2014-09-18 22:57:30 +0000
1349@@ -65,6 +65,7 @@
1350 qRegisterMetaType<qtmir::MirSurfaceItem*>("MirSurfaceItem*");
1351 qRegisterMetaType<qtmir::MirSurfaceItemModel*>("MirSurfaceItemModel*");
1352 qRegisterMetaType<qtmir::Session*>("Session*");
1353+ qRegisterMetaType<qtmir::SessionInterface*>("SessionInterface*");
1354 qRegisterMetaType<qtmir::SessionModel*>("SessionModel*");
1355
1356 qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(
1357
1358=== modified file 'src/modules/Unity/Application/session.cpp'
1359--- src/modules/Unity/Application/session.cpp 2014-09-01 16:07:27 +0000
1360+++ src/modules/Unity/Application/session.cpp 2014-09-18 22:57:30 +0000
1361@@ -34,13 +34,15 @@
1362
1363 namespace ms = mir::scene;
1364
1365+using unity::shell::application::ApplicationInfoInterface;
1366+
1367 namespace qtmir
1368 {
1369
1370 Session::Session(const std::shared_ptr<ms::Session>& session,
1371 const std::shared_ptr<ms::PromptSessionManager>& promptSessionManager,
1372 QObject *parent)
1373- : QObject(parent)
1374+ : SessionInterface(parent)
1375 , m_session(session)
1376 , m_application(nullptr)
1377 , m_surface(nullptr)
1378@@ -72,8 +74,8 @@
1379 qCDebug(QTMIR_SESSIONS) << "Session::~Session() " << name();
1380 stopPromptSessions();
1381
1382- QList<Session*> children(m_children->list());
1383- for (Session* child : children) {
1384+ QList<SessionInterface*> children(m_children->list());
1385+ for (SessionInterface* child : children) {
1386 delete child;
1387 }
1388 if (m_parentSession) {
1389@@ -112,7 +114,7 @@
1390 return m_session;
1391 }
1392
1393-Application* Session::application() const
1394+ApplicationInfoInterface* Session::application() const
1395 {
1396 return m_application;
1397 }
1398@@ -127,7 +129,7 @@
1399 }
1400 }
1401
1402-Session* Session::parentSession() const
1403+SessionInterface* Session::parentSession() const
1404 {
1405 return m_parentSession;
1406 }
1407@@ -147,12 +149,12 @@
1408 return m_live;
1409 }
1410
1411-void Session::setApplication(Application* application)
1412+void Session::setApplication(ApplicationInfoInterface* application)
1413 {
1414 if (m_application == application)
1415 return;
1416
1417- m_application = application;
1418+ m_application = static_cast<Application*>(application);
1419 Q_EMIT applicationChanged(application);
1420 }
1421
1422@@ -251,7 +253,7 @@
1423 m_state = state;
1424 Q_EMIT stateChanged(state);
1425
1426- foreachChildSession([state](Session* session) {
1427+ foreachChildSession([state](SessionInterface* session) {
1428 session->setState(state);
1429 });
1430 }
1431@@ -275,35 +277,35 @@
1432 Q_EMIT parentSessionChanged(session);
1433 }
1434
1435-void Session::addChildSession(Session* session)
1436+void Session::addChildSession(SessionInterface* session)
1437 {
1438 insertChildSession(m_children->rowCount(), session);
1439 }
1440
1441-void Session::insertChildSession(uint index, Session* session)
1442+void Session::insertChildSession(uint index, SessionInterface* session)
1443 {
1444 qCDebug(QTMIR_SESSIONS) << "Session::insertChildSession - " << session->name() << " to " << name() << " @ " << index;
1445
1446- session->setParentSession(this);
1447+ static_cast<Session*>(session)->setParentSession(this);
1448 m_children->insert(index, session);
1449
1450 session->setState(state());
1451 }
1452
1453-void Session::removeChildSession(Session* session)
1454+void Session::removeChildSession(SessionInterface* session)
1455 {
1456 qCDebug(QTMIR_SESSIONS) << "Session::removeChildSession - " << session->name() << " from " << name();
1457
1458 if (m_children->contains(session)) {
1459 m_children->remove(session);
1460- session->setParentSession(nullptr);
1461+ static_cast<Session*>(session)->setParentSession(nullptr);
1462 }
1463 }
1464
1465-void Session::foreachChildSession(std::function<void(Session* session)> f) const
1466+void Session::foreachChildSession(std::function<void(SessionInterface* session)> f) const
1467 {
1468- QList<Session*> children(m_children->list());
1469- for (Session* child : children) {
1470+ QList<SessionInterface*> children(m_children->list());
1471+ for (SessionInterface* child : children) {
1472 f(child);
1473 }
1474 }
1475@@ -331,9 +333,9 @@
1476
1477 void Session::stopPromptSessions()
1478 {
1479- QList<Session*> children(m_children->list());
1480- for (Session* child : children) {
1481- child->stopPromptSessions();
1482+ QList<SessionInterface*> children(m_children->list());
1483+ for (SessionInterface* child : children) {
1484+ static_cast<Session*>(child)->stopPromptSessions();
1485 }
1486
1487 QList<std::shared_ptr<ms::PromptSession>> copy(m_promptSessions);
1488
1489=== modified file 'src/modules/Unity/Application/session.h'
1490--- src/modules/Unity/Application/session.h 2014-09-01 16:07:27 +0000
1491+++ src/modules/Unity/Application/session.h 2014-09-18 22:57:30 +0000
1492@@ -21,19 +21,15 @@
1493 #include <memory>
1494
1495 // local
1496-#include "sessionmodel.h"
1497+#include "session_interface.h"
1498
1499 // Qt
1500 #include <QObject>
1501 #include <QTimer>
1502
1503-// Unity API
1504-#include <unity/shell/application/ApplicationInfoInterface.h>
1505
1506 namespace mir {
1507 namespace scene {
1508- class Session;
1509- class PromptSession;
1510 class PromptSessionManager;
1511 }
1512 }
1513@@ -41,83 +37,61 @@
1514 namespace qtmir {
1515
1516 class Application;
1517-class MirSurfaceItem;
1518
1519-class Session : public QObject
1520+class Session : public SessionInterface
1521 {
1522 Q_OBJECT
1523- Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
1524- Q_PROPERTY(Application* application READ application NOTIFY applicationChanged DESIGNABLE false)
1525- Q_PROPERTY(Session* parentSession READ parentSession NOTIFY parentSessionChanged DESIGNABLE false)
1526- Q_PROPERTY(SessionModel* childSessions READ childSessions DESIGNABLE false CONSTANT)
1527- Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged)
1528- Q_PROPERTY(bool live READ live NOTIFY liveChanged)
1529-
1530 public:
1531 explicit Session(const std::shared_ptr<mir::scene::Session>& session,
1532 const std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager,
1533 QObject *parent = 0);
1534- ~Session();
1535-
1536- // Session State
1537- typedef unity::shell::application::ApplicationInfoInterface::State State;
1538-
1539- Q_INVOKABLE void release();
1540+ virtual ~Session();
1541+
1542+ Q_INVOKABLE void release() override;
1543
1544 //getters
1545- QString name() const;
1546- Application* application() const;
1547- MirSurfaceItem* surface() const;
1548- Session* parentSession() const;
1549- State state() const;
1550- bool fullscreen() const;
1551- bool live() const;
1552-
1553- void setSession();
1554- void setApplication(Application* item);
1555- void setSurface(MirSurfaceItem* surface);
1556- void setState(State state);
1557-
1558- void addChildSession(Session* session);
1559- void insertChildSession(uint index, Session* session);
1560- void removeChildSession(Session* session);
1561- void foreachChildSession(std::function<void(Session* session)> f) const;
1562-
1563- std::shared_ptr<mir::scene::Session> session() const;
1564-
1565- std::shared_ptr<mir::scene::PromptSession> activePromptSession() const;
1566- void foreachPromptSession(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)> f) const;
1567-
1568-Q_SIGNALS:
1569- void surfaceChanged(MirSurfaceItem*);
1570- void parentSessionChanged(Session*);
1571- void applicationChanged(Application* application);
1572- void aboutToBeDestroyed();
1573- void stateChanged(State state);
1574- void fullscreenChanged(bool fullscreen);
1575- void liveChanged(bool live);
1576-
1577- void suspended();
1578- void resumed();
1579+ QString name() const override;
1580+ unity::shell::application::ApplicationInfoInterface* application() const override;
1581+ MirSurfaceItem* surface() const override;
1582+ SessionInterface* parentSession() const override;
1583+ State state() const override;
1584+ bool fullscreen() const override;
1585+ bool live() const override;
1586+
1587+ void setApplication(unity::shell::application::ApplicationInfoInterface* item) override;
1588+ void setSurface(MirSurfaceItem* surface) override;
1589+ void setState(State state) override;
1590+
1591+ void addChildSession(SessionInterface* session) override;
1592+ void insertChildSession(uint index, SessionInterface* session) override;
1593+ void removeChildSession(SessionInterface* session) override;
1594+ void foreachChildSession(std::function<void(SessionInterface* session)> f) const override;
1595+
1596+ std::shared_ptr<mir::scene::Session> session() const override;
1597+
1598+ std::shared_ptr<mir::scene::PromptSession> activePromptSession() const override;
1599+ void foreachPromptSession(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)> f) const override;
1600+
1601+ SessionModel* childSessions() const override;
1602+
1603+protected:
1604+ void setFullscreen(bool fullscreen) override;
1605+ void setLive(const bool) override;
1606+ void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) override;
1607+ void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) override;
1608
1609 private Q_SLOTS:
1610 void updateFullscreenProperty();
1611
1612 private:
1613- SessionModel* childSessions() const;
1614 void setParentSession(Session* session);
1615
1616- void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session);
1617- void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session);
1618 void stopPromptSessions();
1619
1620- void setFullscreen(bool fullscreen);
1621- void setLive(const bool);
1622-
1623 std::shared_ptr<mir::scene::Session> m_session;
1624 Application* m_application;
1625 MirSurfaceItem* m_surface;
1626- Session* m_parentSession;
1627+ SessionInterface* m_parentSession;
1628 SessionModel* m_children;
1629 bool m_fullscreen;
1630 State m_state;
1631@@ -125,8 +99,6 @@
1632 QTimer* m_suspendTimer;
1633 QList<std::shared_ptr<mir::scene::PromptSession>> m_promptSessions;
1634 std::shared_ptr<mir::scene::PromptSessionManager> const m_promptSessionManager;
1635-
1636- friend class SessionManager;
1637 };
1638
1639 } // namespace qtmir
1640
1641=== added file 'src/modules/Unity/Application/session_interface.h'
1642--- src/modules/Unity/Application/session_interface.h 1970-01-01 00:00:00 +0000
1643+++ src/modules/Unity/Application/session_interface.h 2014-09-18 22:57:30 +0000
1644@@ -0,0 +1,106 @@
1645+/*
1646+ * Copyright (C) 2014 Canonical, Ltd.
1647+ *
1648+ * This program is free software; you can redistribute it and/or modify
1649+ * it under the terms of the GNU General Public License as published by
1650+ * the Free Software Foundation; version 3.
1651+ *
1652+ * This program is distributed in the hope that it will be useful,
1653+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1654+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1655+ * GNU General Public License for more details.
1656+ *
1657+ * You should have received a copy of the GNU General Public License
1658+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1659+ */
1660+
1661+#ifndef SESSION_INTERFACE_H
1662+#define SESSION_INTERFACE_H
1663+
1664+#include <functional>
1665+#include <memory>
1666+
1667+// Unity API
1668+#include <unity/shell/application/ApplicationInfoInterface.h>
1669+
1670+// local
1671+#include "sessionmodel.h"
1672+
1673+namespace mir {
1674+ namespace scene {
1675+ class Session;
1676+ class PromptSession;
1677+ }
1678+}
1679+
1680+namespace qtmir {
1681+
1682+class MirSurfaceItem;
1683+
1684+class SessionInterface : public QObject {
1685+ Q_OBJECT
1686+ Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
1687+ Q_PROPERTY(unity::shell::application::ApplicationInfoInterface* application READ application NOTIFY applicationChanged DESIGNABLE false)
1688+ Q_PROPERTY(SessionInterface* parentSession READ parentSession NOTIFY parentSessionChanged DESIGNABLE false)
1689+ Q_PROPERTY(SessionModel* childSessions READ childSessions DESIGNABLE false CONSTANT)
1690+ Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged)
1691+ Q_PROPERTY(bool live READ live NOTIFY liveChanged)
1692+public:
1693+ SessionInterface(QObject *parent = 0) : QObject(parent) {}
1694+ virtual ~SessionInterface() {}
1695+
1696+ // Session State
1697+ typedef unity::shell::application::ApplicationInfoInterface::State State;
1698+
1699+ Q_INVOKABLE virtual void release() = 0;
1700+
1701+ //getters
1702+ virtual QString name() const = 0;
1703+ virtual unity::shell::application::ApplicationInfoInterface* application() const = 0;
1704+ virtual MirSurfaceItem* surface() const = 0;
1705+ virtual SessionInterface* parentSession() const = 0;
1706+ virtual State state() const = 0;
1707+ virtual bool fullscreen() const = 0;
1708+ virtual bool live() const = 0;
1709+
1710+ virtual void setApplication(unity::shell::application::ApplicationInfoInterface* item) = 0;
1711+ virtual void setSurface(MirSurfaceItem* surface) = 0;
1712+ virtual void setState(State state) = 0;
1713+
1714+ virtual void addChildSession(SessionInterface* session) = 0;
1715+ virtual void insertChildSession(uint index, SessionInterface* session) = 0;
1716+ virtual void removeChildSession(SessionInterface* session) = 0;
1717+ virtual void foreachChildSession(std::function<void(SessionInterface* session)> f) const = 0;
1718+
1719+ virtual std::shared_ptr<mir::scene::Session> session() const = 0;
1720+
1721+ virtual std::shared_ptr<mir::scene::PromptSession> activePromptSession() const = 0;
1722+ virtual void foreachPromptSession(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)> f) const = 0;
1723+
1724+ virtual SessionModel* childSessions() const = 0;
1725+
1726+Q_SIGNALS:
1727+ void surfaceChanged(MirSurfaceItem*);
1728+ void parentSessionChanged(SessionInterface*);
1729+ void applicationChanged(unity::shell::application::ApplicationInfoInterface* application);
1730+ void aboutToBeDestroyed();
1731+ void stateChanged(State state);
1732+ void fullscreenChanged(bool fullscreen);
1733+ void liveChanged(bool live);
1734+
1735+ void suspended();
1736+ void resumed();
1737+
1738+protected:
1739+ virtual void setFullscreen(bool fullscreen) = 0;
1740+ virtual void setLive(const bool) = 0;
1741+ virtual void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0;
1742+ virtual void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0;
1743+
1744+ friend class SessionManager;
1745+};
1746+
1747+} // namespace qtmir
1748+
1749+
1750+#endif // SESSION_INTERFACE_H
1751
1752=== modified file 'src/modules/Unity/Application/sessionmanager.cpp'
1753--- src/modules/Unity/Application/sessionmanager.cpp 2014-08-29 14:58:07 +0000
1754+++ src/modules/Unity/Application/sessionmanager.cpp 2014-09-18 22:57:30 +0000
1755@@ -103,11 +103,11 @@
1756 qCDebug(QTMIR_SESSIONS) << "SessionManager::~SessionManager - this=" << this;
1757 }
1758
1759-Session *SessionManager::findSession(const mir::scene::Session* session) const
1760+SessionInterface *SessionManager::findSession(const mir::scene::Session* session) const
1761 {
1762 if (!session) return nullptr;
1763
1764- for (Session* child : list()) {
1765+ for (SessionInterface* child : list()) {
1766 if (child->session().get() == session)
1767 return child;
1768 }
1769@@ -139,7 +139,7 @@
1770 {
1771 qCDebug(QTMIR_SESSIONS) << "SessionManager::onSessionStopping - sessionName=" << session->name().c_str();
1772
1773- Session* qmlSession = findSession(session.get());
1774+ SessionInterface* qmlSession = findSession(session.get());
1775 if (!qmlSession) return;
1776
1777 remove(qmlSession);
1778@@ -153,7 +153,7 @@
1779 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptSessionStarting - promptSession=" << promptSession.get();
1780
1781 std::shared_ptr<mir::scene::Session> appSession = m_mirConfig->the_prompt_session_manager()->application_for(promptSession);
1782- Session *qmlAppSession = findSession(appSession.get());
1783+ SessionInterface *qmlAppSession = findSession(appSession.get());
1784 if (qmlAppSession) {
1785 m_mirPromptToSessionHash[promptSession.get()] = qmlAppSession;
1786 qmlAppSession->appendPromptSession(promptSession);
1787@@ -166,7 +166,7 @@
1788 {
1789 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptSessionStopping - promptSession=" << promptSession.get();
1790
1791- for (Session *qmlSession : this->list()) {
1792+ for (SessionInterface *qmlSession : this->list()) {
1793 qmlSession->removePromptSession(promptSession);
1794 }
1795 m_mirPromptToSessionHash.remove(promptSession.get());
1796@@ -177,13 +177,13 @@
1797 {
1798 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptProviderAdded - promptSession=" << promptSession << " promptProvider=" << promptProvider.get();
1799
1800- Session* qmlAppSession = m_mirPromptToSessionHash.value(promptSession, nullptr);
1801+ SessionInterface* qmlAppSession = m_mirPromptToSessionHash.value(promptSession, nullptr);
1802 if (!qmlAppSession) {
1803 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptProviderAdded - could not find session item for app session";
1804 return;
1805 }
1806
1807- Session* qmlPromptProvider = findSession(promptProvider.get());
1808+ SessionInterface* qmlPromptProvider = findSession(promptProvider.get());
1809 if (!qmlPromptProvider) {
1810 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptProviderAdded - could not find session item for provider session";
1811 return;
1812@@ -197,7 +197,7 @@
1813 {
1814 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptProviderRemoved - promptSession=" << promptSession << " promptProvider=" << promptProvider.get();
1815
1816- Session* qmlPromptProvider = findSession(promptProvider.get());
1817+ SessionInterface* qmlPromptProvider = findSession(promptProvider.get());
1818 if (!qmlPromptProvider) {
1819 qCDebug(QTMIR_SESSIONS) << "SessionManager::onPromptProviderAdded - could not find session item for provider session";
1820 return;
1821
1822=== modified file 'src/modules/Unity/Application/sessionmanager.h'
1823--- src/modules/Unity/Application/sessionmanager.h 2014-08-28 23:36:42 +0000
1824+++ src/modules/Unity/Application/sessionmanager.h 2014-09-18 22:57:30 +0000
1825@@ -59,11 +59,11 @@
1826
1827 static SessionManager* singleton();
1828
1829- Session *findSession(const mir::scene::Session* session) const;
1830+ SessionInterface *findSession(const mir::scene::Session* session) const;
1831
1832 Q_SIGNALS:
1833- void sessionStarting(Session* session);
1834- void sessionStopping(Session* session);
1835+ void sessionStarting(SessionInterface* session);
1836+ void sessionStopping(SessionInterface* session);
1837
1838 public Q_SLOTS:
1839 void onSessionStarting(std::shared_ptr<mir::scene::Session> const& session);
1840@@ -82,7 +82,7 @@
1841 static SessionManager *the_session_manager;
1842
1843 QList<Session*> m_sessions;
1844- QHash<const mir::scene::PromptSession *, Session *> m_mirPromptToSessionHash;
1845+ QHash<const mir::scene::PromptSession *, SessionInterface *> m_mirPromptToSessionHash;
1846 };
1847
1848 } // namespace qtmir
1849
1850=== modified file 'src/modules/Unity/Application/sessionmodel.h'
1851--- src/modules/Unity/Application/sessionmodel.h 2014-08-29 11:15:51 +0000
1852+++ src/modules/Unity/Application/sessionmodel.h 2014-09-18 22:57:30 +0000
1853@@ -22,8 +22,8 @@
1854
1855 namespace qtmir {
1856
1857-class Session;
1858-typedef ObjectListModel<Session> SessionModel;
1859+class SessionInterface;
1860+typedef ObjectListModel<SessionInterface> SessionModel;
1861
1862 } // namespace qtmir
1863
1864
1865=== added file 'src/modules/Unity/Application/tracepoints.tp'
1866--- src/modules/Unity/Application/tracepoints.tp 1970-01-01 00:00:00 +0000
1867+++ src/modules/Unity/Application/tracepoints.tp 2014-09-18 22:57:30 +0000
1868@@ -0,0 +1,9 @@
1869+TRACEPOINT_EVENT(qtmir, startApplication, TP_ARGS(0), TP_FIELDS())
1870+TRACEPOINT_EVENT(qtmir, onProcessStarting, TP_ARGS(0), TP_FIELDS())
1871+TRACEPOINT_EVENT(qtmir, authorizeSession, TP_ARGS(0), TP_FIELDS())
1872+TRACEPOINT_EVENT(qtmir, onProcessStopped, TP_ARGS(0), TP_FIELDS())
1873+TRACEPOINT_EVENT(qtmir, surfaceCreated, TP_ARGS(0), TP_FIELDS())
1874+TRACEPOINT_EVENT(qtmir, surfaceDestroyed, TP_ARGS(0), TP_FIELDS())
1875+TRACEPOINT_EVENT(qtmir, firstFrameDrawn, TP_ARGS(0), TP_FIELDS())
1876+TRACEPOINT_EVENT(qtmir, appIdHasProcessId_start, TP_ARGS(0), TP_FIELDS())
1877+TRACEPOINT_EVENT(qtmir, appIdHasProcessId_end, TP_ARGS(int, found), TP_FIELDS(ctf_integer(int, found, found)))
1878
1879=== modified file 'src/platforms/mirserver/logging.h'
1880--- src/platforms/mirserver/logging.h 2014-08-22 14:57:00 +0000
1881+++ src/platforms/mirserver/logging.h 2014-09-18 22:57:30 +0000
1882@@ -22,5 +22,6 @@
1883 Q_DECLARE_LOGGING_CATEGORY(QTMIR_SESSIONS)
1884 Q_DECLARE_LOGGING_CATEGORY(QTMIR_SURFACES)
1885 Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES)
1886+Q_DECLARE_LOGGING_CATEGORY(QTMIR_MIR_INPUT)
1887
1888 #endif // UBUNTU_APPLICATION_PLUGIN_LOGGING_H
1889
1890=== modified file 'src/platforms/mirserver/mirplacementstrategy.cpp'
1891--- src/platforms/mirserver/mirplacementstrategy.cpp 2014-07-01 13:38:06 +0000
1892+++ src/platforms/mirserver/mirplacementstrategy.cpp 2014-09-18 22:57:30 +0000
1893@@ -16,6 +16,7 @@
1894
1895 #include "mirplacementstrategy.h"
1896 #include "logging.h"
1897+#include "tracepoints.h" // generated from tracepoints.tp
1898
1899 #include <mir/geometry/rectangle.h>
1900 #include <mir/shell/display_layout.h>
1901@@ -35,6 +36,8 @@
1902 MirPlacementStrategy::place(ms::Session const& /*session*/,
1903 ms::SurfaceCreationParameters const& requestParameters)
1904 {
1905+ tracepoint(qtmirserver, surfacePlacementStart);
1906+
1907 // TODO: Callback unity8 so that it can make a decision on that.
1908 // unity8 must bear in mind that the called function will be on a Mir thread though.
1909 // The QPA shouldn't be deciding for itself on such things.
1910@@ -50,5 +53,7 @@
1911 << requestParameters.size.width.as_int() << "," << requestParameters.size.height.as_int() << ") and returned ("
1912 << placedParameters.size.width.as_int() << "," << placedParameters.size.height.as_int() << ")";
1913
1914+ tracepoint(qtmirserver, surfacePlacementEnd);
1915+
1916 return placedParameters;
1917 }
1918
1919=== modified file 'src/platforms/mirserver/mirserver.pro'
1920--- src/platforms/mirserver/mirserver.pro 2014-08-05 09:14:13 +0000
1921+++ src/platforms/mirserver/mirserver.pro 2014-09-18 22:57:30 +0000
1922@@ -1,3 +1,5 @@
1923+include(../../lttng-compiler.pri)
1924+
1925 TARGET = qpa-mirserver
1926 TEMPLATE = lib
1927
1928@@ -14,6 +16,8 @@
1929 QMAKE_CXXFLAGS = -std=c++11 -Werror -Wall
1930 QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined
1931
1932+INCLUDEPATH += ../../common
1933+
1934 CONFIG += link_pkgconfig
1935 PKGCONFIG += mirserver protobuf egl xkbcommon url-dispatcher-1
1936
1937@@ -21,6 +25,7 @@
1938
1939 SOURCES += \
1940 connectioncreator.cpp \
1941+ ../../common/debughelpers.cpp \
1942 focussetter.cpp \
1943 qteventfeeder.cpp \
1944 plugin.cpp \
1945@@ -47,6 +52,7 @@
1946
1947 HEADERS += \
1948 connectioncreator.h \
1949+ ../../common/debughelpers.h \
1950 focussetter.h \
1951 qteventfeeder.h \
1952 plugin.h \
1953@@ -73,6 +79,8 @@
1954 unityprotobufservice.h \
1955 unityrpc.h
1956
1957+LTTNG_TP_FILES += tracepoints.tp
1958+
1959 # Installation path
1960 target.path += $$[QT_INSTALL_PLUGINS]/platforms
1961
1962
1963=== modified file 'src/platforms/mirserver/mirserverconfiguration.cpp'
1964--- src/platforms/mirserver/mirserverconfiguration.cpp 2014-08-05 10:02:12 +0000
1965+++ src/platforms/mirserver/mirserverconfiguration.cpp 2014-09-18 22:57:30 +0000
1966@@ -31,20 +31,31 @@
1967 #include "logging.h"
1968 #include "unityprotobufservice.h"
1969
1970+// mir
1971+#include <mir/options/default_configuration.h>
1972+
1973 // Qt
1974 #include <QDebug>
1975
1976 // egl
1977 #include <EGL/egl.h>
1978
1979+namespace mo = mir::options;
1980 namespace msh = mir::shell;
1981 namespace ms = mir::scene;
1982
1983+namespace
1984+{
1985+void ignore_unparsed_arguments(int /*argc*/, char const* const/*argv*/[])
1986+{
1987+}
1988+}
1989+
1990 Q_LOGGING_CATEGORY(QTMIR_MIR_MESSAGES, "qtmir.mir")
1991
1992 MirServerConfiguration::MirServerConfiguration(int argc, char const* argv[], QObject* parent)
1993 : QObject(parent)
1994- , DefaultServerConfiguration(argc, argv)
1995+ , DefaultServerConfiguration(std::make_shared<mo::DefaultConfiguration>(argc, argv, &ignore_unparsed_arguments))
1996 , m_unityService(std::make_shared<UnityProtobufService>())
1997 {
1998 qCDebug(QTMIR_MIR_MESSAGES) << "MirServerConfiguration created";
1999
2000=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
2001--- src/platforms/mirserver/qteventfeeder.cpp 2014-07-29 15:01:34 +0000
2002+++ src/platforms/mirserver/qteventfeeder.cpp 2014-09-18 22:57:30 +0000
2003@@ -18,10 +18,10 @@
2004 */
2005
2006 #include "qteventfeeder.h"
2007+#include "logging.h"
2008
2009 #include <qpa/qplatforminputcontext.h>
2010 #include <qpa/qplatformintegration.h>
2011-#include <qpa/qwindowsysteminterface.h>
2012 #include <QGuiApplication>
2013 #include <private/qguiapplication_p.h>
2014
2015@@ -30,6 +30,8 @@
2016
2017 #include <QDebug>
2018
2019+Q_LOGGING_CATEGORY(QTMIR_MIR_INPUT, "qtmir.mir.input")
2020+
2021 // from android-input AMOTION_EVENT_ACTION_*, hidden inside mir bowels
2022 // mir headers should define them
2023 const int QtEventFeeder::MirEventActionMask = 0xff;
2024@@ -133,9 +135,61 @@
2025 return toupper(sym);
2026 }
2027
2028-
2029-QtEventFeeder::QtEventFeeder()
2030+namespace {
2031+
2032+class QtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
2033+
2034+ bool hasTargetWindow() override
2035+ {
2036+ if (mTopLevelWindow.isNull() && !QGuiApplication::topLevelWindows().isEmpty()) {
2037+ mTopLevelWindow = QGuiApplication::topLevelWindows().first();
2038+ }
2039+ return !mTopLevelWindow.isNull();
2040+ }
2041+
2042+ QRect targetWindowGeometry() override
2043+ {
2044+ Q_ASSERT(!mTopLevelWindow.isNull());
2045+ return mTopLevelWindow->geometry();
2046+ }
2047+
2048+ void registerTouchDevice(QTouchDevice *device) override
2049+ {
2050+ QWindowSystemInterface::registerTouchDevice(device);
2051+ }
2052+
2053+ void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,
2054+ Qt::KeyboardModifiers modifiers,
2055+ quint32 nativeScanCode, quint32 nativeVirtualKey,
2056+ quint32 nativeModifiers,
2057+ const QString& text, bool autorep, ushort count) override
2058+ {
2059+ Q_ASSERT(!mTopLevelWindow.isNull());
2060+ QWindowSystemInterface::handleExtendedKeyEvent(mTopLevelWindow.data(), timestamp, type, key, modifiers,
2061+ nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
2062+ }
2063+
2064+ void handleTouchEvent(ulong timestamp, QTouchDevice *device,
2065+ const QList<struct QWindowSystemInterface::TouchPoint> &points, Qt::KeyboardModifiers mods) override
2066+ {
2067+ Q_ASSERT(!mTopLevelWindow.isNull());
2068+ QWindowSystemInterface::handleTouchEvent(mTopLevelWindow.data(), timestamp, device, points, mods);
2069+ }
2070+private:
2071+ QPointer<QWindow> mTopLevelWindow;
2072+};
2073+
2074+} // anonymous namespace
2075+
2076+
2077+QtEventFeeder::QtEventFeeder(QtEventFeeder::QtWindowSystemInterface *windowSystem)
2078 {
2079+ if (windowSystem) {
2080+ mQtWindowSystem = windowSystem;
2081+ } else {
2082+ mQtWindowSystem = new QtWindowSystem;
2083+ }
2084+
2085 // Initialize touch device. Hardcoded just like in qtubuntu
2086 // TODO: Create them from info gathered from Mir and store things like device id and source
2087 // in a QTouchDevice-derived class created by us. So that we can properly assemble back
2088@@ -145,7 +199,12 @@
2089 mTouchDevice->setCapabilities(
2090 QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::Pressure |
2091 QTouchDevice::NormalizedPosition);
2092- QWindowSystemInterface::registerTouchDevice(mTouchDevice);
2093+ mQtWindowSystem->registerTouchDevice(mTouchDevice);
2094+}
2095+
2096+QtEventFeeder::~QtEventFeeder()
2097+{
2098+ delete mQtWindowSystem;
2099 }
2100
2101 void QtEventFeeder::dispatch(MirEvent const& event)
2102@@ -171,11 +230,9 @@
2103
2104 void QtEventFeeder::dispatchKey(MirKeyEvent const& event)
2105 {
2106- if (QGuiApplication::topLevelWindows().isEmpty())
2107+ if (!mQtWindowSystem->hasTargetWindow())
2108 return;
2109
2110- QWindow *window = QGuiApplication::topLevelWindows().first();
2111-
2112 ulong timestamp = event.event_time / 1000000;
2113 xkb_keysym_t xk_sym = static_cast<xkb_keysym_t>(event.key_code);
2114
2115@@ -221,20 +278,33 @@
2116 }
2117 }
2118
2119- QWindowSystemInterface::handleExtendedKeyEvent(window, timestamp, keyType, keyCode, modifiers, event.scan_code, event.key_code, event.modifiers, text);
2120+ mQtWindowSystem->handleExtendedKeyEvent(timestamp, keyType, keyCode, modifiers,
2121+ event.scan_code, event.key_code, event.modifiers, text);
2122 }
2123
2124 void QtEventFeeder::dispatchMotion(MirMotionEvent const& event)
2125 {
2126- if (QGuiApplication::topLevelWindows().isEmpty())
2127- return;
2128-
2129- QWindow *window = QGuiApplication::topLevelWindows().first();
2130+ if (!mQtWindowSystem->hasTargetWindow())
2131+ return;
2132+
2133+ const int mirMotionAction = event.action & MirEventActionMask;
2134+
2135+ // Ignore the events that do not interest us (or that we currently don't support or know
2136+ // how to translate into Qt events)
2137+ if (mirMotionAction != mir_motion_action_move
2138+ && mirMotionAction != mir_motion_action_down
2139+ && mirMotionAction != mir_motion_action_up
2140+ && mirMotionAction != mir_motion_action_pointer_down
2141+ && mirMotionAction != mir_motion_action_pointer_up
2142+ && mirMotionAction != mir_motion_action_cancel) {
2143+ return;
2144+ }
2145+
2146
2147 // FIXME(loicm) Max pressure is device specific. That one is for the Samsung Galaxy Nexus. That
2148 // needs to be fixed as soon as the compat input lib adds query support.
2149 const float kMaxPressure = 1.28;
2150- const QRect kWindowGeometry = window->geometry();
2151+ const QRect kWindowGeometry = mQtWindowSystem->targetWindowGeometry();
2152 QList<QWindowSystemInterface::TouchPoint> touchPoints;
2153
2154 // TODO: Is it worth setting the Qt::TouchPointStationary ones? Currently they are left
2155@@ -257,7 +327,7 @@
2156 touchPoints.append(touchPoint);
2157 }
2158
2159- switch (event.action & MirEventActionMask) {
2160+ switch (mirMotionAction) {
2161 case mir_motion_action_move:
2162 // No extra work needed.
2163 break;
2164@@ -291,13 +361,17 @@
2165 case mir_motion_action_scroll:
2166 case mir_motion_action_hover_enter:
2167 case mir_motion_action_hover_exit:
2168- default:
2169- qWarning() << "unhandled motion event action" << (int)(event.action & MirEventActionMask);
2170+ default:
2171+ // Should never reach this point. If so, it's a programming error.
2172+ qFatal("Trying to handle unsupported motion event action");
2173 }
2174
2175+ // Qt needs a happy, sane stream of touch events. So let's make sure we're not forwarding
2176+ // any insanity.
2177+ validateTouches(touchPoints);
2178+
2179 // Touch event propagation.
2180- QWindowSystemInterface::handleTouchEvent(
2181- window,
2182+ mQtWindowSystem->handleTouchEvent(
2183 event.event_time / 1000000, //scales down the nsec_t (int64) to fit a ulong, precision lost but time difference suitable
2184 mTouchDevice,
2185 touchPoints);
2186@@ -323,3 +397,86 @@
2187 Q_UNUSED(device_id);
2188 Q_UNUSED(when);
2189 }
2190+
2191+void QtEventFeeder::validateTouches(QList<QWindowSystemInterface::TouchPoint> &touchPoints)
2192+{
2193+ QSet<int> updatedTouches;
2194+
2195+ {
2196+ int i = 0;
2197+ while (i < touchPoints.count()) {
2198+ bool mustDiscardTouch = !validateTouch(touchPoints[i]);
2199+ if (mustDiscardTouch) {
2200+ touchPoints.removeAt(i);
2201+ } else {
2202+ updatedTouches.insert(touchPoints.at(i).id);
2203+ ++i;
2204+ }
2205+ }
2206+ }
2207+
2208+ // Release all unmentioned touches.
2209+ {
2210+ QHash<int, QWindowSystemInterface::TouchPoint>::iterator it = mActiveTouches.begin();
2211+ while (it != mActiveTouches.end()) {
2212+ if (!updatedTouches.contains(it.key())) {
2213+ qCWarning(QTMIR_MIR_INPUT)
2214+ << "There's a touch (id =" << it.key() << ") missing. Releasing it.";
2215+ it.value().state = Qt::TouchPointReleased;
2216+ touchPoints.append(it.value());
2217+ it = mActiveTouches.erase(it);
2218+ } else {
2219+ ++it;
2220+ }
2221+ }
2222+ }
2223+}
2224+
2225+bool QtEventFeeder::validateTouch(QWindowSystemInterface::TouchPoint &touchPoint)
2226+{
2227+ bool ok = true;
2228+
2229+ switch (touchPoint.state) {
2230+ case Qt::TouchPointPressed:
2231+ if (mActiveTouches.contains(touchPoint.id)) {
2232+ qCWarning(QTMIR_MIR_INPUT)
2233+ << "Would press an already existing touch (id =" << touchPoint.id
2234+ << "). Making it move instead.";
2235+ touchPoint.state = Qt::TouchPointMoved;
2236+ }
2237+ mActiveTouches[touchPoint.id] = touchPoint;
2238+ break;
2239+ case Qt::TouchPointMoved:
2240+ if (!mActiveTouches.contains(touchPoint.id)) {
2241+ qCWarning(QTMIR_MIR_INPUT)
2242+ << "Would move a touch that wasn't pressed before (id =" << touchPoint.id
2243+ << "). Making it press instead.";
2244+ touchPoint.state = Qt::TouchPointPressed;
2245+ }
2246+ mActiveTouches[touchPoint.id] = touchPoint;
2247+ break;
2248+ case Qt::TouchPointStationary:
2249+ if (!mActiveTouches.contains(touchPoint.id)) {
2250+ qCWarning(QTMIR_MIR_INPUT)
2251+ << "There's an stationary touch that wasn't pressed before (id =" << touchPoint.id
2252+ << "). Making it press instead.";
2253+ touchPoint.state = Qt::TouchPointPressed;
2254+ }
2255+ mActiveTouches[touchPoint.id] = touchPoint;
2256+ break;
2257+ case Qt::TouchPointReleased:
2258+ if (!mActiveTouches.contains(touchPoint.id)) {
2259+ qCWarning(QTMIR_MIR_INPUT)
2260+ << "Would release a touch that wasn't pressed before (id =" << touchPoint.id
2261+ << "). Ignoring it.";
2262+ ok = false;
2263+ } else {
2264+ mActiveTouches.remove(touchPoint.id);
2265+ }
2266+ break;
2267+ default:
2268+ qFatal("QtEventFeeder: invalid touch state");
2269+ }
2270+
2271+ return ok;
2272+}
2273
2274=== modified file 'src/platforms/mirserver/qteventfeeder.h'
2275--- src/platforms/mirserver/qteventfeeder.h 2014-07-18 20:23:35 +0000
2276+++ src/platforms/mirserver/qteventfeeder.h 2014-09-18 22:57:30 +0000
2277@@ -22,6 +22,8 @@
2278 #include <mir/input/input_dispatcher.h>
2279 #include <mir/shell/input_targeter.h>
2280
2281+#include <qpa/qwindowsysteminterface.h>
2282+
2283 class QTouchDevice;
2284
2285 /*
2286@@ -30,7 +32,29 @@
2287 class QtEventFeeder : public mir::input::InputDispatcher
2288 {
2289 public:
2290- QtEventFeeder();
2291+ // Interface between QtEventFeeder and the actual QWindowSystemInterface functions
2292+ // and other related Qt methods and objects to enable replacing them with mocks in
2293+ // pure unit tests.
2294+ // TODO - Make it work with multimonitor scenarios
2295+ class QtWindowSystemInterface {
2296+ public:
2297+ virtual ~QtWindowSystemInterface() {}
2298+ virtual bool hasTargetWindow() = 0;
2299+ virtual QRect targetWindowGeometry() = 0;
2300+ virtual void registerTouchDevice(QTouchDevice *device) = 0;
2301+ virtual void handleExtendedKeyEvent(ulong timestamp, QEvent::Type type, int key,
2302+ Qt::KeyboardModifiers modifiers,
2303+ quint32 nativeScanCode, quint32 nativeVirtualKey,
2304+ quint32 nativeModifiers,
2305+ const QString& text = QString(), bool autorep = false,
2306+ ushort count = 1) = 0;
2307+ virtual void handleTouchEvent(ulong timestamp, QTouchDevice *device,
2308+ const QList<struct QWindowSystemInterface::TouchPoint> &points,
2309+ Qt::KeyboardModifiers mods = Qt::NoModifier) = 0;
2310+ };
2311+
2312+ QtEventFeeder(QtWindowSystemInterface *windowSystem = nullptr);
2313+ virtual ~QtEventFeeder();
2314
2315 static const int MirEventActionMask;
2316 static const int MirEventActionPointerIndexMask;
2317@@ -45,8 +69,14 @@
2318 private:
2319 void dispatchKey(MirKeyEvent const& event);
2320 void dispatchMotion(MirMotionEvent const& event);
2321+ void validateTouches(QList<QWindowSystemInterface::TouchPoint> &touchPoints);
2322+ bool validateTouch(QWindowSystemInterface::TouchPoint &touchPoint);
2323
2324 QTouchDevice *mTouchDevice;
2325+ QtWindowSystemInterface *mQtWindowSystem;
2326+
2327+ // Maps the id of an active touch to its last known state
2328+ QHash<int, QWindowSystemInterface::TouchPoint> mActiveTouches;
2329 };
2330
2331 #endif // MIR_QT_EVENT_FEEDER_H
2332
2333=== modified file 'src/platforms/mirserver/sessionauthorizer.cpp'
2334--- src/platforms/mirserver/sessionauthorizer.cpp 2014-07-18 08:53:13 +0000
2335+++ src/platforms/mirserver/sessionauthorizer.cpp 2014-09-18 22:57:30 +0000
2336@@ -16,6 +16,7 @@
2337
2338 #include "sessionauthorizer.h"
2339 #include "logging.h"
2340+#include "tracepoints.h" // generated from tracepoints.tp
2341
2342 // mir
2343 #include <mir/frontend/session_credentials.h>
2344@@ -33,10 +34,13 @@
2345
2346 bool SessionAuthorizer::connection_is_allowed(SessionCredentials const& creds)
2347 {
2348+ tracepoint(qtmirserver, sessionAuthorizeStart);
2349 qCDebug(QTMIR_MIR_MESSAGES) << "SessionAuthorizer::connection_is_allowed - this=" << this << "pid=" << creds.pid();
2350 bool authorized = true;
2351
2352 Q_EMIT requestAuthorizationForSession(creds.pid(), authorized); // needs to block until authorized value returned
2353+ tracepoint(qtmirserver, sessionAuthorizeEnd);
2354+
2355 return authorized;
2356 }
2357
2358
2359=== modified file 'src/platforms/mirserver/sessionlistener.cpp'
2360--- src/platforms/mirserver/sessionlistener.cpp 2014-07-01 13:38:06 +0000
2361+++ src/platforms/mirserver/sessionlistener.cpp 2014-09-18 22:57:30 +0000
2362@@ -16,6 +16,7 @@
2363
2364 #include "sessionlistener.h"
2365 #include "logging.h"
2366+#include "tracepoints.h" // generated from tracepoints.tp
2367
2368 namespace ms = mir::scene;
2369
2370@@ -38,12 +39,14 @@
2371
2372 void SessionListener::starting(std::shared_ptr<ms::Session> const& session)
2373 {
2374+ tracepoint(qtmirserver, starting);
2375 qCDebug(QTMIR_MIR_MESSAGES) << "SessionListener::starting - this=" << this << "session=" << session.get();
2376 Q_EMIT sessionStarting(session);
2377 }
2378
2379 void SessionListener::stopping(std::shared_ptr<ms::Session> const& session)
2380 {
2381+ tracepoint(qtmirserver, stopping);
2382 qCDebug(QTMIR_MIR_MESSAGES) << "SessionListener::stopping - this=" << this << "session=" << session.get();
2383 Q_EMIT sessionStopping(session);
2384 }
2385@@ -62,6 +65,7 @@
2386
2387 void SessionListener::surface_created(ms::Session& session, std::shared_ptr<ms::Surface> const& surface)
2388 {
2389+ tracepoint(qtmirserver, surfaceCreated);
2390 qCDebug(QTMIR_MIR_MESSAGES) << "SessionListener::surface_created - this=" << this << "session=" << &session
2391 << "surface=" << surface.get();
2392 Q_EMIT sessionCreatedSurface(&session, surface);
2393@@ -69,6 +73,7 @@
2394
2395 void SessionListener::destroying_surface(ms::Session& session, std::shared_ptr<ms::Surface> const& surface)
2396 {
2397+ tracepoint(qtmirserver, surfaceDestroyed);
2398 qCDebug(QTMIR_MIR_MESSAGES) << "SessionListener::destroying_surface - this=" << this << "session=" << &session
2399 << "surface=" << surface.get();
2400 Q_EMIT sessionDestroyingSurface(&session, surface);
2401
2402=== added file 'src/platforms/mirserver/tracepoints.tp'
2403--- src/platforms/mirserver/tracepoints.tp 1970-01-01 00:00:00 +0000
2404+++ src/platforms/mirserver/tracepoints.tp 2014-09-18 22:57:30 +0000
2405@@ -0,0 +1,10 @@
2406+TRACEPOINT_EVENT(qtmirserver, starting, TP_ARGS(0), TP_FIELDS())
2407+TRACEPOINT_EVENT(qtmirserver, stopping, TP_ARGS(0), TP_FIELDS())
2408+TRACEPOINT_EVENT(qtmirserver, surfaceCreated, TP_ARGS(0), TP_FIELDS())
2409+TRACEPOINT_EVENT(qtmirserver, surfaceDestroyed, TP_ARGS(0), TP_FIELDS())
2410+
2411+TRACEPOINT_EVENT(qtmirserver, sessionAuthorizeStart, TP_ARGS(0), TP_FIELDS())
2412+TRACEPOINT_EVENT(qtmirserver, sessionAuthorizeEnd, TP_ARGS(0), TP_FIELDS())
2413+
2414+TRACEPOINT_EVENT(qtmirserver, surfacePlacementStart, TP_ARGS(0), TP_FIELDS())
2415+TRACEPOINT_EVENT(qtmirserver, surfacePlacementEnd, TP_ARGS(0), TP_FIELDS())
2416
2417=== added file 'tests/google-mock.pri'
2418--- tests/google-mock.pri 1970-01-01 00:00:00 +0000
2419+++ tests/google-mock.pri 2014-09-18 22:57:30 +0000
2420@@ -0,0 +1,24 @@
2421+GMOCK_SOURCES = /usr/src/gmock/src/gmock-all.cc \
2422+ /usr/src/gmock/src/gmock_main.cc \
2423+ /usr/src/gtest/src/gtest-all.cc
2424+
2425+QMAKE_EXTRA_COMPILERS += gmock_compiler
2426+gmock_compiler.input = GMOCK_SOURCES
2427+gmock_compiler.output = $${OUT_PWD}/${QMAKE_FILE_BASE}.o
2428+gmock_compiler.commands = g++ \
2429+ -I/usr/src/gtest \
2430+ -I/usr/src/gmock \
2431+ -c ${QMAKE_FILE_IN} \
2432+ -o ${QMAKE_FILE_OUT}
2433+gmock_compiler.CONFIG = no_link
2434+
2435+QMAKE_EXTRA_COMPILERS += gmock_linker
2436+gmock_linker.depends = $${OUT_PWD}/gmock-all.o \
2437+ $${OUT_PWD}/gmock_main.o \
2438+ $${OUT_PWD}/gtest-all.o
2439+gmock_linker.input = GMOCK_SOURCES
2440+gmock_linker.output = $${OUT_PWD}/libgmock.a
2441+gmock_linker.commands = ar -rv ${QMAKE_FILE_OUT} $${OUT_PWD}/gmock-all.o $${OUT_PWD}/gmock_main.o $${OUT_PWD}/gtest-all.o
2442+gmock_linker.CONFIG = combine explicit_dependencies no_link target_predeps
2443+
2444+LIBS += $${OUT_PWD}/libgmock.a
2445
2446=== added directory 'tests/mirserver'
2447=== added directory 'tests/mirserver/QtEventFeeder'
2448=== added file 'tests/mirserver/QtEventFeeder/QtEventFeeder.pro'
2449--- tests/mirserver/QtEventFeeder/QtEventFeeder.pro 1970-01-01 00:00:00 +0000
2450+++ tests/mirserver/QtEventFeeder/QtEventFeeder.pro 2014-09-18 22:57:30 +0000
2451@@ -0,0 +1,16 @@
2452+include(../../test-includes.pri)
2453+
2454+TARGET = QtEventFeederTest
2455+
2456+QT += gui-private
2457+
2458+INCLUDEPATH += \
2459+ ../../../src/platforms/mirserver \
2460+ ../../../src/common
2461+
2462+SOURCES += \
2463+ qteventfeeder_test.cpp \
2464+ ../../../src/common/debughelpers.cpp
2465+
2466+LIBS += -Wl,-rpath,$${OUT_PWD}/../../../src/platforms/mirserver \
2467+ -L../../../src/platforms/mirserver -lqpa-mirserver
2468
2469=== added file 'tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h'
2470--- tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 1970-01-01 00:00:00 +0000
2471+++ tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h 2014-09-18 22:57:30 +0000
2472@@ -0,0 +1,65 @@
2473+/*
2474+ * Copyright (C) 2014 Canonical, Ltd.
2475+ *
2476+ * This program is free software: you can redistribute it and/or modify it under
2477+ * the terms of the GNU Lesser General Public License version 3, as published by
2478+ * the Free Software Foundation.
2479+ *
2480+ * This program is distributed in the hope that it will be useful, but WITHOUT
2481+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2482+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2483+ * Lesser General Public License for more details.
2484+ *
2485+ * You should have received a copy of the GNU Lesser General Public License
2486+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2487+ *
2488+ */
2489+
2490+#ifndef MOCK_QTWINDOWSYSTEM_H
2491+#define MOCK_QTWINDOWSYSTEM_H
2492+
2493+#include <qteventfeeder.h>
2494+
2495+class MockQtWindowSystem : public QtEventFeeder::QtWindowSystemInterface {
2496+public:
2497+ MOCK_METHOD0(hasTargetWindow, bool());
2498+ MOCK_METHOD0(targetWindowGeometry, QRect());
2499+ MOCK_METHOD1(registerTouchDevice, void(QTouchDevice* device));
2500+ MOCK_METHOD10(handleExtendedKeyEvent, void(ulong timestamp, QEvent::Type type, int key,
2501+ Qt::KeyboardModifiers modifiers,
2502+ quint32 nativeScanCode, quint32 nativeVirtualKey,
2503+ quint32 nativeModifiers,
2504+ const QString& text, bool autorep,
2505+ ushort count));
2506+ MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device,
2507+ const QList<struct QWindowSystemInterface::TouchPoint> &points,
2508+ Qt::KeyboardModifiers mods));
2509+};
2510+
2511+namespace testing
2512+{
2513+
2514+MATCHER(IsPressed, std::string(negation ? "isn't" : "is") + " pressed")
2515+{
2516+ return arg.state == Qt::TouchPointPressed;
2517+}
2518+
2519+MATCHER(IsReleased, std::string(negation ? "isn't" : "is") + " released")
2520+{
2521+ return arg.state == Qt::TouchPointReleased;
2522+}
2523+
2524+MATCHER(StateIsMoved, "state " + std::string(negation ? "isn't" : "is") + " 'moved'")
2525+{
2526+ return arg.state == Qt::TouchPointMoved;
2527+}
2528+
2529+MATCHER_P(HasId, expectedId, "id " + std::string(negation ? "isn't " : "is ") + PrintToString(expectedId))
2530+{
2531+ return arg.id == expectedId;
2532+}
2533+
2534+} // namespace testing
2535+
2536+
2537+#endif // MOCK_QTWINDOWSYSTEM_H
2538
2539=== added file 'tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp'
2540--- tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 1970-01-01 00:00:00 +0000
2541+++ tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp 2014-09-18 22:57:30 +0000
2542@@ -0,0 +1,224 @@
2543+/*
2544+ * Copyright (C) 2014 Canonical, Ltd.
2545+ *
2546+ * This program is free software: you can redistribute it and/or modify it under
2547+ * the terms of the GNU Lesser General Public License version 3, as published by
2548+ * the Free Software Foundation.
2549+ *
2550+ * This program is distributed in the hope that it will be useful, but WITHOUT
2551+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
2552+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2553+ * Lesser General Public License for more details.
2554+ *
2555+ * You should have received a copy of the GNU Lesser General Public License
2556+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2557+ *
2558+ */
2559+
2560+#include <gmock/gmock.h>
2561+#include <gtest/gtest.h>
2562+
2563+#include <qteventfeeder.h>
2564+#include <debughelpers.h>
2565+
2566+#include <QGuiApplication>
2567+#include <QWindow>
2568+
2569+#include "mock_qtwindowsystem.h"
2570+
2571+using ::testing::_;
2572+using ::testing::AllOf;
2573+using ::testing::AnyNumber;
2574+using ::testing::Contains;
2575+using ::testing::AtLeast;
2576+using ::testing::InSequence;
2577+using ::testing::Mock;
2578+using ::testing::SizeIs;
2579+using ::testing::Return;
2580+
2581+// own gmock extensions
2582+using ::testing::IsPressed;
2583+using ::testing::IsReleased;
2584+using ::testing::HasId;
2585+using ::testing::StateIsMoved;
2586+
2587+void PrintTo(const struct QWindowSystemInterface::TouchPoint& touchPoint, ::std::ostream* os) {
2588+ *os << "TouchPoint("
2589+ << "id=" << touchPoint.id
2590+ << "," << touchPointStateToString(touchPoint.state)
2591+ << ")";
2592+}
2593+
2594+class QtEventFeederTest : public ::testing::Test {
2595+protected:
2596+ void SetUp() override;
2597+ void TearDown() override;
2598+
2599+ void setIrrelevantMockWindowSystemExpectations();
2600+
2601+ MockQtWindowSystem *mockWindowSystem;
2602+ QtEventFeeder *qtEventFeeder;
2603+};
2604+
2605+void QtEventFeederTest::SetUp()
2606+{
2607+ mockWindowSystem = new MockQtWindowSystem;
2608+
2609+ EXPECT_CALL(*mockWindowSystem, registerTouchDevice(_));
2610+
2611+ qtEventFeeder = new QtEventFeeder(mockWindowSystem);
2612+
2613+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
2614+}
2615+
2616+void QtEventFeederTest::TearDown()
2617+{
2618+ // mockWindowSystem will be deleted by QtEventFeeder
2619+ delete qtEventFeeder;
2620+}
2621+
2622+void QtEventFeederTest::setIrrelevantMockWindowSystemExpectations()
2623+{
2624+ EXPECT_CALL(*mockWindowSystem, hasTargetWindow())
2625+ .Times(AnyNumber())
2626+ .WillRepeatedly(Return(true));
2627+ EXPECT_CALL(*mockWindowSystem, targetWindowGeometry())
2628+ .Times(AnyNumber())
2629+ .WillRepeatedly(Return(QRect(0,0,100,100)));
2630+}
2631+
2632+
2633+/*
2634+ Mir sends a MirEvent([touch(id=0,state=pressed)]. QtEventFeeder happily forwards that to Qt.
2635+
2636+ Then, Mir sends a MirEvent([touch(id=1,state=pressed)]). In MirEvents, every single active touch
2637+ point must be listed in the event even if it didn't change at all in the meantime. So that's a bug.
2638+ But instead of crashing or forwarding the bogus event stream down to Qt, QtEventFeeder should attempt
2639+ to fix the situation by synthesizing a touch[id=1,state=released] to be send along with the
2640+ touch(id=1,state=pressed) it got. So that Qt receives a correct touch event stream.
2641+ */
2642+TEST_F(QtEventFeederTest, GenerateMissingTouchEnd)
2643+{
2644+
2645+ setIrrelevantMockWindowSystemExpectations();
2646+
2647+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
2648+ Contains(AllOf(HasId(0),
2649+ IsPressed()))),_)).Times(1);
2650+
2651+ MirEvent mirEvent;
2652+ mirEvent.type = mir_event_type_motion;
2653+ mirEvent.motion.pointer_count = 1;
2654+ mirEvent.motion.pointer_coordinates[0].id = 0;
2655+ mirEvent.motion.pointer_coordinates[0].x = 10;
2656+ mirEvent.motion.pointer_coordinates[0].y = 10;
2657+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
2658+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
2659+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
2660+ mirEvent.motion.action = mir_motion_action_down;
2661+ mirEvent.motion.event_time = 123 * 1000000;
2662+
2663+ qtEventFeeder->dispatch(mirEvent);
2664+
2665+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
2666+
2667+ setIrrelevantMockWindowSystemExpectations();
2668+
2669+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(2),
2670+ Contains(AllOf(HasId(0),IsReleased())),
2671+ Contains(AllOf(HasId(1),IsPressed()))
2672+ ),_)).Times(1);
2673+
2674+ mirEvent.type = mir_event_type_motion;
2675+ mirEvent.motion.pointer_count = 1;
2676+ mirEvent.motion.pointer_coordinates[0].id = 1;
2677+ mirEvent.motion.pointer_coordinates[0].x = 20;
2678+ mirEvent.motion.pointer_coordinates[0].y = 20;
2679+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
2680+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
2681+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
2682+ mirEvent.motion.action = mir_motion_action_down;
2683+ mirEvent.motion.event_time = 125 * 1000000;
2684+
2685+ qtEventFeeder->dispatch(mirEvent);
2686+
2687+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
2688+}
2689+
2690+TEST_F(QtEventFeederTest, PressSameTouchTwice)
2691+{
2692+ setIrrelevantMockWindowSystemExpectations();
2693+
2694+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
2695+ Contains(AllOf(HasId(0),
2696+ IsPressed()))),_)).Times(1);
2697+
2698+ MirEvent mirEvent;
2699+ mirEvent.type = mir_event_type_motion;
2700+ mirEvent.motion.pointer_count = 1;
2701+ mirEvent.motion.pointer_coordinates[0].id = 0;
2702+ mirEvent.motion.pointer_coordinates[0].x = 10;
2703+ mirEvent.motion.pointer_coordinates[0].y = 10;
2704+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
2705+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
2706+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
2707+ mirEvent.motion.action = mir_motion_action_down;
2708+ mirEvent.motion.event_time = 123 * 1000000;
2709+
2710+ qtEventFeeder->dispatch(mirEvent);
2711+
2712+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
2713+
2714+ setIrrelevantMockWindowSystemExpectations();
2715+
2716+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,AllOf(SizeIs(1),
2717+ Contains(AllOf(HasId(0), StateIsMoved()))
2718+ ),_)).Times(1);
2719+
2720+ mirEvent.type = mir_event_type_motion;
2721+ mirEvent.motion.pointer_count = 1;
2722+ mirEvent.motion.pointer_coordinates[0].id = 0;
2723+ mirEvent.motion.pointer_coordinates[0].x = 20;
2724+ mirEvent.motion.pointer_coordinates[0].y = 20;
2725+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
2726+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
2727+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
2728+ mirEvent.motion.action = mir_motion_action_down;
2729+ mirEvent.motion.event_time = 125 * 1000000;
2730+
2731+ qtEventFeeder->dispatch(mirEvent);
2732+
2733+ ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
2734+}
2735+
2736+TEST_F(QtEventFeederTest, IgnoreHovering)
2737+{
2738+ setIrrelevantMockWindowSystemExpectations();
2739+ EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,_)).Times(0);
2740+
2741+ MirEvent mirEvent;
2742+ mirEvent.type = mir_event_type_motion;
2743+ mirEvent.motion.pointer_count = 1;
2744+ mirEvent.motion.pointer_coordinates[0].id = 0;
2745+ mirEvent.motion.pointer_coordinates[0].x = 10;
2746+ mirEvent.motion.pointer_coordinates[0].y = 10;
2747+ mirEvent.motion.pointer_coordinates[0].touch_major = 1;
2748+ mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
2749+ mirEvent.motion.pointer_coordinates[0].pressure = 10;
2750+ mirEvent.motion.action = mir_motion_action_hover_enter;
2751+ mirEvent.motion.event_time = 123 * 1000000;
2752+
2753+ qtEventFeeder->dispatch(mirEvent);
2754+
2755+ mirEvent.motion.pointer_coordinates[0].x = 20;
2756+ mirEvent.motion.pointer_coordinates[0].y = 20;
2757+ mirEvent.motion.action = mir_motion_action_hover_move;
2758+ mirEvent.motion.event_time = 125 * 1000000;
2759+
2760+ qtEventFeeder->dispatch(mirEvent);
2761+
2762+ mirEvent.motion.action = mir_motion_action_hover_exit;
2763+ mirEvent.motion.event_time = 127 * 1000000;
2764+
2765+ qtEventFeeder->dispatch(mirEvent);
2766+}
2767
2768=== added file 'tests/mirserver/mirserver.pro'
2769--- tests/mirserver/mirserver.pro 1970-01-01 00:00:00 +0000
2770+++ tests/mirserver/mirserver.pro 2014-09-18 22:57:30 +0000
2771@@ -0,0 +1,2 @@
2772+TEMPLATE = subdirs
2773+SUBDIRS = QtEventFeeder
2774
2775=== modified file 'tests/modules/ApplicationManager/application_manager_test.cpp'
2776--- tests/modules/ApplicationManager/application_manager_test.cpp 2014-08-29 10:18:57 +0000
2777+++ tests/modules/ApplicationManager/application_manager_test.cpp 2014-09-18 22:57:30 +0000
2778@@ -25,6 +25,7 @@
2779 #include "qtmir_test.h"
2780
2781 using namespace qtmir;
2782+using mir::scene::MockSession;
2783
2784 namespace ms = mir::scene;
2785
2786@@ -1774,7 +1775,7 @@
2787 }).detach();
2788 }));
2789
2790- auto mockSurface = std::make_shared<MockSurface>();
2791+ auto mockSurface = std::make_shared<ms::MockSurface>();
2792 EXPECT_CALL(*session, default_surface()).WillRepeatedly(Return(mockSurface));
2793
2794 {
2795@@ -1826,7 +1827,7 @@
2796 }).detach();
2797 }));
2798
2799- auto mockSurface = std::make_shared<MockSurface>();
2800+ auto mockSurface = std::make_shared<ms::MockSurface>();
2801 EXPECT_CALL(*session, default_surface()).WillRepeatedly(Return(mockSurface));
2802
2803 {
2804
2805=== added directory 'tests/modules/DesktopFileReader'
2806=== added file 'tests/modules/DesktopFileReader/DesktopFileReader.pro'
2807--- tests/modules/DesktopFileReader/DesktopFileReader.pro 1970-01-01 00:00:00 +0000
2808+++ tests/modules/DesktopFileReader/DesktopFileReader.pro 2014-09-18 22:57:30 +0000
2809@@ -0,0 +1,15 @@
2810+include(../../test-includes.pri)
2811+include(../common/common.pri)
2812+
2813+TARGET = desktopfilereader_test
2814+
2815+SOURCES += \
2816+ desktopfilereader_test.cpp
2817+
2818+OTHER_FILES += \
2819+ calculator.desktop
2820+
2821+# Copy to build directory
2822+for(FILE, OTHER_FILES){
2823+ QMAKE_POST_LINK += $$quote(cp $${PWD}/$${FILE} $${OUT_PWD}$$escape_expand(\\n\\t))
2824+}
2825
2826=== added file 'tests/modules/DesktopFileReader/calculator.desktop'
2827--- tests/modules/DesktopFileReader/calculator.desktop 1970-01-01 00:00:00 +0000
2828+++ tests/modules/DesktopFileReader/calculator.desktop 2014-09-18 22:57:30 +0000
2829@@ -0,0 +1,227 @@
2830+[Desktop Entry]
2831+Name=Calculator
2832+Name[am]=መደመሪያ
2833+Name[ar]=الآلة الحاسبة
2834+Name[ast]=Calculadora
2835+Name[az]=Kalkulyator
2836+Name[be]=Калькулятар
2837+Name[bg]=Калкулатор
2838+Name[br]=Jederez
2839+Name[bs]=Kalkulator
2840+Name[ca]=Calculadora
2841+Name[cs]=Kalkulačka
2842+Name[cy]=Cyfrifiannell
2843+Name[da]=Lommeregner
2844+Name[de]=Taschenrechner
2845+Name[el]=Αριθμομηχανή
2846+Name[en_AU]=Calculator
2847+Name[en_CA]=Calculator
2848+Name[en_GB]=Calculator
2849+Name[es]=Calculadora
2850+Name[eu]=Kalkulagailua
2851+Name[fa]=ماشین‌حساب
2852+Name[fi]=Laskin
2853+Name[fr]=Calculatrice
2854+Name[gd]=An t-àireamhair
2855+Name[gl]=Calculadora
2856+Name[gu]=કેલ્ક્યુલેટર
2857+Name[he]=מחשבון
2858+Name[hi]=कैलकुलेटर
2859+Name[hu]=Számológép
2860+Name[id]=Kalkulator
2861+Name[is]=Reiknivél
2862+Name[it]=Calcolatrice
2863+Name[ja]=電卓
2864+Name[km]=ម៉ាស៊ីន​គិត​លេខ
2865+Name[ko]=계산기
2866+Name[lv]=Kalkulators
2867+Name[mr]=गणनयंत्र
2868+Name[ms]=Kalkulator
2869+Name[my]=ဂဏန်းတွက်စက်
2870+Name[nb]=Kalkulator
2871+Name[ne]=क्याल्कुलेटर
2872+Name[nl]=Rekenmachine
2873+Name[pa]=ਕੈਲਕੂਲੇਟਰ
2874+Name[pl]=Kalkulator
2875+Name[pt]=Calculadora
2876+Name[pt_BR]=Calculadora
2877+Name[ro]=Calculator
2878+Name[ru]=Калькулятор
2879+Name[sa]=सङ्कलकम्
2880+Name[shn]=ၸၢၵ်ႈၼပ့်သွၼ်
2881+Name[sl]=Računalo
2882+Name[sr]=Калкулатор
2883+Name[sv]=Kalkylator
2884+Name[ta]=கணிப்பான்
2885+Name[te]=గణన పరికరం
2886+Name[tr]=Hesap Makinesi
2887+Name[ug]=ھېسابلىغۇچ
2888+Name[uk]=Калькулятор
2889+Name[zh_CN]=计算器
2890+Name[zh_HK]=計數機
2891+Name[zh_TW]=計算機
2892+Comment=A simple calculator for Ubuntu.
2893+Comment[am]=ለ ኡቡንቱ ቀላል መደመሪያ
2894+Comment[ar]=آلة حاسبة بسيطة لأوبونتو.
2895+Comment[ast]=Una calculadora cenciella pa Ubuntu.
2896+Comment[az]=Ubuntu üçün sadә kalkulyator.
2897+Comment[br]=Ur jederez eeun evit Ubuntu.
2898+Comment[ca]=Una calculadora simple per a l'Ubuntu.
2899+Comment[cy]=Cyfrifiannell hawdd ar gyfer Ubuntu.
2900+Comment[da]=En simpel lommeregner til Ubuntu.
2901+Comment[de]=Ein einfach Tachenrechner für Ubuntu.
2902+Comment[el]=Μια απλή αριθμομηχανή για το Ubuntu
2903+Comment[en_AU]=A simple calculator for Ubuntu.
2904+Comment[en_GB]=A simple calculator for Ubuntu.
2905+Comment[es]=Una calculadora sencilla para Ubuntu.
2906+Comment[eu]=Ubunturako kalkulagailu sinplea.
2907+Comment[fa]=یک ماشین حساب ساده برای اوبونتو.
2908+Comment[fi]=Laskin Ubuntulle.
2909+Comment[fr]=Une calculatrice simple pour Ubuntu.
2910+Comment[gd]=Àireamhair simplidh airson Ubuntu.
2911+Comment[gl]=Calculadora sinxela para Ubuntu.
2912+Comment[he]=מחשבון פשוט לאובונטו.
2913+Comment[hu]=Egyszerű számológép Ubuntuhoz.
2914+Comment[is]=Einföld reiknivél
2915+Comment[it]=Una semplice calcolatrice per Ubuntu.
2916+Comment[ja]=Ubuntu用のシンプルな電卓です。
2917+Comment[km]=ម៉ាស៊ីន​គិត​លេខ​ធម្មតា​សម្រាប់ Ubuntu ។
2918+Comment[ko]=우분투를 위한 간단한 계산기
2919+Comment[lv]=Vienkāršs kalkulators priekš Ubuntu
2920+Comment[nb]=En enkel kalkulator for Ubuntu.
2921+Comment[ne]=Ubuntu को लागि एक सरल कैलकुलेटर।
2922+Comment[nl]=Een eenvoudige rekenmachine voor Ubuntu.
2923+Comment[pa]=ਉਬੰਤੂ ਲਈ ਇੱਕ ਸਧਾਰਨ ਕੈਲਕੂਲੇਟਰ
2924+Comment[pl]=Prosty kalkulator dla Ubuntu
2925+Comment[pt]=Uma calculadora simples para o Ubuntu.
2926+Comment[pt_BR]=Uma simples calculadora para Ubuntu
2927+Comment[ro]=Un calculator simplu pentru Ubuntu.
2928+Comment[ru]=Простой калькулятор для Ubuntu
2929+Comment[sa]=Ubuntu इत्यस्मा एकं सरलं सङ्कलकम्।
2930+Comment[sl]=Preprost kalkulator za Ubuntu.
2931+Comment[sr]=Једноставан калкулатор за Убунту
2932+Comment[sv]=En enkel kalkylator för Ubuntu.
2933+Comment[tr]=Ubuntu için sade bir hesap makinesi.
2934+Comment[ug]=ئاددىي ھېسابلىغۇچى
2935+Comment[uk]=Простий калькулятор для Ubuntu.
2936+Comment[zh_CN]=Ubuntu 简易计算器
2937+Comment[zh_TW]=Ubuntu 簡易計算機。
2938+Keywords=math;addition;subtraction;multiplication;division;
2939+Keywords[am]=ሂሳብ;መደመሪያ;መቀነሻ;ማባዣ;ማካፈያ;
2940+Keywords[ar]=رياضة;ياضيات;حساب;حسابات;جمع;طرح;ضرب;قسمة;
2941+Keywords[ast]=matemática;suma;resta;multiplicación;división;
2942+Keywords[az]=riyaziyyat;әlavә etmә;çıxma;vurma;bölmә;toplama;
2943+Keywords[br]=matematikoù;sammadenn;lamadenn;lieskementadenn;rannadenn;
2944+Keywords[ca]=suma;resta;calculadora;multiplica;divideix
2945+Keywords[da]=matematik;plus;minus;gange;dividere;beregning;lommeregner;
2946+Keywords[de]=Mathe;Mathematik;Multiplikation;Subtraktion;Addition;Division;
2947+Keywords[en_AU]=math;addition;subtraction;multiplication;division;
2948+Keywords[en_GB]=maths;addition;subtraction;multiplication;division;
2949+Keywords[es]=matemática;suma;resta;multiplicación;división;
2950+Keywords[eu]=matematikak;gehitu;kendu;biderkatu;zatitu;
2951+Keywords[fa]=حساب;جمع;تفریق;ضرب;تقسیم
2952+Keywords[fi]=math;addition;subtraction;multiplication;division;matematiikka;lisäys;vähennys;kertaus;jakaminen;
2953+Keywords[fr]=math;addition;soustraction;multiplication;division;
2954+Keywords[gd]=math;addition;subtraction;multiplication;division;matamataig;roinneadh;toirt air falbh;cur ris;iomadadh
2955+Keywords[gl]=matemáticas;suma;resta;multiplicación;división;
2956+Keywords[he]=מתמטיקה;חשבון;חיבור;חיסור;כפל;חילוק;
2957+Keywords[hu]=számolás;összeadás;kivonás;szorzás;osztás;
2958+Keywords[is]=reikna;samlagning;frádráttur;margföldun;deiling
2959+Keywords[it]=matematica;addizioni;sottrazioni;moltiplicazioni;divisioni;
2960+Keywords[ja]=math;addition;subtraction;multiplication;division;計算;電卓;足し算;引き算;かけ算;わり算;
2961+Keywords[km]=math;addition;subtraction;multiplication;division;
2962+Keywords[ko]=수학;덧셈;뺄셈;곱셈;나눗셈;
2963+Keywords[nb]=matte;addisjon;subtraksjon;multiplikasjon;divisjon;
2964+Keywords[ne]=गणित; जोड्; घटाउ; गुणन; विभाजन;
2965+Keywords[nl]=math;addition;subtraction;multiplication;division;optellen;aftrekken;vermenigvuldigen;delen;
2966+Keywords[pa]=ਹਿਸਾਬ;ਜੋੜ;ਘਟਾਉ;ਗੁਣਾ;ਭਾਗ;
2967+Keywords[pl]=liczenie;dodawanie;odejmowanie;mnożenie;dzielenie;
2968+Keywords[pt]=matemática;soma;subtracção;multiplicação;divisão;
2969+Keywords[pt_BR]=matemática;adição;subtração;multiplicação;divisão
2970+Keywords[ro]=matematică;adunare;scădere;înmulțire;împărțire
2971+Keywords[ru]=математика;сложение;умножение;деление;
2972+Keywords[sa]=गणितम्;योजनम्;वियोजनम्;गुणनम्;विभाजनम्;
2973+Keywords[sl]=matematika;seštevanje;odštevanje;množenje;deljenje;
2974+Keywords[sr]=математика;сабирање;одузимање;множење;дељење;рачунање;дигитрон;
2975+Keywords[sv]=matematik;addition;substraktion;multiplikation;division
2976+Keywords[tr]=matematik;ekleme;çıkarma;çarpma;bölme;toplama
2977+Keywords[ug]=ماتېماتىكا;قوشۇش;ئېلىش;كۆپەيتىش;بۆلۈش;
2978+Keywords[uk]=math;addition;subtraction;multiplication;division;математика;додавання;віднімання;множення;ділення;калькулятор;
2979+Keywords[zh_CN]=数学;加;减;乘;除;
2980+Keywords[zh_TW]=math;addition;subtraction;multiplication;division;數學;加;減;乘;除;
2981+Type=Application
2982+Terminal=false
2983+Exec=aa-exec-click -p com.ubuntu.calculator_calculator_1.3.329 -- qmlscene -qt5 ubuntu-calculator-app.qml
2984+Icon=/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator/calculator-app@30.png
2985+X-Ubuntu-Touch=true
2986+X-Ubuntu-StageHint=SideStage
2987+X-Ubuntu-Default-Department-ID=accessories
2988+Path=/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator
2989+X-Ubuntu-Old-Icon=calculator-app@30.png
2990+X-Ubuntu-Application-ID=com.ubuntu.calculator_calculator_1.3.329
2991+X-Ubuntu-Splash-Show-Header=True
2992+X-Ubuntu-Splash-Color=#aabbcc
2993+X-Ubuntu-Splash-Color-Header=purple
2994+X-Ubuntu-Splash-Color-Footer=#deadbeefda
2995+X-Ubuntu-Splash-Image=/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator/calculator-app@30.png
2996+X-Ubuntu-Splash-Title=Calculator 2.0
2997+X-Ubuntu-Splash-Title[am]=መደመሪያ 2.0
2998+X-Ubuntu-Splash-Title[ar]=الآلة 2.0الحاسبة
2999+X-Ubuntu-Splash-Title[ast]=Calculadora 2.0
3000+X-Ubuntu-Splash-Title[az]=Kalkulyator 2.0
3001+X-Ubuntu-Splash-Title[be]=Калькулятар 2.0
3002+X-Ubuntu-Splash-Title[bg]=Калкулатор 2.0
3003+X-Ubuntu-Splash-Title[br]=Jederez 2.0
3004+X-Ubuntu-Splash-Title[bs]=Kalkulator 2.0
3005+X-Ubuntu-Splash-Title[ca]=Calculadora 2.0
3006+X-Ubuntu-Splash-Title[cs]=Kalkulačka 2.0
3007+X-Ubuntu-Splash-Title[cy]=Cyfrifiannell 2.0
3008+X-Ubuntu-Splash-Title[da]=Lommeregner 2.0
3009+X-Ubuntu-Splash-Title[de]=Taschenrechner 2.0
3010+X-Ubuntu-Splash-Title[el]=Αριθμομηχανή 2.0
3011+X-Ubuntu-Splash-Title[en_AU]=Calculator 2.0
3012+X-Ubuntu-Splash-Title[en_CA]=Calculator 2.0
3013+X-Ubuntu-Splash-Title[en_GB]=Calculator 2.0
3014+X-Ubuntu-Splash-Title[es]=Calculadora 2.0
3015+X-Ubuntu-Splash-Title[eu]=Kalkulagailua 2.0
3016+X-Ubuntu-Splash-Title[fa]= 2.0ماشین‌حساب
3017+X-Ubuntu-Splash-Title[fi]=Laskin 2.0
3018+X-Ubuntu-Splash-Title[fr]=Calculatrice 2.0
3019+X-Ubuntu-Splash-Title[gd]=An t-àireamhair 2.0
3020+X-Ubuntu-Splash-Title[gl]=Calculadora 2.0
3021+X-Ubuntu-Splash-Title[gu]=કેલ્ક્યુલેટર 2.0
3022+X-Ubuntu-Splash-Title[he]= 2.0מחשבון
3023+X-Ubuntu-Splash-Title[hi]=कैलकुलेटर 2.0
3024+X-Ubuntu-Splash-Title[hu]=Számológép 2.0
3025+X-Ubuntu-Splash-Title[id]=Kalkulator 2.0
3026+X-Ubuntu-Splash-Title[is]=Reiknivél 2.0
3027+X-Ubuntu-Splash-Title[it]=Calcolatrice 2.0
3028+X-Ubuntu-Splash-Title[ja]=電卓 2.0
3029+X-Ubuntu-Splash-Title[km]=ម៉ាស៊ីន​គិត​លេខ 2.0
3030+X-Ubuntu-Splash-Title[ko]=계산기 2.0
3031+X-Ubuntu-Splash-Title[lv]=Kalkulators 2.0
3032+X-Ubuntu-Splash-Title[mr]=गणनयंत्र 2.0
3033+X-Ubuntu-Splash-Title[ms]=Kalkulator 2.0
3034+X-Ubuntu-Splash-Title[my]=ဂဏန်းတွက်စက် 2.0
3035+X-Ubuntu-Splash-Title[nb]=Kalkulator 2.0
3036+X-Ubuntu-Splash-Title[ne]=क्याल्कुलेटर 2.0
3037+X-Ubuntu-Splash-Title[nl]=Rekenmachine 2.0
3038+X-Ubuntu-Splash-Title[pa]=ਕੈਲਕੂਲੇਟਰ 2.0
3039+X-Ubuntu-Splash-Title[pl]=Kalkulator 2.0
3040+X-Ubuntu-Splash-Title[pt]=Calculadora 2.0
3041+X-Ubuntu-Splash-Title[pt_BR]=Calculadora 2.0
3042+X-Ubuntu-Splash-Title[ro]=Calculator 2.0
3043+X-Ubuntu-Splash-Title[ru]=Калькулятор 2.0
3044+X-Ubuntu-Splash-Title[sa]=सङ्कलकम् 2.0
3045+X-Ubuntu-Splash-Title[shn]=ၸၢၵ်ႈၼပ့်သွၼ် 2.0
3046+X-Ubuntu-Splash-Title[sl]=Računalo 2.0
3047+X-Ubuntu-Splash-Title[sr]=Калкулатор 2.0
3048+X-Ubuntu-Splash-Title[sv]=Kalkylator 2.0
3049+X-Ubuntu-Splash-Title[ta]=கணிப்பான் 2.0
3050+X-Ubuntu-Splash-Title[te]=గణన పరికరం 2.0
3051+X-Ubuntu-Splash-Title[tr]=Hesap Makinesi 2.0
3052+X-Ubuntu-Splash-Title[ug]= 2.0ھېسابلىغۇچ
3053+X-Ubuntu-Splash-Title[uk]=Калькулятор 2.0
3054+X-Ubuntu-Splash-Title[zh_CN]=计算器 2.0
3055+X-Ubuntu-Splash-Title[zh_HK]=計數機 2.0
3056+X-Ubuntu-Splash-Title[zh_TW]=計算機 2.0
3057
3058=== added file 'tests/modules/DesktopFileReader/desktopfilereader_test.cpp'
3059--- tests/modules/DesktopFileReader/desktopfilereader_test.cpp 1970-01-01 00:00:00 +0000
3060+++ tests/modules/DesktopFileReader/desktopfilereader_test.cpp 2014-09-18 22:57:30 +0000
3061@@ -0,0 +1,128 @@
3062+/*
3063+ * Copyright (C) 2014 Canonical, Ltd.
3064+ *
3065+ * This program is free software: you can redistribute it and/or modify it under
3066+ * the terms of the GNU Lesser General Public License version 3, as published by
3067+ * the Free Software Foundation.
3068+ *
3069+ * This program is distributed in the hope that it will be useful, but WITHOUT
3070+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
3071+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3072+ * Lesser General Public License for more details.
3073+ *
3074+ * You should have received a copy of the GNU Lesser General Public License
3075+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3076+ *
3077+ */
3078+
3079+#include <Unity/Application/desktopfilereader.h>
3080+
3081+#include <gtest/gtest.h>
3082+
3083+#include <QDir>
3084+#include <QFileInfo>
3085+#include <QLocale>
3086+#include <QtGlobal>
3087+#include <QString>
3088+
3089+using namespace qtmir;
3090+
3091+namespace {
3092+ static void setLocale(const char *locale)
3093+ {
3094+ qputenv("LANGUAGE", locale);
3095+ qputenv("LC_ALL", locale); // set these for GIO
3096+ QLocale::setDefault(QString(locale)); // set for Qt
3097+ }
3098+}
3099+
3100+TEST(DesktopFileReader, testReadsDesktopFile)
3101+{
3102+ using namespace ::testing;
3103+ setLocale("C");
3104+
3105+ QFileInfo fileInfo(QDir::currentPath() + "/calculator.desktop");
3106+ DesktopFileReader::Factory readerFactory;
3107+ DesktopFileReader *reader = readerFactory.createInstance("calculator", fileInfo);
3108+
3109+ EXPECT_EQ(reader->loaded(), true);
3110+ EXPECT_EQ(reader->appId(), "calculator");
3111+ EXPECT_EQ(reader->name(), "Calculator");
3112+ EXPECT_EQ(reader->exec(), "aa-exec-click -p com.ubuntu.calculator_calculator_1.3.329 -- qmlscene -qt5 ubuntu-calculator-app.qml");
3113+ EXPECT_EQ(reader->icon(), "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator/calculator-app@30.png");
3114+ EXPECT_EQ(reader->path(), "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator");
3115+ EXPECT_EQ(reader->comment(), "A simple calculator for Ubuntu.");
3116+ EXPECT_EQ(reader->stageHint(), "SideStage");
3117+ EXPECT_EQ(reader->splashColor(), "#aabbcc");
3118+ EXPECT_EQ(reader->splashColorFooter(), "#deadbeefda");
3119+ EXPECT_EQ(reader->splashColorHeader(), "purple");
3120+ EXPECT_EQ(reader->splashImage(), "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator/calculator-app@30.png");
3121+ EXPECT_EQ(reader->splashShowHeader(), "True");
3122+ EXPECT_EQ(reader->splashTitle(), "Calculator 2.0");
3123+}
3124+
3125+TEST(DesktopFileReader, testReadsLocalizedDesktopFile)
3126+{
3127+ using namespace ::testing;
3128+ setLocale("de");
3129+
3130+ QFileInfo fileInfo(QDir::currentPath() + "/calculator.desktop");
3131+ DesktopFileReader::Factory readerFactory;
3132+ DesktopFileReader *reader = readerFactory.createInstance("calculator", fileInfo);
3133+
3134+ EXPECT_EQ(reader->loaded(), true);
3135+ EXPECT_EQ(reader->appId(), "calculator");
3136+ EXPECT_EQ(reader->name(), "Taschenrechner");
3137+ EXPECT_EQ(reader->exec(), "aa-exec-click -p com.ubuntu.calculator_calculator_1.3.329 -- qmlscene -qt5 ubuntu-calculator-app.qml");
3138+ EXPECT_EQ(reader->icon(), "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator/calculator-app@30.png");
3139+ EXPECT_EQ(reader->path(), "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator");
3140+ EXPECT_EQ(reader->comment(), "Ein einfach Tachenrechner für Ubuntu.");
3141+ EXPECT_EQ(reader->stageHint(), "SideStage");
3142+ EXPECT_EQ(reader->splashColor(), "#aabbcc");
3143+ EXPECT_EQ(reader->splashColorFooter(), "#deadbeefda");
3144+ EXPECT_EQ(reader->splashColorHeader(), "purple");
3145+ EXPECT_EQ(reader->splashImage(), "/usr/share/click/preinstalled/.click/users/@all/com.ubuntu.calculator/calculator-app@30.png");
3146+ EXPECT_EQ(reader->splashShowHeader(), "True");
3147+ EXPECT_EQ(reader->splashTitle(), "Taschenrechner 2.0");
3148+}
3149+
3150+TEST(DesktopFileReader, testMissingDesktopFile)
3151+{
3152+ using namespace ::testing;
3153+ setLocale("C");
3154+
3155+ QFileInfo fileInfo(QDir::currentPath() + "/missing.desktop");
3156+ DesktopFileReader::Factory readerFactory;
3157+ DesktopFileReader *reader = readerFactory.createInstance("calculator", fileInfo);
3158+
3159+ EXPECT_EQ(reader->loaded(), false);
3160+ EXPECT_EQ(reader->appId(), "calculator");
3161+ EXPECT_EQ(reader->name(), "");
3162+ EXPECT_EQ(reader->exec(), "");
3163+ EXPECT_EQ(reader->icon(), "");
3164+ EXPECT_EQ(reader->path(), "");
3165+ EXPECT_EQ(reader->comment(), "");
3166+ EXPECT_EQ(reader->stageHint(), "");
3167+ EXPECT_EQ(reader->splashColor(), "");
3168+ EXPECT_EQ(reader->splashColorFooter(), "");
3169+ EXPECT_EQ(reader->splashColorHeader(), "");
3170+ EXPECT_EQ(reader->splashImage(), "");
3171+ EXPECT_EQ(reader->splashShowHeader(), "");
3172+ EXPECT_EQ(reader->splashTitle(), "");
3173+}
3174+
3175+TEST(DesktopFileReader, testUTF8Characters)
3176+{
3177+ using namespace ::testing;
3178+ setLocale("zh_CN");
3179+
3180+ QFileInfo fileInfo(QDir::currentPath() + "/calculator.desktop");
3181+ DesktopFileReader::Factory readerFactory;
3182+ DesktopFileReader *reader = readerFactory.createInstance("calculator", fileInfo);
3183+
3184+ EXPECT_EQ(reader->loaded(), true);
3185+ EXPECT_EQ(reader->appId(), "calculator");
3186+ EXPECT_EQ(reader->name(), "计算器");
3187+ EXPECT_EQ(reader->comment(), "Ubuntu 简易计算器");
3188+ EXPECT_EQ(reader->splashTitle(), "计算器 2.0");
3189+}
3190
3191=== added directory 'tests/modules/MirSurfaceItem'
3192=== added file 'tests/modules/MirSurfaceItem/MirSurfaceItem.pro'
3193--- tests/modules/MirSurfaceItem/MirSurfaceItem.pro 1970-01-01 00:00:00 +0000
3194+++ tests/modules/MirSurfaceItem/MirSurfaceItem.pro 2014-09-18 22:57:30 +0000
3195@@ -0,0 +1,13 @@
3196+include(../../test-includes.pri)
3197+include(../common/common.pri)
3198+
3199+TARGET = mirsurfaceitem_test
3200+
3201+QT += testlib
3202+
3203+INCLUDEPATH += \
3204+ ../../../src/platforms/mirserver \
3205+ ../../../src/modules/Unity/Application
3206+
3207+SOURCES += \
3208+ mirsurfaceitem_test.cpp
3209
3210=== added file 'tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp'
3211--- tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp 1970-01-01 00:00:00 +0000
3212+++ tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp 2014-09-18 22:57:30 +0000
3213@@ -0,0 +1,113 @@
3214+/*
3215+ * Copyright (C) 2014 Canonical, Ltd.
3216+ *
3217+ * This program is free software: you can redistribute it and/or modify it under
3218+ * the terms of the GNU Lesser General Public License version 3, as published by
3219+ * the Free Software Foundation.
3220+ *
3221+ * This program is distributed in the hope that it will be useful, but WITHOUT
3222+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
3223+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3224+ * Lesser General Public License for more details.
3225+ *
3226+ * You should have received a copy of the GNU Lesser General Public License
3227+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3228+ *
3229+ */
3230+
3231+#include <gtest/gtest.h>
3232+
3233+#include <QLoggingCategory>
3234+#include <QTest>
3235+
3236+// the test subject
3237+#include <mirsurfaceitem.h>
3238+
3239+// mocks
3240+#include <mock_surface.h>
3241+#include <mock_session.h>
3242+
3243+using namespace qtmir;
3244+
3245+using mir::scene::MockSurface;
3246+using qtmir::MockSession;
3247+
3248+// gtest stuff
3249+using ::testing::_;
3250+using ::testing::AnyNumber;
3251+using ::testing::Invoke;
3252+using ::testing::InSequence;
3253+using ::testing::Return;
3254+
3255+/*
3256+ Tests that even if Qt fails to finish a touch sequence, MirSurfaceItem will
3257+ properly finish it when forwarding it to its mir::input::surface. So
3258+ mir::input::surface will still consume a proper sequence of touch events
3259+ (comprised of a begin, zero or more updates and an end).
3260+ */
3261+TEST(MirSurfaceItemTest, MissingTouchEnd)
3262+{
3263+ // We don't want the logging spam cluttering the test results
3264+ QLoggingCategory::setFilterRules(QStringLiteral("qtmir*=false"));
3265+
3266+ std::shared_ptr<MockSurface> mockSurface = std::make_shared<MockSurface>();
3267+ MockSession *mockSession = new MockSession;
3268+
3269+ // Set some expectations and behavior for calls we are not interested in
3270+ EXPECT_CALL(*mockSurface, add_observer(_)).Times(AnyNumber());
3271+ EXPECT_CALL(*mockSurface, remove_observer(_)).Times(AnyNumber());
3272+ EXPECT_CALL(*mockSurface, size()).Times(AnyNumber()).WillRepeatedly(Return(mir::geometry::Size(100,100)));
3273+ EXPECT_CALL(*mockSurface, type()).Times(AnyNumber()).WillRepeatedly(Return(mir_surface_type_normal));
3274+ EXPECT_CALL(*mockSession, setSurface(_)).Times(AnyNumber());
3275+
3276+ // The touch event sequence we expect mir::input::surface to receive from MirSurfaceItem.
3277+ // It should properly finish the sequence for touch 0 ('down', 'move' and 'up') before starting
3278+ // the sequence for touch 1.
3279+ EXPECT_CALL(*mockSurface, consume(_))
3280+ .WillOnce(Invoke([] (MirEvent const& mirEvent) {
3281+ ASSERT_EQ(mir_motion_action_down, mirEvent.motion.action);
3282+ ASSERT_EQ(1, mirEvent.motion.pointer_count);
3283+ ASSERT_EQ(0, mirEvent.motion.pointer_coordinates[0].id);
3284+ }))
3285+ .WillOnce(Invoke([] (MirEvent const& mirEvent) {
3286+ ASSERT_EQ(mir_motion_action_move, mirEvent.motion.action);
3287+ ASSERT_EQ(1, mirEvent.motion.pointer_count);
3288+ ASSERT_EQ(0, mirEvent.motion.pointer_coordinates[0].id);
3289+ }))
3290+ .WillOnce(Invoke([] (MirEvent const& mirEvent) {
3291+ ASSERT_EQ(mir_motion_action_up, mirEvent.motion.action);
3292+ ASSERT_EQ(1, mirEvent.motion.pointer_count);
3293+ ASSERT_EQ(0, mirEvent.motion.pointer_coordinates[0].id);
3294+ }))
3295+ .WillOnce(Invoke([] (MirEvent const& mirEvent) {
3296+ ASSERT_EQ(mir_motion_action_down, mirEvent.motion.action);
3297+ ASSERT_EQ(1, mirEvent.motion.pointer_count);
3298+ ASSERT_EQ(1, mirEvent.motion.pointer_coordinates[0].id);
3299+ }));
3300+
3301+
3302+ MirSurfaceItem *surfaceItem = new MirSurfaceItem(mockSurface, mockSession);
3303+
3304+ ulong timestamp = 1234;
3305+ QList<QTouchEvent::TouchPoint> touchPoints;
3306+ touchPoints.append(QTouchEvent::TouchPoint());
3307+
3308+ touchPoints[0].setId(0);
3309+ touchPoints[0].setState(Qt::TouchPointPressed);
3310+ surfaceItem->processTouchEvent(QEvent::TouchBegin,
3311+ timestamp, touchPoints, touchPoints[0].state());
3312+
3313+ touchPoints[0].setState(Qt::TouchPointMoved);
3314+ surfaceItem->processTouchEvent(QEvent::TouchUpdate,
3315+ timestamp + 10, touchPoints, touchPoints[0].state());
3316+
3317+ // Starting a new touch sequence (with touch 1) without ending the current one
3318+ // (wich has touch 0).
3319+ touchPoints[0].setId(1);
3320+ touchPoints[0].setState(Qt::TouchPointPressed);
3321+ surfaceItem->processTouchEvent(QEvent::TouchBegin,
3322+ timestamp + 20, touchPoints, touchPoints[0].state());
3323+
3324+ delete surfaceItem;
3325+ delete mockSession;
3326+}
3327
3328=== modified file 'tests/modules/SessionManager/session_manager_test.cpp'
3329--- tests/modules/SessionManager/session_manager_test.cpp 2014-08-29 14:58:07 +0000
3330+++ tests/modules/SessionManager/session_manager_test.cpp 2014-09-18 22:57:30 +0000
3331@@ -24,6 +24,7 @@
3332 #include "qtmir_test.h"
3333
3334 using namespace qtmir;
3335+using mir::scene::MockSession;
3336
3337 namespace ms = mir::scene;
3338
3339@@ -33,7 +34,7 @@
3340 SessionManagerTests()
3341 {}
3342
3343- QList<std::shared_ptr<ms::PromptSession>> listPromptSessions(Session* session) {
3344+ QList<std::shared_ptr<ms::PromptSession>> listPromptSessions(SessionInterface* session) {
3345 QList<std::shared_ptr<ms::PromptSession>> promptSessions;
3346 session->foreachPromptSession([&promptSessions](const std::shared_ptr<ms::PromptSession>& promptSession) {
3347 promptSessions << promptSession;
3348@@ -41,9 +42,9 @@
3349 return promptSessions;
3350 }
3351
3352- QList<Session*> listChildSessions(Session* session) {
3353- QList<Session*> sessions;
3354- session->foreachChildSession([&sessions](Session* session) {
3355+ QList<SessionInterface*> listChildSessions(SessionInterface* session) {
3356+ QList<SessionInterface*> sessions;
3357+ session->foreachChildSession([&sessions](SessionInterface* session) {
3358 sessions << session;
3359 });
3360 return sessions;
3361@@ -56,10 +57,10 @@
3362
3363 std::shared_ptr<ms::Session> mirAppSession = std::make_shared<MockSession>("mirAppSession", __LINE__);
3364 sessionManager.onSessionStarting(mirAppSession);
3365- Session* qtmirAppSession = sessionManager.findSession(mirAppSession.get());
3366+ SessionInterface* qtmirAppSession = sessionManager.findSession(mirAppSession.get());
3367 EXPECT_TRUE(qtmirAppSession != nullptr);
3368
3369- auto promptSession = std::make_shared<MockPromptSession>();
3370+ auto promptSession = std::make_shared<ms::MockPromptSession>();
3371 ON_CALL(*mirConfig->the_mock_prompt_session_manager(), application_for(_)).WillByDefault(Return(mirAppSession));
3372
3373 sessionManager.onPromptSessionStarting(promptSession);
3374@@ -80,18 +81,18 @@
3375
3376 std::shared_ptr<ms::Session> mirAppSession = std::make_shared<MockSession>("mirAppSession", __LINE__);
3377 sessionManager.onSessionStarting(mirAppSession);
3378- Session* qtmirAppSession = sessionManager.findSession(mirAppSession.get());
3379+ SessionInterface* qtmirAppSession = sessionManager.findSession(mirAppSession.get());
3380 EXPECT_TRUE(qtmirAppSession != nullptr);
3381
3382 EXPECT_CALL(*mirConfig->the_mock_prompt_session_manager(), application_for(_)).WillRepeatedly(Return(mirAppSession));
3383 EXPECT_CALL(*mirConfig->the_mock_prompt_session_manager(), helper_for(_)).WillRepeatedly(Return(nullptr));
3384
3385- std::shared_ptr<ms::PromptSession> mirPromptSession = std::make_shared<MockPromptSession>();
3386+ std::shared_ptr<ms::PromptSession> mirPromptSession = std::make_shared<ms::MockPromptSession>();
3387
3388 // prompt provider session
3389 std::shared_ptr<ms::Session> mirProviderSession = std::make_shared<MockSession>("mirProviderSession", __LINE__);
3390 sessionManager.onSessionStarting(mirProviderSession);
3391- Session* qtmirProviderSession = sessionManager.findSession(mirProviderSession.get());
3392+ SessionInterface* qtmirProviderSession = sessionManager.findSession(mirProviderSession.get());
3393
3394 EXPECT_CALL(*mirConfig->the_mock_prompt_session_manager(), for_each_provider_in(mirPromptSession,_)).WillRepeatedly(WithArgs<1>(Invoke(
3395 [&](std::function<void(std::shared_ptr<ms::Session> const& prompt_provider)> const& f) {
3396
3397=== modified file 'tests/modules/SessionManager/session_test.cpp'
3398--- tests/modules/SessionManager/session_test.cpp 2014-08-28 23:36:42 +0000
3399+++ tests/modules/SessionManager/session_test.cpp 2014-09-18 22:57:30 +0000
3400@@ -22,6 +22,8 @@
3401 #include "stub_scene_surface.h"
3402
3403 using namespace qtmir;
3404+using mir::scene::MockSession;
3405+
3406
3407 namespace ms = mir::scene;
3408 namespace mtd = mir::test::doubles;
3409@@ -32,9 +34,9 @@
3410 SessionTests()
3411 {}
3412
3413- QList<Session*> listChildSessions(Session* session) {
3414- QList<Session*> sessions;
3415- session->foreachChildSession([&sessions](Session* session) {
3416+ QList<SessionInterface*> listChildSessions(Session* session) {
3417+ QList<SessionInterface*> sessions;
3418+ session->foreachChildSession([&sessions](SessionInterface* session) {
3419 sessions << session;
3420 });
3421 return sessions;
3422@@ -151,17 +153,14 @@
3423
3424 // delete surfaces
3425 delete session2;
3426- EXPECT_EQ(session2->parentSession(), nullptr);
3427 EXPECT_THAT(listChildSessions(&session), ElementsAre(session1, session3));
3428
3429 // delete surfaces
3430 delete session3;
3431- EXPECT_EQ(session3->parentSession(), nullptr);
3432 EXPECT_THAT(listChildSessions(&session), ElementsAre(session1));
3433
3434 // delete surfaces
3435 delete session1;
3436- EXPECT_EQ(session1->parentSession(), nullptr);
3437 EXPECT_THAT(listChildSessions(&session), IsEmpty());
3438 }
3439
3440
3441=== modified file 'tests/modules/common/common.pri'
3442--- tests/modules/common/common.pri 2014-08-26 14:55:03 +0000
3443+++ tests/modules/common/common.pri 2014-09-18 22:57:30 +0000
3444@@ -1,12 +1,12 @@
3445-CONFIG += link_pkgconfig no_keywords # keywords clash with ProcessC++
3446-PKGCONFIG += mirserver process-cpp ubuntu-app-launch-2
3447+CONFIG += no_keywords # keywords clash with ProcessC++
3448+PKGCONFIG += process-cpp ubuntu-app-launch-2
3449
3450-QT += quick testlib
3451-QMAKE_CXXFLAGS = -std=c++11
3452+QT += quick
3453
3454 HEADERS += ../common/mock_application_controller.h \
3455 ../common/mock_desktop_file_reader.h \
3456 ../common/mock_focus_controller.h \
3457+ ../common/mock_mir_session.h \
3458 ../common/mock_oom_controller.h \
3459 ../common/mock_process_controller.h \
3460 ../common/mock_proc_info.h \
3461@@ -22,31 +22,7 @@
3462 INCLUDEPATH += ../../../src/modules \
3463 ../common
3464
3465-
3466-GMOCK_SOURCES = /usr/src/gmock/src/gmock-all.cc \
3467- /usr/src/gmock/src/gmock_main.cc \
3468- /usr/src/gtest/src/gtest-all.cc
3469-
3470-QMAKE_EXTRA_COMPILERS += gmock_compiler
3471-gmock_compiler.input = GMOCK_SOURCES
3472-gmock_compiler.output = $${OUT_PWD}/${QMAKE_FILE_BASE}.o
3473-gmock_compiler.commands = g++ \
3474- -I/usr/src/gtest \
3475- -I/usr/src/gmock \
3476- -c ${QMAKE_FILE_IN} \
3477- -o ${QMAKE_FILE_OUT}
3478-gmock_compiler.CONFIG = no_link
3479-
3480-QMAKE_EXTRA_COMPILERS += gmock_linker
3481-gmock_linker.depends = $${OUT_PWD}/gmock-all.o \
3482- $${OUT_PWD}/gmock_main.o \
3483- $${OUT_PWD}/gtest-all.o
3484-gmock_linker.input = GMOCK_SOURCES
3485-gmock_linker.output = $${OUT_PWD}/libgmock.a
3486-gmock_linker.commands = ar -rv ${QMAKE_FILE_OUT} $${OUT_PWD}/gmock-all.o $${OUT_PWD}/gmock_main.o $${OUT_PWD}/gtest-all.o
3487-gmock_linker.CONFIG = combine explicit_dependencies no_link target_predeps
3488-
3489-LIBS += $${OUT_PWD}/libgmock.a \
3490+LIBS += \
3491 -Wl,-rpath,$${OUT_PWD}/../../../src/modules/Unity/Application \
3492 -L$${OUT_PWD}/../../../src/modules/Unity/Application -lunityapplicationplugin \
3493 -Wl,-rpath,$${OUT_PWD}/../../../src/platforms/mirserver \
3494
3495=== modified file 'tests/modules/common/mock_focus_controller.h'
3496--- tests/modules/common/mock_focus_controller.h 2014-07-01 13:38:06 +0000
3497+++ tests/modules/common/mock_focus_controller.h 2014-09-18 22:57:30 +0000
3498@@ -23,15 +23,18 @@
3499
3500 #include <string>
3501
3502-namespace testing
3503-{
3504-class MockFocusController : public mir::shell::FocusController
3505+namespace mir {
3506+namespace shell {
3507+
3508+class MockFocusController : public FocusController
3509 {
3510 public:
3511 MOCK_METHOD0(focus_next, void());
3512- MOCK_CONST_METHOD0(focussed_application, std::weak_ptr<mir::scene::Session>());
3513- MOCK_METHOD1(set_focus_to, void(std::shared_ptr<mir::scene::Session>const&));
3514+ MOCK_CONST_METHOD0(focussed_application, std::weak_ptr<scene::Session>());
3515+ MOCK_METHOD1(set_focus_to, void(std::shared_ptr<scene::Session>const&));
3516 };
3517-}
3518+
3519+} // namespace shell
3520+} // namespace mir
3521
3522 #endif // MOCK_MIR_SHELL_FOCUS_CONTROLLER_H_
3523
3524=== renamed file 'tests/modules/common/mock_session.h' => 'tests/modules/common/mock_mir_session.h'
3525--- tests/modules/common/mock_session.h 2014-07-01 13:38:06 +0000
3526+++ tests/modules/common/mock_mir_session.h 2014-09-18 22:57:30 +0000
3527@@ -25,9 +25,10 @@
3528
3529 #include <string>
3530
3531-namespace testing
3532-{
3533-struct MockSession : public mir::scene::Session
3534+namespace mir {
3535+namespace scene {
3536+
3537+struct MockSession : public Session
3538 {
3539 MockSession() {}
3540 MockSession(std::string const& sessionName, pid_t processId)
3541@@ -44,22 +45,20 @@
3542 return m_sessionId;
3543 }
3544
3545- typedef mir::frontend::SurfaceId SurfaceId;
3546-
3547 MOCK_METHOD0(force_requests_to_complete, void());
3548
3549- MOCK_CONST_METHOD0(default_surface, std::shared_ptr<mir::scene::Surface>());
3550- MOCK_CONST_METHOD1(get_surface, std::shared_ptr<mir::frontend::Surface>(SurfaceId));
3551+ MOCK_CONST_METHOD0(default_surface, std::shared_ptr<Surface>());
3552+ MOCK_CONST_METHOD1(get_surface, std::shared_ptr<frontend::Surface>(frontend::SurfaceId));
3553
3554- MOCK_METHOD1(take_snapshot, void(mir::scene::SnapshotCallback const&));
3555+ MOCK_METHOD1(take_snapshot, void(SnapshotCallback const&));
3556 MOCK_METHOD1(set_lifecycle_state, void(MirLifecycleState));
3557- MOCK_METHOD1(create_surface, SurfaceId(mir::scene::SurfaceCreationParameters const&));
3558- MOCK_METHOD1(destroy_surface, void (SurfaceId));
3559+ MOCK_METHOD1(create_surface, frontend::SurfaceId(SurfaceCreationParameters const&));
3560+ MOCK_METHOD1(destroy_surface, void (frontend::SurfaceId));
3561
3562 MOCK_METHOD0(hide, void());
3563 MOCK_METHOD0(show, void());
3564- MOCK_METHOD1(send_display_config, void(mir::graphics::DisplayConfiguration const&));
3565- MOCK_METHOD3(configure_surface, int(SurfaceId, MirSurfaceAttrib, int));
3566+ MOCK_METHOD1(send_display_config, void(graphics::DisplayConfiguration const&));
3567+ MOCK_METHOD3(configure_surface, int(frontend::SurfaceId, MirSurfaceAttrib, int));
3568
3569 void start_prompt_session() override {};
3570 void stop_prompt_session() override {};
3571@@ -68,6 +67,8 @@
3572 std::string m_sessionName;
3573 pid_t m_sessionId;
3574 };
3575-}
3576+
3577+} // namespace scene
3578+} // namespace mir
3579
3580 #endif // MOCK_MIR_SCENE_SESSION_H
3581
3582=== modified file 'tests/modules/common/mock_prompt_session.h'
3583--- tests/modules/common/mock_prompt_session.h 2014-07-21 15:51:17 +0000
3584+++ tests/modules/common/mock_prompt_session.h 2014-09-18 22:57:30 +0000
3585@@ -21,11 +21,14 @@
3586 #include <mir/scene/prompt_session.h>
3587 #include <gmock/gmock.h>
3588
3589-namespace testing
3590-{
3591-struct MockPromptSession : public mir::scene::PromptSession
3592+namespace mir {
3593+namespace scene {
3594+
3595+struct MockPromptSession : public PromptSession
3596 {
3597 };
3598-}
3599+
3600+} // namespace scene
3601+} // namespace mir
3602
3603 #endif // MOCK_MIR_PROMPT_SESSION_H
3604
3605=== modified file 'tests/modules/common/mock_prompt_session_manager.h'
3606--- tests/modules/common/mock_prompt_session_manager.h 2014-07-21 15:51:17 +0000
3607+++ tests/modules/common/mock_prompt_session_manager.h 2014-09-18 22:57:30 +0000
3608@@ -23,33 +23,36 @@
3609
3610 #include <gmock/gmock.h>
3611
3612-namespace testing
3613-{
3614-class MockPromptSessionManager: public mir::scene::PromptSessionManager
3615+namespace mir {
3616+namespace scene {
3617+
3618+class MockPromptSessionManager: public PromptSessionManager
3619 {
3620 public:
3621- MOCK_CONST_METHOD2(start_prompt_session_for, std::shared_ptr<mir::scene::PromptSession>(std::shared_ptr<mir::scene::Session> const&,
3622+ MOCK_CONST_METHOD2(start_prompt_session_for, std::shared_ptr<PromptSession>(std::shared_ptr<mir::scene::Session> const&,
3623 mir::scene::PromptSessionCreationParameters const&));
3624
3625- MOCK_CONST_METHOD1(stop_prompt_session, void(std::shared_ptr<mir::scene::PromptSession> const&));
3626+ MOCK_CONST_METHOD1(stop_prompt_session, void(std::shared_ptr<PromptSession> const&));
3627
3628- MOCK_CONST_METHOD2(add_prompt_provider, void(std::shared_ptr<mir::scene::PromptSession> const&,
3629+ MOCK_CONST_METHOD2(add_prompt_provider, void(std::shared_ptr<PromptSession> const&,
3630 std::shared_ptr<mir::scene::Session> const&));
3631
3632- MOCK_CONST_METHOD2(add_prompt_provider_by_pid, void(std::shared_ptr<mir::scene::PromptSession> const&,
3633+ MOCK_CONST_METHOD2(add_prompt_provider_by_pid, void(std::shared_ptr<PromptSession> const&,
3634 pid_t));
3635
3636- MOCK_CONST_METHOD1(add_expected_session, void(std::shared_ptr<mir::scene::Session> const&));
3637-
3638- MOCK_CONST_METHOD1(remove_session, void(std::shared_ptr<mir::scene::Session> const&));
3639-
3640- MOCK_CONST_METHOD1(application_for, std::shared_ptr<mir::scene::Session>(std::shared_ptr<mir::scene::PromptSession> const&));
3641-
3642- MOCK_CONST_METHOD1(helper_for, std::shared_ptr<mir::scene::Session>(std::shared_ptr<mir::scene::PromptSession> const&));
3643-
3644- MOCK_CONST_METHOD2(for_each_provider_in, void(std::shared_ptr<mir::scene::PromptSession> const&,
3645- std::function<void(std::shared_ptr<mir::scene::Session> const&)> const&));
3646+ MOCK_CONST_METHOD1(add_expected_session, void(std::shared_ptr<Session> const&));
3647+
3648+ MOCK_CONST_METHOD1(remove_session, void(std::shared_ptr<Session> const&));
3649+
3650+ MOCK_CONST_METHOD1(application_for, std::shared_ptr<Session>(std::shared_ptr<PromptSession> const&));
3651+
3652+ MOCK_CONST_METHOD1(helper_for, std::shared_ptr<Session>(std::shared_ptr<PromptSession> const&));
3653+
3654+ MOCK_CONST_METHOD2(for_each_provider_in, void(std::shared_ptr<PromptSession> const&,
3655+ std::function<void(std::shared_ptr<Session> const&)> const&));
3656 };
3657-} // namespace testing
3658+
3659+} // namespace scene
3660+} // namespace mir
3661
3662 #endif // MOCK_MIR_SCENE_PROMPT_SESSION_MANAGER_H_
3663
3664=== modified file 'tests/modules/common/mock_renderable.h'
3665--- tests/modules/common/mock_renderable.h 2014-08-14 15:38:15 +0000
3666+++ tests/modules/common/mock_renderable.h 2014-09-18 22:57:30 +0000
3667@@ -21,23 +21,26 @@
3668 #include <mir/graphics/renderable.h>
3669 #include <gmock/gmock.h>
3670
3671-namespace testing
3672-{
3673-struct MockRenderable : public mir::graphics::Renderable
3674+namespace mir {
3675+namespace graphics {
3676+
3677+struct MockRenderable : public Renderable
3678 {
3679 MockRenderable() {};
3680
3681 MOCK_CONST_METHOD0(id, ID());
3682- MOCK_CONST_METHOD0(buffer, std::shared_ptr<mir::graphics::Buffer>());
3683+ MOCK_CONST_METHOD0(buffer, std::shared_ptr<Buffer>());
3684 MOCK_CONST_METHOD0(alpha_enabled, bool());
3685- MOCK_CONST_METHOD0(screen_position, mir::geometry::Rectangle());
3686+ MOCK_CONST_METHOD0(screen_position, geometry::Rectangle());
3687 MOCK_CONST_METHOD0(alpha, float() );
3688 MOCK_CONST_METHOD0(transformation, glm::mat4());
3689 MOCK_CONST_METHOD0(visible, bool());
3690 MOCK_CONST_METHOD0(shaped, bool());
3691 MOCK_CONST_METHOD0(buffers_ready_for_compositor, int());
3692 };
3693-}
3694+
3695+} // namespace graphics
3696+} // namespace mir
3697
3698 #endif // MOCK_MIR_GRAPHICS_RENDERABLE_H
3699
3700
3701=== added file 'tests/modules/common/mock_session.h'
3702--- tests/modules/common/mock_session.h 1970-01-01 00:00:00 +0000
3703+++ tests/modules/common/mock_session.h 2014-09-18 22:57:30 +0000
3704@@ -0,0 +1,65 @@
3705+/*
3706+ * Copyright (C) 2014 Canonical, Ltd.
3707+ *
3708+ * This program is free software: you can redistribute it and/or modify it under
3709+ * the terms of the GNU Lesser General Public License version 3, as published by
3710+ * the Free Software Foundation.
3711+ *
3712+ * This program is distributed in the hope that it will be useful, but WITHOUT
3713+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
3714+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3715+ * Lesser General Public License for more details.
3716+ *
3717+ * You should have received a copy of the GNU Lesser General Public License
3718+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3719+ *
3720+ */
3721+
3722+#ifndef MOCK_QTMIR_SESSION_H
3723+#define MOCK_QTMIR_SESSION_H
3724+
3725+#include <session_interface.h>
3726+#include <gmock/gmock.h>
3727+
3728+namespace qtmir {
3729+
3730+class MockSession : public SessionInterface {
3731+public:
3732+ MockSession() : SessionInterface(0) {}
3733+
3734+ MOCK_METHOD0(release, void());
3735+
3736+ MOCK_CONST_METHOD0(name, QString());
3737+ MOCK_CONST_METHOD0(application, unity::shell::application::ApplicationInfoInterface*());
3738+ MOCK_CONST_METHOD0(surface, MirSurfaceItem*());
3739+ MOCK_CONST_METHOD0(parentSession, SessionInterface*());
3740+ MOCK_CONST_METHOD0(state, State());
3741+ MOCK_CONST_METHOD0(fullscreen, bool());
3742+ MOCK_CONST_METHOD0(live, bool());
3743+
3744+ MOCK_METHOD1(setApplication, void(unity::shell::application::ApplicationInfoInterface* item));
3745+ MOCK_METHOD1(setSurface, void(MirSurfaceItem* surface));
3746+ MOCK_METHOD1(setState, void(State state));
3747+
3748+ MOCK_METHOD1(addChildSession, void(SessionInterface* session));
3749+ MOCK_METHOD2(insertChildSession, void(uint index, SessionInterface* session));
3750+ MOCK_METHOD1(removeChildSession, void(SessionInterface* session));
3751+ MOCK_CONST_METHOD1(foreachChildSession, void(std::function<void(SessionInterface* session)> f));
3752+
3753+ MOCK_CONST_METHOD0(session, std::shared_ptr<mir::scene::Session>());
3754+
3755+ MOCK_CONST_METHOD0(activePromptSession, std::shared_ptr<mir::scene::PromptSession>());
3756+ MOCK_CONST_METHOD1(foreachPromptSession, void(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)> f));
3757+
3758+ MOCK_CONST_METHOD0(childSessions, SessionModel*());
3759+
3760+protected:
3761+ MOCK_METHOD1(setFullscreen, void(bool fullscreen));
3762+ MOCK_METHOD1(setLive, void(const bool));
3763+ MOCK_METHOD1(appendPromptSession, void(const std::shared_ptr<mir::scene::PromptSession>& session));
3764+ MOCK_METHOD1(removePromptSession, void(const std::shared_ptr<mir::scene::PromptSession>& session));
3765+};
3766+
3767+} // namespace qtmir
3768+
3769+#endif // MOCK_QTMIR_SESSION_H
3770
3771=== modified file 'tests/modules/common/mock_surface.h'
3772--- tests/modules/common/mock_surface.h 2014-08-18 19:40:31 +0000
3773+++ tests/modules/common/mock_surface.h 2014-09-18 22:57:30 +0000
3774@@ -24,22 +24,22 @@
3775 #include <string>
3776 #include "mock_renderable.h"
3777
3778-namespace testing
3779-{
3780+namespace mir {
3781+namespace scene {
3782
3783 struct MockSurface : public mir::scene::Surface
3784 {
3785 MockSurface() {}
3786
3787 MOCK_CONST_METHOD0(name, std::string());
3788- MOCK_CONST_METHOD0(client_size, mir::geometry::Size());
3789- MOCK_CONST_METHOD0(input_bounds, mir::geometry::Rectangle());
3790- MOCK_CONST_METHOD0(top_left, mir::geometry::Point());
3791- MOCK_CONST_METHOD0(size, mir::geometry::Size());
3792+ MOCK_CONST_METHOD0(client_size, geometry::Size());
3793+ MOCK_CONST_METHOD0(input_bounds, geometry::Rectangle());
3794+ MOCK_CONST_METHOD0(top_left, geometry::Point());
3795+ MOCK_CONST_METHOD0(size, geometry::Size());
3796
3797- std::unique_ptr<mir::graphics::Renderable> compositor_snapshot(void const* /*compositor_id*/) const
3798+ std::unique_ptr<graphics::Renderable> compositor_snapshot(void const* /*compositor_id*/) const
3799 {
3800- return std::unique_ptr<mir::graphics::Renderable>(new MockRenderable);
3801+ return std::unique_ptr<graphics::Renderable>(new graphics::MockRenderable);
3802 }
3803
3804 MOCK_CONST_METHOD0(alpha, float());
3805@@ -47,39 +47,40 @@
3806 MOCK_CONST_METHOD0(state, MirSurfaceState());
3807 MOCK_METHOD0(hide, void());
3808 MOCK_METHOD0(show, void());
3809- MOCK_METHOD1(move_to, void(mir::geometry::Point const& top_left));
3810- MOCK_METHOD1(take_input_focus, void(std::shared_ptr<mir::shell::InputTargeter> const& targeter));
3811- MOCK_METHOD1(set_input_region, void(std::vector<mir::geometry::Rectangle> const& region));
3812+ MOCK_METHOD1(move_to, void(geometry::Point const& top_left));
3813+ MOCK_METHOD1(take_input_focus, void(std::shared_ptr<shell::InputTargeter> const& targeter));
3814+ MOCK_METHOD1(set_input_region, void(std::vector<geometry::Rectangle> const& region));
3815 MOCK_METHOD1(allow_framedropping, void(bool));
3816- MOCK_METHOD1(resize, void(mir::geometry::Size const& size));
3817+ MOCK_METHOD1(resize, void(geometry::Size const& size));
3818 MOCK_METHOD1(set_transformation, void(glm::mat4 const& t));
3819 MOCK_METHOD1(set_alpha, void(float alpha));
3820 MOCK_METHOD1(set_orientation, void(MirOrientation orientation));
3821 MOCK_METHOD0(force_requests_to_complete, void());
3822- MOCK_METHOD1(set_cursor_image, void(std::shared_ptr<mir::graphics::CursorImage> const& image));
3823- MOCK_CONST_METHOD0(cursor_image, std::shared_ptr<mir::graphics::CursorImage>());
3824- MOCK_METHOD1(add_observer, void(std::shared_ptr<mir::scene::SurfaceObserver> const& observer));
3825- MOCK_METHOD1(remove_observer, void(std::weak_ptr<mir::scene::SurfaceObserver> const& observer));
3826- MOCK_CONST_METHOD0(input_channel, std::shared_ptr<mir::input::InputChannel>());
3827- MOCK_METHOD1(set_reception_mode, void(mir::input::InputReceptionMode mode));
3828+ MOCK_METHOD1(set_cursor_image, void(std::shared_ptr<graphics::CursorImage> const& image));
3829+ MOCK_CONST_METHOD0(cursor_image, std::shared_ptr<graphics::CursorImage>());
3830+ MOCK_METHOD1(add_observer, void(std::shared_ptr<SurfaceObserver> const& observer));
3831+ MOCK_METHOD1(remove_observer, void(std::weak_ptr<SurfaceObserver> const& observer));
3832+ MOCK_CONST_METHOD0(input_channel, std::shared_ptr<input::InputChannel>());
3833+ MOCK_METHOD1(set_reception_mode, void(input::InputReceptionMode mode));
3834
3835 // from mir::input::surface
3836- MOCK_CONST_METHOD1(input_area_contains, bool(mir::geometry::Point const& point));
3837- MOCK_CONST_METHOD0(reception_mode, mir::input::InputReceptionMode());
3838+ MOCK_CONST_METHOD1(input_area_contains, bool(geometry::Point const& point));
3839+ MOCK_CONST_METHOD0(reception_mode, input::InputReceptionMode());
3840 MOCK_METHOD1(consume, void(MirEvent const& event));
3841
3842 // from mir::frontend::surface
3843 MOCK_CONST_METHOD0(pixel_format, MirPixelFormat());
3844- MOCK_METHOD2(swap_buffers, void(mir::graphics::Buffer* old_buffer, std::function<void(mir::graphics::Buffer* new_buffer)> complete));
3845+ MOCK_METHOD2(swap_buffers, void(graphics::Buffer* old_buffer, std::function<void(graphics::Buffer* new_buffer)> complete));
3846 MOCK_CONST_METHOD0(supports_input, bool());
3847 MOCK_CONST_METHOD0(client_input_fd, int());
3848 MOCK_METHOD2(configure, int(MirSurfaceAttrib attrib, int value));
3849 MOCK_METHOD1(query, int(MirSurfaceAttrib attrib));
3850
3851 // from mir::scene::SurfaceBufferAccess
3852- MOCK_METHOD1(with_most_recent_buffer_do, void(std::function<void(mir::graphics::Buffer&)> const& exec));
3853+ MOCK_METHOD1(with_most_recent_buffer_do, void(std::function<void(graphics::Buffer&)> const& exec));
3854 };
3855
3856-}
3857+} // namespace scene
3858+} // namespace mir
3859
3860 #endif // MOCK_MIR_SCENE_SURFACE_H
3861
3862=== modified file 'tests/modules/common/qtmir_test.h'
3863--- tests/modules/common/qtmir_test.h 2014-08-28 23:36:42 +0000
3864+++ tests/modules/common/qtmir_test.h 2014-09-18 22:57:30 +0000
3865@@ -35,7 +35,7 @@
3866 #include "mock_oom_controller.h"
3867 #include "mock_process_controller.h"
3868 #include "mock_proc_info.h"
3869-#include "mock_session.h"
3870+#include "mock_mir_session.h"
3871 #include "mock_focus_controller.h"
3872 #include "mock_prompt_session_manager.h"
3873 #include "mock_prompt_session.h"
3874@@ -43,14 +43,13 @@
3875 namespace ms = mir::scene;
3876 using namespace qtmir;
3877
3878-namespace testing
3879-{
3880+namespace qtmir {
3881
3882-class QtMirTestConfiguration: public MirServerConfiguration
3883+class FakeMirServerConfiguration: public MirServerConfiguration
3884 {
3885- typedef NiceMock<testing::MockPromptSessionManager> StubPromptSessionManager;
3886+ typedef testing::NiceMock<mir::scene::MockPromptSessionManager> StubPromptSessionManager;
3887 public:
3888- QtMirTestConfiguration()
3889+ FakeMirServerConfiguration()
3890 : MirServerConfiguration(0, nullptr)
3891 , mock_prompt_session_manager(std::make_shared<StubPromptSessionManager>())
3892 {
3893@@ -73,6 +72,10 @@
3894 std::shared_ptr<StubPromptSessionManager> mock_prompt_session_manager;
3895 };
3896
3897+} // namespace qtmir
3898+
3899+namespace testing {
3900+
3901 class QtMirTest : public ::testing::Test
3902 {
3903 public:
3904@@ -83,7 +86,7 @@
3905 [](ProcessController::OomController*){})
3906 }
3907 , mirConfig{
3908- QSharedPointer<QtMirTestConfiguration> (new QtMirTestConfiguration)
3909+ QSharedPointer<FakeMirServerConfiguration> (new FakeMirServerConfiguration)
3910 }
3911 , taskController{
3912 QSharedPointer<TaskController> (
3913@@ -141,7 +144,7 @@
3914 applicationManager.authorizeSession(procId, authed);
3915 EXPECT_EQ(authed, true);
3916
3917- auto appSession = std::make_shared<MockSession>(appId.toStdString(), procId);
3918+ auto appSession = std::make_shared<mir::scene::MockSession>(appId.toStdString(), procId);
3919 sessionManager.onSessionStarting(appSession);
3920 return application;
3921 return nullptr;
3922@@ -152,7 +155,7 @@
3923 testing::NiceMock<testing::MockApplicationController> appController;
3924 testing::NiceMock<testing::MockProcInfo> procInfo;
3925 testing::NiceMock<testing::MockDesktopFileReaderFactory> desktopFileReaderFactory;
3926- QSharedPointer<QtMirTestConfiguration> mirConfig;
3927+ QSharedPointer<FakeMirServerConfiguration> mirConfig;
3928 QSharedPointer<TaskController> taskController;
3929 ApplicationManager applicationManager;
3930 SessionManager sessionManager;
3931
3932=== modified file 'tests/modules/modules.pro'
3933--- tests/modules/modules.pro 2014-08-28 23:36:42 +0000
3934+++ tests/modules/modules.pro 2014-09-18 22:57:30 +0000
3935@@ -1,2 +1,2 @@
3936 TEMPLATE = subdirs
3937-SUBDIRS = ApplicationManager General SessionManager TaskController
3938+SUBDIRS = ApplicationManager General MirSurfaceItem SessionManager TaskController DesktopFileReader
3939
3940=== modified file 'tests/test-includes.pri'
3941--- tests/test-includes.pri 2014-07-07 19:33:56 +0000
3942+++ tests/test-includes.pri 2014-09-18 22:57:30 +0000
3943@@ -4,3 +4,12 @@
3944 # adds a 'make install' that installs the test cases, which we do not want.
3945 # Can configure it not to do that with 'no_testcase_installs'
3946 CONFIG += testcase no_testcase_installs
3947+
3948+QMAKE_CXXFLAGS = -std=c++11
3949+
3950+QT += testlib
3951+
3952+CONFIG += link_pkgconfig
3953+PKGCONFIG += mirserver
3954+
3955+include(google-mock.pri)
3956
3957=== modified file 'tests/tests.pro'
3958--- tests/tests.pro 2014-08-28 23:36:42 +0000
3959+++ tests/tests.pro 2014-09-18 22:57:30 +0000
3960@@ -1,2 +1,2 @@
3961 TEMPLATE = subdirs
3962-SUBDIRS = modules
3963+SUBDIRS = modules mirserver

Subscribers

People subscribed via source and target branches

to all changes: