Merge lp:~gerboland/qtmir/initialSurfaceGeometry into lp:qtmir
- initialSurfaceGeometry
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~gerboland/qtmir/initialSurfaceGeometry |
Merge into: | lp:qtmir |
Prerequisite: | lp:~dandrader/qtmir/lifecycle |
Diff against target: |
5503 lines (+1949/-1606) 45 files modified
CMakeLists.txt (+3/-1) debian/changelog (+7/-0) debian/control (+1/-1) src/common/globals.h (+76/-0) src/modules/Unity/Application/CMakeLists.txt (+2/-0) src/modules/Unity/Application/application.cpp (+341/-69) src/modules/Unity/Application/application.h (+61/-19) src/modules/Unity/Application/application_manager.cpp (+118/-245) src/modules/Unity/Application/application_manager.h (+22/-20) src/modules/Unity/Application/applicationcontroller.h (+2/-1) src/modules/Unity/Application/applicationscreenshotprovider.cpp (+1/-1) src/modules/Unity/Application/mirsurfaceitem.cpp (+25/-25) src/modules/Unity/Application/mirsurfaceitem.h (+21/-78) src/modules/Unity/Application/mirsurfaceiteminterface.h (+89/-0) src/modules/Unity/Application/mirsurfaceitemmodel.h (+2/-2) src/modules/Unity/Application/mirsurfacemanager.cpp (+6/-6) src/modules/Unity/Application/mirsurfacemanager.h (+4/-4) src/modules/Unity/Application/plugin.cpp (+30/-32) src/modules/Unity/Application/session.cpp (+123/-73) src/modules/Unity/Application/session.h (+15/-8) src/modules/Unity/Application/session_interface.h (+31/-23) src/modules/Unity/Application/sessionmanager.cpp (+2/-2) src/modules/Unity/Application/sessionmanager.h (+3/-1) src/modules/Unity/Application/taskcontroller.cpp (+8/-13) src/modules/Unity/Application/taskcontroller.h (+4/-6) src/modules/Unity/Application/upstart/applicationcontroller.cpp (+10/-2) src/platforms/mirserver/CMakeLists.txt (+2/-0) src/platforms/mirserver/mirserver.cpp (+1/-2) src/platforms/mirserver/mirshell.cpp (+28/-23) src/platforms/mirserver/mirshell.h (+16/-12) tests/modules/Application/CMakeLists.txt (+5/-0) tests/modules/Application/application_test.cpp (+145/-71) tests/modules/ApplicationManager/CMakeLists.txt (+5/-1) tests/modules/ApplicationManager/application_manager_test.cpp (+410/-831) tests/modules/MirSurfaceItem/CMakeLists.txt (+3/-1) tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp (+1/-1) tests/modules/SessionManager/CMakeLists.txt (+4/-0) tests/modules/SessionManager/session_manager_test.cpp (+1/-1) tests/modules/SessionManager/session_test.cpp (+57/-24) tests/modules/TaskController/CMakeLists.txt (+1/-0) tests/modules/common/fake_mirsurfaceitem.h (+95/-0) tests/modules/common/mock_mirsurfaceitem.h (+50/-0) tests/modules/common/mock_session.h (+44/-5) tests/modules/common/qtmir_test.cpp (+61/-0) tests/modules/common/qtmir_test.h (+13/-2) |
To merge this branch: | bzr merge lp:~gerboland/qtmir/initialSurfaceGeometry |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Albert Astals Cid (community) | Needs Fixing | ||
Michał Sawicz | Approve | ||
Daniel d'Andrada | Pending | ||
Review via email: mp+231725@code.launchpad.net |
This proposal supersedes a proposal from 2014-08-12.
Commit message
Implement a callback mechanism to allow shell override the initial surface geometry requested by clients
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
* 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
* If you changed the UI, has there been a design review?
N/A
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
Comments addressed, please check out rev 234
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:235
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) : Posted in a previous version of this proposal | # |
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
In src/platforms/
+ void sessionAboutToC
That line is way too long.
In tests/modules/
+ QJSValue callback = jsEngine-
Here as well.
Looks good otherwise.
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
Done
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:236
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) : Posted in a previous version of this proposal | # |
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Minor inline.
Gerry Boland (gerboland) : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:237
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:238
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) : Posted in a previous version of this proposal | # |
Gerry Boland (gerboland) : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:240
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:241
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:241
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:243
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:244
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
635 + std::shared_
...
601 + //auto sharedPtr = the_placement_
602 + if (m_placementStr
603 +
604 + return static_
Better as:
std::weak_
....
return m_placementStra
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:261
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Code looks good, haven't time to test. If nobody beats me to it, i'll do on Monday
Albert Astals Cid (aacid) wrote : | # |
Doesn't merge correctly
Text conflict in debian/changelog
Text conflict in src/modules/
Text conflict in src/modules/
3 conflicts encountered.
- 262. By Gerry Boland
-
Merge trunk & fix conflicts
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:262
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Let's wait for https:/
- 263. By Gerry Boland
-
Move Surface Types & States into Globals enum class. Expand surfaceSizer parameter to include state
- 264. By Gerry Boland
-
Merge trunk
- 265. By Gerry Boland
-
Merge trunk, required many changes
- 266. By Gerry Boland
-
Remove accidental commits
- 267. By Gerry Boland
-
Remove local build tweak
- 268. By Gerry Boland
-
Merge trunk
- 269. By Gerry Boland
-
Merge detach-
state-from- focus and resolve conflicts
Unmerged revisions
- 269. By Gerry Boland
-
Merge detach-
state-from- focus and resolve conflicts - 268. By Gerry Boland
-
Merge trunk
- 267. By Gerry Boland
-
Remove local build tweak
- 266. By Gerry Boland
-
Remove accidental commits
- 265. By Gerry Boland
-
Merge trunk, required many changes
- 264. By Gerry Boland
-
Merge trunk
- 263. By Gerry Boland
-
Move Surface Types & States into Globals enum class. Expand surfaceSizer parameter to include state
- 262. By Gerry Boland
-
Merge trunk & fix conflicts
- 261. By Gerry Boland
-
Merge trunk
- 260. By Gerry Boland
-
Workaround MirServer API missing the_placement_
strategy method (bug lp:1407687)
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2015-05-21 18:48:59 +0000 |
3 | +++ CMakeLists.txt 2015-07-13 21:57:32 +0000 |
4 | @@ -80,7 +80,9 @@ |
5 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
6 | pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED) |
7 | pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED) |
8 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6) |
9 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=7) |
10 | + |
11 | +include_directories(${APPLICATION_API_INCLUDE_DIRS}) |
12 | |
13 | add_definitions(-DMIR_REQUIRE_DEPRECATED_EVENT_OPT_IN=1) |
14 | |
15 | |
16 | === modified file 'debian/changelog' |
17 | --- debian/changelog 2015-06-17 13:46:09 +0000 |
18 | +++ debian/changelog 2015-07-13 21:57:32 +0000 |
19 | @@ -1,3 +1,10 @@ |
20 | +qtmir (0.4.6) UNRELEASED; urgency=medium |
21 | + |
22 | + * Implement a callback mechanism to allow shell override the initial |
23 | + surface geometry requested by clients |
24 | + |
25 | + -- Gerry Boland <gerry.boland@canonical.com> Mon, 12 Jul 2015 14:47:07 +0100 |
26 | + |
27 | qtmir (0.4.5+15.10.20150617-0ubuntu1) wily; urgency=medium |
28 | |
29 | [ Gerry Boland ] |
30 | |
31 | === modified file 'debian/control' |
32 | --- debian/control 2015-06-17 13:45:56 +0000 |
33 | +++ debian/control 2015-07-13 21:57:32 +0000 |
34 | @@ -28,7 +28,7 @@ |
35 | libubuntu-app-launch2-dev, |
36 | libubuntu-application-api-dev (>= 2.1.0), |
37 | libudev-dev, |
38 | - libunity-api-dev (>= 7.97), |
39 | + libunity-api-dev (>= 7.99), |
40 | liburl-dispatcher1-dev, |
41 | libxkbcommon-dev, |
42 | libxrender-dev, |
43 | |
44 | === added file 'src/common/globals.h' |
45 | --- src/common/globals.h 1970-01-01 00:00:00 +0000 |
46 | +++ src/common/globals.h 2015-07-13 21:57:32 +0000 |
47 | @@ -0,0 +1,76 @@ |
48 | +/* |
49 | + * Copyright (C) 2015 Canonical, Ltd. |
50 | + * |
51 | + * This program is free software: you can redistribute it and/or modify it under |
52 | + * the terms of the GNU Lesser General Public License version 3, as published by |
53 | + * the Free Software Foundation. |
54 | + * |
55 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
56 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
57 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
58 | + * Lesser General Public License for more details. |
59 | + * |
60 | + * You should have received a copy of the GNU Lesser General Public License |
61 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
62 | + */ |
63 | + |
64 | +#ifndef GLOBALS_H |
65 | +#define GLOBALS_H |
66 | + |
67 | +#include <QObject> |
68 | +#include <QSize> |
69 | +#include <mir_toolkit/common.h> |
70 | + |
71 | +namespace qtmir { |
72 | + |
73 | +class Globals |
74 | +{ |
75 | + Q_GADGET |
76 | + Q_ENUMS(SurfaceState) |
77 | + Q_ENUMS(SurfaceType) |
78 | + |
79 | +public: |
80 | + enum SurfaceState { |
81 | + Unknown = mir_surface_state_unknown, |
82 | + Restored = mir_surface_state_restored, |
83 | + Minimized = mir_surface_state_minimized, |
84 | + Maximized = mir_surface_state_maximized, |
85 | + VertMaximized = mir_surface_state_vertmaximized, |
86 | + /* SemiMaximized = mir_surface_state_semimaximized, // see mircommon/mir_toolbox/common.h*/ |
87 | + Fullscreen = mir_surface_state_fullscreen, |
88 | + }; |
89 | + |
90 | + enum SurfaceType { |
91 | + Normal = mir_surface_type_normal, |
92 | + Utility = mir_surface_type_utility, |
93 | + Dialog = mir_surface_type_dialog, |
94 | + Overlay = mir_surface_type_overlay, |
95 | + Freestyle = mir_surface_type_freestyle, |
96 | + Popover = mir_surface_type_popover, |
97 | + InputMethod = mir_surface_type_inputmethod, |
98 | + }; |
99 | + |
100 | + enum OrientationAngle { |
101 | + Angle0 = 0, |
102 | + Angle90 = 90, |
103 | + Angle180 = 180, |
104 | + Angle270 = 270 |
105 | + }; |
106 | + |
107 | +private: |
108 | + Globals() = default; |
109 | + ~Globals() = default; |
110 | +}; |
111 | + |
112 | + |
113 | +struct SurfaceParameters |
114 | +{ |
115 | + QSize geometry; |
116 | + Globals::SurfaceState state; |
117 | +}; |
118 | + |
119 | +} // namespace qtmir |
120 | + |
121 | +Q_DECLARE_METATYPE(qtmir::Globals::OrientationAngle) |
122 | + |
123 | +#endif // GLOBALS_H |
124 | |
125 | === modified file 'src/modules/Unity/Application/CMakeLists.txt' |
126 | --- src/modules/Unity/Application/CMakeLists.txt 2015-05-21 18:48:59 +0000 |
127 | +++ src/modules/Unity/Application/CMakeLists.txt 2015-07-13 21:57:32 +0000 |
128 | @@ -46,9 +46,11 @@ |
129 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h |
130 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h |
131 | # Feed the automoc monster |
132 | + mirsurfaceiteminterface.h |
133 | session_interface.h |
134 | applicationcontroller.h |
135 | settings_interface.h |
136 | + ../../../common/globals.h |
137 | ) |
138 | |
139 | add_library(unityapplicationplugin SHARED |
140 | |
141 | === modified file 'src/modules/Unity/Application/application.cpp' |
142 | --- src/modules/Unity/Application/application.cpp 2015-04-10 14:54:44 +0000 |
143 | +++ src/modules/Unity/Application/application.cpp 2015-07-13 21:57:32 +0000 |
144 | @@ -1,5 +1,5 @@ |
145 | /* |
146 | - * Copyright (C) 2013-2014 Canonical, Ltd. |
147 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
148 | * |
149 | * This program is free software: you can redistribute it and/or modify it under |
150 | * the terms of the GNU Lesser General Public License version 3, as published by |
151 | @@ -37,25 +37,28 @@ |
152 | namespace qtmir |
153 | { |
154 | |
155 | -Application::Application(const QSharedPointer<TaskController>& taskController, |
156 | - const QSharedPointer<SharedWakelock>& sharedWakelock, |
157 | +QStringList Application::lifecycleExceptions; |
158 | + |
159 | +Application::Application(const QSharedPointer<SharedWakelock>& sharedWakelock, |
160 | DesktopFileReader *desktopFileReader, |
161 | - State state, |
162 | const QStringList &arguments, |
163 | ApplicationManager *parent) |
164 | : ApplicationInfoInterface(desktopFileReader->appId(), parent) |
165 | - , m_taskController(taskController) |
166 | , m_sharedWakelock(sharedWakelock) |
167 | , m_desktopData(desktopFileReader) |
168 | , m_pid(0) |
169 | , m_stage((m_desktopData->stageHint() == "SideStage") ? Application::SideStage : Application::MainStage) |
170 | - , m_state(state) |
171 | + , m_state(InternalState::Starting) |
172 | , m_focused(false) |
173 | - , m_canBeResumed(true) |
174 | , m_arguments(arguments) |
175 | , m_session(nullptr) |
176 | + , m_requestedState(RequestedRunning) |
177 | + , m_processState(ProcessUnknown) |
178 | { |
179 | - qCDebug(QTMIR_APPLICATIONS) << "Application::Application - appId=" << desktopFileReader->appId() << "state=" << state; |
180 | + qCDebug(QTMIR_APPLICATIONS) << "Application::Application - appId=" << desktopFileReader->appId(); |
181 | + |
182 | + // Because m_state is InternalState::Starting |
183 | + acquireWakelock(); |
184 | |
185 | // FIXME(greyback) need to save long appId internally until ubuntu-app-launch can hide it from us |
186 | m_longAppId = desktopFileReader->file().remove(QRegExp(".desktop$")).split('/').last(); |
187 | @@ -69,10 +72,33 @@ |
188 | { |
189 | qCDebug(QTMIR_APPLICATIONS) << "Application::~Application"; |
190 | |
191 | + // (ricmm) -- To be on the safe side, better wipe the application QML compile cache if it crashes on startup |
192 | + if (m_processState == Application::ProcessUnknown |
193 | + || state() == Application::Starting |
194 | + || state() == Application::Running) { |
195 | + wipeQMLCache(); |
196 | + } |
197 | + |
198 | delete m_session; |
199 | delete m_desktopData; |
200 | } |
201 | |
202 | + |
203 | +void Application::wipeQMLCache() |
204 | +{ |
205 | + QString path(QDir::homePath() + QStringLiteral("/.cache/QML/Apps/")); |
206 | + QDir dir(path); |
207 | + QStringList apps = dir.entryList(); |
208 | + for (int i = 0; i < apps.size(); i++) { |
209 | + if (apps.at(i).contains(appId())) { |
210 | + qCDebug(QTMIR_APPLICATIONS) << "Application appId=" << apps.at(i) << " Wiping QML Cache"; |
211 | + dir.cd(apps.at(i)); |
212 | + dir.removeRecursively(); |
213 | + break; |
214 | + } |
215 | + } |
216 | +} |
217 | + |
218 | bool Application::isValid() const |
219 | { |
220 | return m_desktopData->loaded(); |
221 | @@ -159,6 +185,30 @@ |
222 | return color; |
223 | } |
224 | |
225 | +const char* Application::internalStateToStr(InternalState state) |
226 | +{ |
227 | + switch (state) { |
228 | + case InternalState::Starting: |
229 | + return "Starting"; |
230 | + case InternalState::Running: |
231 | + return "Running"; |
232 | + case InternalState::RunningInBackground: |
233 | + return "RunningInBackground"; |
234 | + case InternalState::SuspendingWaitSession: |
235 | + return "SuspendingWaitSession"; |
236 | + case InternalState::SuspendingWaitProcess: |
237 | + return "SuspendingWaitProcess"; |
238 | + case InternalState::Suspended: |
239 | + return "Suspended"; |
240 | + case InternalState::StoppedUnexpectedly: |
241 | + return "StoppedUnexpectedly"; |
242 | + case InternalState::Stopped: |
243 | + return "Stopped"; |
244 | + default: |
245 | + return "???"; |
246 | + } |
247 | +} |
248 | + |
249 | bool Application::splashShowHeader() const |
250 | { |
251 | QString showHeader = m_desktopData->splashShowHeader(); |
252 | @@ -204,7 +254,104 @@ |
253 | |
254 | Application::State Application::state() const |
255 | { |
256 | - return m_state; |
257 | + // The public state is a simplified version of the internal one as our consumers |
258 | + // don't have to know or care about all the nasty details. |
259 | + switch (m_state) { |
260 | + case InternalState::Starting: |
261 | + return Starting; |
262 | + case InternalState::Running: |
263 | + case InternalState::RunningInBackground: |
264 | + case InternalState::SuspendingWaitSession: |
265 | + case InternalState::SuspendingWaitProcess: |
266 | + return Running; |
267 | + case InternalState::Suspended: |
268 | + return Suspended; |
269 | + case InternalState::Stopped: |
270 | + default: |
271 | + return Stopped; |
272 | + } |
273 | +} |
274 | + |
275 | +Application::RequestedState Application::requestedState() const |
276 | +{ |
277 | + return m_requestedState; |
278 | +} |
279 | + |
280 | +void Application::setRequestedState(RequestedState value) |
281 | +{ |
282 | + if (m_requestedState == value) { |
283 | + // nothing to do |
284 | + return; |
285 | + } |
286 | + |
287 | + qCDebug(QTMIR_APPLICATIONS) << "Application::setRequestedState - appId=" << appId() |
288 | + << "requestedState=" << applicationStateToStr(value); |
289 | + m_requestedState = value; |
290 | + Q_EMIT requestedStateChanged(m_requestedState); |
291 | + |
292 | + applyRequestedState(); |
293 | +} |
294 | + |
295 | +void Application::applyRequestedState() |
296 | +{ |
297 | + if (m_requestedState == RequestedRunning) { |
298 | + applyRequestedRunning(); |
299 | + } else { |
300 | + applyRequestedSuspended(); |
301 | + } |
302 | +} |
303 | + |
304 | +void Application::applyRequestedRunning() |
305 | +{ |
306 | + switch (m_state) { |
307 | + case InternalState::Starting: |
308 | + // should leave the app alone until it reaches Running state |
309 | + break; |
310 | + case InternalState::Running: |
311 | + // already where it's wanted to be |
312 | + break; |
313 | + case InternalState::RunningInBackground: |
314 | + case InternalState::SuspendingWaitSession: |
315 | + case InternalState::Suspended: |
316 | + resume(); |
317 | + break; |
318 | + case InternalState::SuspendingWaitProcess: |
319 | + // should leave the app alone until it reaches Suspended state |
320 | + break; |
321 | + case InternalState::StoppedUnexpectedly: |
322 | + respawn(); |
323 | + break; |
324 | + case InternalState::Stopped: |
325 | + // dead end. |
326 | + break; |
327 | + } |
328 | +} |
329 | + |
330 | +void Application::applyRequestedSuspended() |
331 | +{ |
332 | + switch (m_state) { |
333 | + case InternalState::Starting: |
334 | + // should leave the app alone until it reaches Running state |
335 | + break; |
336 | + case InternalState::Running: |
337 | + if (m_processState == ProcessRunning) { |
338 | + suspend(); |
339 | + } else { |
340 | + // we can't suspend it since we have no information on the app process |
341 | + Q_ASSERT(m_processState == ProcessUnknown); |
342 | + } |
343 | + break; |
344 | + case InternalState::RunningInBackground: |
345 | + case InternalState::SuspendingWaitSession: |
346 | + case InternalState::SuspendingWaitProcess: |
347 | + case InternalState::Suspended: |
348 | + // it's already going where we it's wanted |
349 | + break; |
350 | + case InternalState::StoppedUnexpectedly: |
351 | + case InternalState::Stopped: |
352 | + // the app doesn't have a process in the first place, so there's nothing to suspend |
353 | + break; |
354 | + } |
355 | } |
356 | |
357 | bool Application::focused() const |
358 | @@ -219,12 +366,7 @@ |
359 | |
360 | bool Application::canBeResumed() const |
361 | { |
362 | - return m_canBeResumed; |
363 | -} |
364 | - |
365 | -void Application::setCanBeResumed(const bool resume) |
366 | -{ |
367 | - m_canBeResumed = resume; |
368 | + return m_processState != ProcessUnknown; |
369 | } |
370 | |
371 | pid_t Application::pid() const |
372 | @@ -242,7 +384,7 @@ |
373 | m_arguments = arguments; |
374 | } |
375 | |
376 | -void Application::setSession(Session *newSession) |
377 | +void Application::setSession(SessionInterface *newSession) |
378 | { |
379 | qCDebug(QTMIR_APPLICATIONS) << "Application::setSession - appId=" << appId() << "session=" << newSession; |
380 | |
381 | @@ -261,10 +403,25 @@ |
382 | if (m_session) { |
383 | m_session->setParent(this); |
384 | m_session->setApplication(this); |
385 | - m_session->setState(state()); |
386 | - |
387 | - connect(m_session, &SessionInterface::suspended, this, &Application::onSessionSuspended); |
388 | - connect(m_session, &SessionInterface::resumed, this, &Application::onSessionResumed); |
389 | + |
390 | + switch (m_state) { |
391 | + case InternalState::Starting: |
392 | + case InternalState::Running: |
393 | + case InternalState::RunningInBackground: |
394 | + m_session->resume(); |
395 | + break; |
396 | + case InternalState::SuspendingWaitSession: |
397 | + case InternalState::SuspendingWaitProcess: |
398 | + case InternalState::Suspended: |
399 | + m_session->suspend(); |
400 | + break; |
401 | + case InternalState::Stopped: |
402 | + default: |
403 | + m_session->stop(); |
404 | + break; |
405 | + } |
406 | + |
407 | + connect(m_session, &SessionInterface::stateChanged, this, &Application::onSessionStateChanged); |
408 | connect(m_session, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged); |
409 | |
410 | if (oldFullscreen != fullscreen()) |
411 | @@ -288,37 +445,53 @@ |
412 | } |
413 | } |
414 | |
415 | -void Application::setState(Application::State state) |
416 | +void Application::setInternalState(Application::InternalState state) |
417 | { |
418 | - qCDebug(QTMIR_APPLICATIONS) << "Application::setState - appId=" << appId() << "state=" << applicationStateToStr(state); |
419 | - if (m_state != state) { |
420 | - if (session()) { |
421 | - session()->setState((Session::State)state); |
422 | - } else { |
423 | - // If we have have no session, we may have to respawn it. |
424 | - switch (state) |
425 | - { |
426 | - case Session::State::Running: |
427 | - if (m_state == Session::State::Stopped) { |
428 | - respawn(); |
429 | - state = Session::State::Starting; |
430 | - } |
431 | - break; |
432 | - default: |
433 | - break; |
434 | - } |
435 | - } |
436 | - m_state = state; |
437 | - Q_EMIT stateChanged(state); |
438 | - } |
439 | + if (m_state == state) { |
440 | + return; |
441 | + } |
442 | + |
443 | + qCDebug(QTMIR_APPLICATIONS) << "Application::setInternalState - appId=" << appId() |
444 | + << "state=" << internalStateToStr(state); |
445 | + |
446 | + auto oldPublicState = this->state(); |
447 | + m_state = state; |
448 | + |
449 | + switch (m_state) { |
450 | + case InternalState::Starting: |
451 | + case InternalState::Running: |
452 | + acquireWakelock(); |
453 | + break; |
454 | + case InternalState::RunningInBackground: |
455 | + releaseWakelock(); |
456 | + break; |
457 | + case InternalState::Suspended: |
458 | + releaseWakelock(); |
459 | + break; |
460 | + case InternalState::StoppedUnexpectedly: |
461 | + releaseWakelock(); |
462 | + break; |
463 | + case InternalState::Stopped: |
464 | + Q_EMIT stopped(); |
465 | + releaseWakelock(); |
466 | + break; |
467 | + case InternalState::SuspendingWaitSession: |
468 | + case InternalState::SuspendingWaitProcess: |
469 | + // transitory states. leave as it is |
470 | + default: |
471 | + break; |
472 | + }; |
473 | + |
474 | + if (this->state() != oldPublicState) { |
475 | + Q_EMIT stateChanged(this->state()); |
476 | + } |
477 | + |
478 | + applyRequestedState(); |
479 | } |
480 | |
481 | void Application::setFocused(bool focused) |
482 | { |
483 | qCDebug(QTMIR_APPLICATIONS) << "Application::setFocused - appId=" << appId() << "focused=" << focused; |
484 | - if (focused) { |
485 | - holdWakelock(true); |
486 | - } |
487 | |
488 | if (m_focused != focused) { |
489 | m_focused = focused; |
490 | @@ -326,25 +499,84 @@ |
491 | } |
492 | } |
493 | |
494 | -void Application::onSessionSuspended() |
495 | -{ |
496 | - qCDebug(QTMIR_APPLICATIONS) << "Application::onSessionSuspended - appId=" << appId(); |
497 | - m_taskController->suspend(longAppId()); |
498 | - holdWakelock(false); |
499 | -} |
500 | - |
501 | -void Application::onSessionResumed() |
502 | -{ |
503 | - qCDebug(QTMIR_APPLICATIONS) << "Application::onSessionResumed - appId=" << appId(); |
504 | - holdWakelock(true); |
505 | - m_taskController->resume(longAppId()); |
506 | +void Application::setProcessState(ProcessState newProcessState) |
507 | +{ |
508 | + if (m_processState == newProcessState) { |
509 | + return; |
510 | + } |
511 | + |
512 | + m_processState = newProcessState; |
513 | + |
514 | + switch (m_processState) { |
515 | + case ProcessUnknown: |
516 | + // it would be a coding error |
517 | + Q_ASSERT(false); |
518 | + break; |
519 | + case ProcessRunning: |
520 | + if (m_state == InternalState::StoppedUnexpectedly) { |
521 | + setInternalState(InternalState::Starting); |
522 | + } |
523 | + break; |
524 | + case ProcessSuspended: |
525 | + Q_ASSERT(m_state == InternalState::SuspendingWaitProcess); |
526 | + setInternalState(InternalState::Suspended); |
527 | + break; |
528 | + case ProcessStopped: |
529 | + // we assume the session always stop before the process |
530 | + Q_ASSERT(!m_session || m_session->state() == Session::Stopped); |
531 | + if (m_state == InternalState::Starting) { |
532 | + setInternalState(InternalState::Stopped); |
533 | + } else { |
534 | + Q_ASSERT(m_state == InternalState::Stopped |
535 | + || m_state == InternalState::StoppedUnexpectedly); |
536 | + } |
537 | + break; |
538 | + } |
539 | + |
540 | + applyRequestedState(); |
541 | +} |
542 | + |
543 | +void Application::suspend() |
544 | +{ |
545 | + Q_ASSERT(m_state == InternalState::Running); |
546 | + Q_ASSERT(m_session != nullptr); |
547 | + |
548 | + if (!lifecycleExceptions.filter(appId().section('_',0,0)).empty()) { |
549 | + // Present in exceptions list. |
550 | + // There's no need to keep the wakelock as the process is never suspended |
551 | + // and thus has no cleanup to perform when (for example) the display is |
552 | + // blanked. |
553 | + setInternalState(InternalState::RunningInBackground); |
554 | + } else { |
555 | + setInternalState(InternalState::SuspendingWaitSession); |
556 | + m_session->suspend(); |
557 | + } |
558 | +} |
559 | + |
560 | +void Application::resume() |
561 | +{ |
562 | + if (m_state == InternalState::Suspended) { |
563 | + setInternalState(InternalState::Running); |
564 | + Q_EMIT resumeProcessRequested(); |
565 | + if (m_processState == ProcessSuspended) { |
566 | + setProcessState(ProcessRunning); // should we wait for a resumed() signal? |
567 | + } |
568 | + m_session->resume(); |
569 | + } else if (m_state == InternalState::SuspendingWaitSession) { |
570 | + setInternalState(InternalState::Running); |
571 | + m_session->resume(); |
572 | + } else if (m_state == InternalState::RunningInBackground) { |
573 | + setInternalState(InternalState::Running); |
574 | + } |
575 | } |
576 | |
577 | void Application::respawn() |
578 | { |
579 | qCDebug(QTMIR_APPLICATIONS) << "Application::respawn - appId=" << appId(); |
580 | - holdWakelock(true); |
581 | - m_taskController->start(appId(), m_arguments); |
582 | + |
583 | + setInternalState(InternalState::Starting); |
584 | + |
585 | + Q_EMIT startProcessRequested(); |
586 | } |
587 | |
588 | QString Application::longAppId() const |
589 | @@ -362,20 +594,60 @@ |
590 | return m_rotatesWindowContents; |
591 | } |
592 | |
593 | -Session* Application::session() const |
594 | +SessionInterface* Application::session() const |
595 | { |
596 | return m_session; |
597 | } |
598 | |
599 | -void Application::holdWakelock(bool enable) const |
600 | -{ |
601 | - if (appId() == "unity8-dash") |
602 | - return; |
603 | - |
604 | - if (enable) { |
605 | - m_sharedWakelock->acquire(this); |
606 | - } else { |
607 | - m_sharedWakelock->release(this); |
608 | +void Application::acquireWakelock() const |
609 | +{ |
610 | + if (appId() == "unity8-dash") |
611 | + return; |
612 | + |
613 | + m_sharedWakelock->acquire(this); |
614 | +} |
615 | + |
616 | +void Application::releaseWakelock() const |
617 | +{ |
618 | + if (appId() == "unity8-dash") |
619 | + return; |
620 | + |
621 | + m_sharedWakelock->release(this); |
622 | +} |
623 | + |
624 | +void Application::onSessionStateChanged(Session::State sessionState) |
625 | +{ |
626 | + switch (sessionState) { |
627 | + case Session::Starting: |
628 | + break; |
629 | + case Session::Running: |
630 | + if (m_state == InternalState::Starting) { |
631 | + setInternalState(InternalState::Running); |
632 | + } |
633 | + break; |
634 | + case Session::Suspending: |
635 | + break; |
636 | + case Session::Suspended: |
637 | + Q_ASSERT(m_state == InternalState::SuspendingWaitSession); |
638 | + setInternalState(InternalState::SuspendingWaitProcess); |
639 | + Q_EMIT suspendProcessRequested(); |
640 | + break; |
641 | + case Session::Stopped: |
642 | + if (!canBeResumed() |
643 | + || m_state == InternalState::Starting |
644 | + || m_state == InternalState::Running) { |
645 | + /* 1. application is not managed by upstart |
646 | + * 2. application is managed by upstart, but has stopped before it managed |
647 | + * to create a surface, we can assume it crashed on startup, and thus |
648 | + * cannot be resumed |
649 | + * 3. application is managed by upstart and is in foreground (i.e. has |
650 | + * Running state), if Mir reports the application disconnects, it |
651 | + * either crashed or stopped itself. |
652 | + */ |
653 | + setInternalState(InternalState::Stopped); |
654 | + } else { |
655 | + setInternalState(InternalState::StoppedUnexpectedly); |
656 | + } |
657 | } |
658 | } |
659 | |
660 | |
661 | === modified file 'src/modules/Unity/Application/application.h' |
662 | --- src/modules/Unity/Application/application.h 2015-01-19 11:48:32 +0000 |
663 | +++ src/modules/Unity/Application/application.h 2015-07-13 21:57:32 +0000 |
664 | @@ -1,5 +1,5 @@ |
665 | /* |
666 | - * Copyright (C) 2013-2014 Canonical, Ltd. |
667 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
668 | * |
669 | * This program is free software: you can redistribute it and/or modify it under |
670 | * the terms of the GNU Lesser General Public License version 3, as published by |
671 | @@ -28,6 +28,8 @@ |
672 | // Unity API |
673 | #include <unity/shell/application/ApplicationInfoInterface.h> |
674 | |
675 | +#include "session_interface.h" |
676 | + |
677 | namespace mir { |
678 | namespace scene { |
679 | class Session; |
680 | @@ -39,7 +41,6 @@ |
681 | |
682 | class ApplicationManager; |
683 | class DesktopFileReader; |
684 | -class TaskController; |
685 | class Session; |
686 | class SharedWakelock; |
687 | |
688 | @@ -51,15 +52,32 @@ |
689 | Q_PROPERTY(QString exec READ exec CONSTANT) |
690 | Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged) |
691 | Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged) |
692 | - Q_PROPERTY(Session* session READ session NOTIFY sessionChanged DESIGNABLE false) |
693 | + Q_PROPERTY(SessionInterface* session READ session NOTIFY sessionChanged DESIGNABLE false) |
694 | |
695 | public: |
696 | Q_DECLARE_FLAGS(Stages, Stage) |
697 | |
698 | - Application(const QSharedPointer<TaskController>& taskController, |
699 | - const QSharedPointer<SharedWakelock>& sharedWakelock, |
700 | + enum ProcessState { |
701 | + ProcessUnknown, |
702 | + ProcessRunning, |
703 | + ProcessSuspended, |
704 | + ProcessStopped |
705 | + }; |
706 | + |
707 | + enum class InternalState { |
708 | + Starting, |
709 | + Running, |
710 | + RunningInBackground, |
711 | + SuspendingWaitSession, |
712 | + SuspendingWaitProcess, |
713 | + Suspended, |
714 | + StoppedUnexpectedly, |
715 | + Stopped // It closed itself, crashed or it stopped and we can't respawn it |
716 | + // In any case, this is a dead end. |
717 | + }; |
718 | + |
719 | + Application(const QSharedPointer<SharedWakelock>& sharedWakelock, |
720 | DesktopFileReader *desktopFileReader, |
721 | - State state, |
722 | const QStringList &arguments, |
723 | ApplicationManager *parent); |
724 | virtual ~Application(); |
725 | @@ -71,6 +89,8 @@ |
726 | QUrl icon() const override; |
727 | Stage stage() const override; |
728 | State state() const override; |
729 | + RequestedState requestedState() const override; |
730 | + void setRequestedState(RequestedState) override; |
731 | bool focused() const override; |
732 | QString splashTitle() const override; |
733 | QUrl splashImage() const override; |
734 | @@ -82,12 +102,16 @@ |
735 | bool rotatesWindowContents() const override; |
736 | |
737 | void setStage(Stage stage); |
738 | - void setState(State state); |
739 | - |
740 | - Session* session() const; |
741 | + |
742 | + |
743 | + void setProcessState(ProcessState value); |
744 | + |
745 | + QStringList arguments() const { return m_arguments; } |
746 | + |
747 | + SessionInterface* session() const; |
748 | + void setSession(SessionInterface *session); |
749 | |
750 | bool canBeResumed() const; |
751 | - void setCanBeResumed(const bool); |
752 | |
753 | bool isValid() const; |
754 | QString desktopFile() const; |
755 | @@ -98,40 +122,58 @@ |
756 | |
757 | pid_t pid() const; |
758 | |
759 | + // for tests |
760 | + InternalState internalState() const { return m_state; } |
761 | + |
762 | + static QStringList lifecycleExceptions; |
763 | + |
764 | Q_SIGNALS: |
765 | void fullscreenChanged(bool fullscreen); |
766 | void stageChanged(Stage stage); |
767 | - void sessionChanged(Session *session); |
768 | + void sessionChanged(SessionInterface *session); |
769 | + |
770 | + void startProcessRequested(); |
771 | + void suspendProcessRequested(); |
772 | + void resumeProcessRequested(); |
773 | + void stopped(); |
774 | |
775 | private Q_SLOTS: |
776 | - void onSessionSuspended(); |
777 | - void onSessionResumed(); |
778 | + void onSessionStateChanged(SessionInterface::State sessionState); |
779 | |
780 | void respawn(); |
781 | |
782 | private: |
783 | + |
784 | QString longAppId() const; |
785 | - void holdWakelock(bool enable) const; |
786 | + void acquireWakelock() const; |
787 | + void releaseWakelock() const; |
788 | void setPid(pid_t pid); |
789 | void setArguments(const QStringList arguments); |
790 | void setFocused(bool focus); |
791 | - void setSession(Session *session); |
792 | + void setInternalState(InternalState state); |
793 | + void wipeQMLCache(); |
794 | + void suspend(); |
795 | + void resume(); |
796 | QColor colorFromString(const QString &colorString, const char *colorName) const; |
797 | + static const char* internalStateToStr(InternalState state); |
798 | + void applyRequestedState(); |
799 | + void applyRequestedRunning(); |
800 | + void applyRequestedSuspended(); |
801 | |
802 | - QSharedPointer<TaskController> m_taskController; |
803 | QSharedPointer<SharedWakelock> m_sharedWakelock; |
804 | DesktopFileReader* m_desktopData; |
805 | QString m_longAppId; |
806 | qint64 m_pid; |
807 | Stage m_stage; |
808 | Stages m_supportedStages; |
809 | - State m_state; |
810 | + InternalState m_state; |
811 | bool m_focused; |
812 | - bool m_canBeResumed; |
813 | QStringList m_arguments; |
814 | Qt::ScreenOrientations m_supportedOrientations; |
815 | bool m_rotatesWindowContents; |
816 | - Session *m_session; |
817 | + SessionInterface *m_session; |
818 | + RequestedState m_requestedState; |
819 | + ProcessState m_processState; |
820 | |
821 | friend class ApplicationManager; |
822 | friend class SessionManager; |
823 | |
824 | === modified file 'src/modules/Unity/Application/application_manager.cpp' |
825 | --- src/modules/Unity/Application/application_manager.cpp 2015-05-21 18:38:27 +0000 |
826 | +++ src/modules/Unity/Application/application_manager.cpp 2015-07-13 21:57:32 +0000 |
827 | @@ -1,5 +1,5 @@ |
828 | /* |
829 | - * Copyright (C) 2013,2014 Canonical, Ltd. |
830 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
831 | * |
832 | * This program is free software: you can redistribute it and/or modify it under |
833 | * the terms of the GNU Lesser General Public License version 3, as published by |
834 | @@ -29,6 +29,7 @@ |
835 | |
836 | // mirserver |
837 | #include "mirserver.h" |
838 | +#include "mirshell.h" |
839 | #include "nativeinterface.h" |
840 | #include "sessionlistener.h" |
841 | #include "sessionauthorizer.h" |
842 | @@ -47,6 +48,8 @@ |
843 | #include <QDebug> |
844 | #include <QByteArray> |
845 | #include <QDir> |
846 | +#include <QJSEngine> |
847 | +#include <QJSValue> |
848 | |
849 | // std |
850 | #include <csignal> |
851 | @@ -90,23 +93,31 @@ |
852 | manager, &ApplicationManager::authorizeSession, Qt::BlockingQueuedConnection); |
853 | } |
854 | |
855 | +void connectToMirShell(ApplicationManager *manager, MirShell *shell) |
856 | +{ |
857 | + QObject::connect(shell, &MirShell::sessionAboutToCreateSurface, |
858 | + manager, &ApplicationManager::onSessionAboutToCreateSurface, Qt::BlockingQueuedConnection); |
859 | +} |
860 | + |
861 | void connectToTaskController(ApplicationManager *manager, TaskController *controller) |
862 | { |
863 | QObject::connect(controller, &TaskController::processStarting, |
864 | manager, &ApplicationManager::onProcessStarting); |
865 | QObject::connect(controller, &TaskController::processStopped, |
866 | manager, &ApplicationManager::onProcessStopped); |
867 | + QObject::connect(controller, &TaskController::processSuspended, |
868 | + manager, &ApplicationManager::onProcessSuspended); |
869 | QObject::connect(controller, &TaskController::processFailed, |
870 | manager, &ApplicationManager::onProcessFailed); |
871 | - QObject::connect(controller, &TaskController::requestFocus, |
872 | + QObject::connect(controller, &TaskController::focusRequested, |
873 | manager, &ApplicationManager::onFocusRequested); |
874 | - QObject::connect(controller, &TaskController::requestResume, |
875 | + QObject::connect(controller, &TaskController::resumeRequested, |
876 | manager, &ApplicationManager::onResumeRequested); |
877 | } |
878 | |
879 | } // namespace |
880 | |
881 | -ApplicationManager* ApplicationManager::Factory::Factory::create() |
882 | +ApplicationManager* ApplicationManager::Factory::Factory::create(QJSEngine *jsEngine) |
883 | { |
884 | NativeInterface *nativeInterface = dynamic_cast<NativeInterface*>(QGuiApplication::platformNativeInterface()); |
885 | |
886 | @@ -139,11 +150,13 @@ |
887 | sharedWakelock, |
888 | fileReaderFactory, |
889 | procInfo, |
890 | - settings |
891 | + settings, |
892 | + jsEngine |
893 | ); |
894 | |
895 | connectToSessionListener(appManager, sessionListener); |
896 | connectToSessionAuthorizer(appManager, sessionAuthorizer); |
897 | + connectToMirShell(appManager, mirServer.lock()->shell()); |
898 | connectToTaskController(appManager, taskController.data()); |
899 | |
900 | // Emit signal to notify Upstart that Mir is ready to receive client connections |
901 | @@ -159,12 +172,12 @@ |
902 | } |
903 | |
904 | |
905 | -ApplicationManager* ApplicationManager::singleton() |
906 | +ApplicationManager* ApplicationManager::singleton(QJSEngine *jsEngine) |
907 | { |
908 | static ApplicationManager* instance; |
909 | if (!instance) { |
910 | Factory appFactory; |
911 | - instance = appFactory.create(); |
912 | + instance = appFactory.create(jsEngine); |
913 | } |
914 | return instance; |
915 | } |
916 | @@ -176,20 +189,19 @@ |
917 | const QSharedPointer<DesktopFileReader::Factory>& desktopFileReaderFactory, |
918 | const QSharedPointer<ProcInfo>& procInfo, |
919 | const QSharedPointer<SettingsInterface>& settings, |
920 | + QJSEngine *jsEngine, |
921 | QObject *parent) |
922 | : ApplicationManagerInterface(parent) |
923 | , m_mirServer(mirServer) |
924 | , m_focusedApplication(nullptr) |
925 | - , m_mainStageApplication(nullptr) |
926 | - , m_sideStageApplication(nullptr) |
927 | , m_dbusWindowStack(new DBusWindowStack(this)) |
928 | , m_taskController(taskController) |
929 | , m_desktopFileReaderFactory(desktopFileReaderFactory) |
930 | , m_procInfo(procInfo) |
931 | , m_sharedWakelock(sharedWakelock) |
932 | , m_settings(settings) |
933 | - , m_suspended(false) |
934 | - , m_forceDashActive(false) |
935 | + , m_surfaceAboutToBeCreatedCallback(QJSValue::UndefinedValue) |
936 | + , m_jsEngine(jsEngine) |
937 | { |
938 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::ApplicationManager (this=%p)" << this; |
939 | setObjectName("qtmir::ApplicationManager"); |
940 | @@ -198,7 +210,7 @@ |
941 | m_roleNames.insert(RoleFullscreen, "fullscreen"); |
942 | |
943 | if (settings.data()) { |
944 | - m_lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList(); |
945 | + Application::lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList(); |
946 | connect(m_settings.data(), &Settings::changed, this, &ApplicationManager::onSettingsChanged); |
947 | } |
948 | } |
949 | @@ -206,6 +218,7 @@ |
950 | ApplicationManager::~ApplicationManager() |
951 | { |
952 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::~ApplicationManager"; |
953 | + m_surfaceAboutToBeCreatedCallback = QJSValue::UndefinedValue; //unset immediately to avoid racing on shutdown |
954 | } |
955 | |
956 | int ApplicationManager::rowCount(const QModelIndex &parent) const |
957 | @@ -289,96 +302,23 @@ |
958 | } |
959 | } |
960 | |
961 | -bool ApplicationManager::suspended() const |
962 | +QJSValue ApplicationManager::surfaceAboutToBeCreatedCallback() const |
963 | { |
964 | - return m_suspended; |
965 | + return m_surfaceAboutToBeCreatedCallback; |
966 | } |
967 | |
968 | -void ApplicationManager::setSuspended(bool suspended) |
969 | +void ApplicationManager::setSurfaceAboutToBeCreatedCallback(const QJSValue &callback) |
970 | { |
971 | - if (suspended == m_suspended) { |
972 | + if (m_surfaceAboutToBeCreatedCallback.equals(callback)) |
973 | return; |
974 | - } |
975 | - m_suspended = suspended; |
976 | - Q_EMIT suspendedChanged(); |
977 | |
978 | - if (m_suspended) { |
979 | - suspendApplication(m_mainStageApplication); |
980 | - suspendApplication(m_sideStageApplication); |
981 | - if (m_focusedApplication) { |
982 | - m_focusedApplication->setFocused(false); |
983 | - m_dbusWindowStack->FocusedWindowChanged(0, QString(), 0); |
984 | - } |
985 | + if (callback.isCallable()) { |
986 | + m_surfaceAboutToBeCreatedCallback = callback; |
987 | } else { |
988 | - resumeApplication(m_mainStageApplication); |
989 | - resumeApplication(m_sideStageApplication); |
990 | - if (m_focusedApplication) { |
991 | - m_focusedApplication->setFocused(true); |
992 | - m_dbusWindowStack->FocusedWindowChanged(0, m_focusedApplication->appId(), m_focusedApplication->stage()); |
993 | - } |
994 | - } |
995 | -} |
996 | - |
997 | -bool ApplicationManager::forceDashActive() const |
998 | -{ |
999 | - return m_forceDashActive; |
1000 | -} |
1001 | - |
1002 | -void ApplicationManager::setForceDashActive(bool forceDashActive) |
1003 | -{ |
1004 | - if (m_forceDashActive == forceDashActive) { |
1005 | - return; |
1006 | - } |
1007 | - |
1008 | - m_forceDashActive = forceDashActive; |
1009 | - Q_EMIT forceDashActiveChanged(); |
1010 | - |
1011 | - Application *dashApp = findApplication("unity8-dash"); |
1012 | - if (!dashApp) { |
1013 | - qCWarning(QTMIR_APPLICATIONS) << "Dash doesn't seem to be running... Ignoring."; |
1014 | - return; |
1015 | - } |
1016 | - |
1017 | - if (m_forceDashActive && dashApp->state() != Application::Running) { |
1018 | - resumeApplication(dashApp); |
1019 | - } else if (!m_forceDashActive && dashApp->state() == Application::Running |
1020 | - && m_mainStageApplication != dashApp |
1021 | - && m_sideStageApplication != dashApp) { |
1022 | - suspendApplication(dashApp); |
1023 | - } |
1024 | -} |
1025 | - |
1026 | -bool ApplicationManager::suspendApplication(Application *application) |
1027 | -{ |
1028 | - if (application == nullptr) |
1029 | - return false; |
1030 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::suspendApplication - appId=" << application->appId(); |
1031 | - |
1032 | - // Present in exceptions list, explicitly release wakelock and return. There's no need to keep the wakelock |
1033 | - // as the process is never suspended and thus has no cleanup to perform when (for example) the display is blanked |
1034 | - if (!m_lifecycleExceptions.filter(application->appId().section('_',0,0)).empty()) { |
1035 | - m_sharedWakelock->release(application); |
1036 | - return false; |
1037 | - } |
1038 | - |
1039 | - if (m_forceDashActive && application->appId() == "unity8-dash") { |
1040 | - return false; |
1041 | - } |
1042 | - |
1043 | - if (application->state() == Application::Running) |
1044 | - application->setState(Application::Suspended); |
1045 | - |
1046 | - return true; |
1047 | -} |
1048 | - |
1049 | -void ApplicationManager::resumeApplication(Application *application) |
1050 | -{ |
1051 | - if (application == nullptr) |
1052 | - return; |
1053 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::resumeApplication - appId=" << application->appId(); |
1054 | - |
1055 | - if (application->state() == Application::Suspended || application->state() == Application::Stopped) |
1056 | - application->setState(Application::Running); |
1057 | + qWarning() << "ApplicationManager::setSurfaceAboutToBeCreatedCallback - attempted to register a non-function!"; |
1058 | + m_surfaceAboutToBeCreatedCallback = QJSValue::UndefinedValue; |
1059 | + } |
1060 | + Q_EMIT surfaceAboutToBeCreatedCallbackChanged(); |
1061 | } |
1062 | |
1063 | bool ApplicationManager::focusApplication(const QString &inputAppId) |
1064 | @@ -392,27 +332,8 @@ |
1065 | return false; |
1066 | } |
1067 | |
1068 | - resumeApplication(application); |
1069 | - |
1070 | - // set state of previously focused app to suspended |
1071 | if (m_focusedApplication) { |
1072 | m_focusedApplication->setFocused(false); |
1073 | - Application *lastApplication = applicationForStage(application->stage()); |
1074 | - if (lastApplication != application) { |
1075 | - suspendApplication(lastApplication); |
1076 | - } |
1077 | - } |
1078 | - |
1079 | - if (application->stage() == Application::MainStage) { |
1080 | - m_mainStageApplication = application; |
1081 | - } else { |
1082 | - m_sideStageApplication = application; |
1083 | - } |
1084 | - |
1085 | - if (!m_suspended) { |
1086 | - resumeApplication(application); // in case unfocusCurrentApplication() was last called |
1087 | - } else { |
1088 | - suspendApplication(application); // Make sure we also have this one suspended if everything is suspended |
1089 | } |
1090 | |
1091 | m_focusedApplication = application; |
1092 | @@ -422,9 +343,6 @@ |
1093 | Q_EMIT focusedApplicationIdChanged(); |
1094 | m_dbusWindowStack->FocusedWindowChanged(0, application->appId(), application->stage()); |
1095 | |
1096 | - // FIXME(dandrader): lying here. The operation is async. So we will only know whether |
1097 | - // the focusing was successful once the server replies. Maybe the API in unity-api should |
1098 | - // reflect that? |
1099 | return true; |
1100 | } |
1101 | |
1102 | @@ -432,9 +350,6 @@ |
1103 | { |
1104 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::unfocusCurrentApplication"; |
1105 | |
1106 | - suspendApplication(m_sideStageApplication); |
1107 | - suspendApplication(m_mainStageApplication); |
1108 | - |
1109 | m_focusedApplication = nullptr; |
1110 | Q_EMIT focusedApplicationIdChanged(); |
1111 | } |
1112 | @@ -484,10 +399,8 @@ |
1113 | application->setArguments(arguments); |
1114 | } else { |
1115 | application = new Application( |
1116 | - m_taskController, |
1117 | m_sharedWakelock, |
1118 | m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)), |
1119 | - Application::Starting, |
1120 | arguments, |
1121 | this); |
1122 | |
1123 | @@ -514,10 +427,8 @@ |
1124 | Application *application = findApplication(appId); |
1125 | if (!application) { // then shell did not start this application, so ubuntu-app-launch must have - add to list |
1126 | application = new Application( |
1127 | - m_taskController, |
1128 | m_sharedWakelock, |
1129 | m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)), |
1130 | - Application::Starting, |
1131 | QStringList(), |
1132 | this); |
1133 | |
1134 | @@ -530,17 +441,17 @@ |
1135 | Q_EMIT focusRequested(appId); |
1136 | } |
1137 | else { |
1138 | - // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned |
1139 | - // application and focus it immediately (as user expects app to still be running). |
1140 | if (application->state() == Application::Stopped) { |
1141 | + // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned |
1142 | + // application and focus it immediately (as user expects app to still be running). |
1143 | qCDebug(QTMIR_APPLICATIONS) << "Stopped application appId=" << appId << "is being resumed externally"; |
1144 | - application->setState(Application::Starting); |
1145 | Q_EMIT focusRequested(appId); |
1146 | } else { |
1147 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting application already found with appId" |
1148 | << appId; |
1149 | } |
1150 | } |
1151 | + application->setProcessState(Application::ProcessRunning); |
1152 | } |
1153 | |
1154 | /** |
1155 | @@ -559,14 +470,7 @@ |
1156 | return false; |
1157 | } |
1158 | |
1159 | - if (application == m_focusedApplication) { |
1160 | - // unfocus, and let shell decide what next to focus |
1161 | - m_focusedApplication = nullptr; |
1162 | - Q_EMIT focusedApplicationIdChanged(); |
1163 | - } |
1164 | - |
1165 | remove(application); |
1166 | - m_dbusWindowStack->WindowDestroyed(0, appId); |
1167 | |
1168 | bool result = m_taskController->stop(application->longAppId()); |
1169 | |
1170 | @@ -583,10 +487,7 @@ |
1171 | |
1172 | void ApplicationManager::onProcessFailed(const QString &appId, const bool duringStartup) |
1173 | { |
1174 | - /* Applications fail if they fail to launch, crash or are killed. If failed to start, must |
1175 | - * immediately remove from list of applications. If crash or kill, instead we set flag on the |
1176 | - * Application to indicate it can be resumed. |
1177 | - */ |
1178 | + // Applications fail if they fail to launch, crash or are killed. |
1179 | |
1180 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessFailed - appId=" << appId << "duringStartup=" << duringStartup; |
1181 | |
1182 | @@ -598,20 +499,8 @@ |
1183 | } |
1184 | |
1185 | Q_UNUSED(duringStartup); // FIXME(greyback) upstart reports app that fully started up & crashes as failing during startup?? |
1186 | - if (application->state() == Application::Starting) { |
1187 | - if (application == m_focusedApplication) { |
1188 | - m_focusedApplication = nullptr; |
1189 | - Q_EMIT focusedApplicationIdChanged(); |
1190 | - } |
1191 | - remove(application); |
1192 | - m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
1193 | - delete application; |
1194 | - } else { |
1195 | - // We need to set flags on the Application to say the app can be resumed, and thus should not be removed |
1196 | - // from the list by onProcessStopped. |
1197 | - application->setCanBeResumed(true); |
1198 | - application->setPid(0); |
1199 | - } |
1200 | + application->setProcessState(Application::ProcessStopped); |
1201 | + application->setPid(0); |
1202 | } |
1203 | |
1204 | void ApplicationManager::onProcessStopped(const QString &appId) |
1205 | @@ -626,29 +515,15 @@ |
1206 | return; |
1207 | } |
1208 | |
1209 | - // if shell did not stop the application, but ubuntu-app-launch says it died, we assume the process has been |
1210 | - // killed, so it can be respawned later. Only exception is if that application is focused or running |
1211 | - // as then it most likely crashed. Update this logic when ubuntu-app-launch gives some failure info. |
1212 | - bool removeApplication = true; |
1213 | - |
1214 | - if (application == m_focusedApplication) { |
1215 | - // Very bad case where focused application dies. Remove from list. Should give error message |
1216 | - m_focusedApplication = nullptr; |
1217 | - Q_EMIT focusedApplicationIdChanged(); |
1218 | - } |
1219 | - |
1220 | - // The following scenario is the only time that we do NOT remove the application from the app list: |
1221 | - if ((application->state() == Application::Suspended || application->state() == Application::Stopped) |
1222 | - && application->pid() == 0 // i.e. onProcessFailed was called, which resets the PID of this application |
1223 | - && application->canBeResumed()) { |
1224 | - removeApplication = false; |
1225 | - } |
1226 | - |
1227 | - if (removeApplication) { |
1228 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - removing appId=" << appId; |
1229 | - remove(application); |
1230 | - m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
1231 | - delete application; |
1232 | + application->setProcessState(Application::ProcessStopped); |
1233 | + application->setPid(0); |
1234 | +} |
1235 | + |
1236 | +void ApplicationManager::onProcessSuspended(const QString &appId) |
1237 | +{ |
1238 | + Application *application = findApplication(appId); |
1239 | + if (application) { |
1240 | + application->setProcessState(Application::ProcessSuspended); |
1241 | } |
1242 | } |
1243 | |
1244 | @@ -670,10 +545,10 @@ |
1245 | return; |
1246 | } |
1247 | |
1248 | - // If app Stopped, trust that ubuntu-app-launch respawns it itself, and AppManager will |
1249 | - // be notified of that through the onProcessStartReportReceived slot. Else resume. |
1250 | + // We interpret this as a focus request for a suspended app. |
1251 | + // Shell will have this app resumed if it complies with the focus request |
1252 | if (application->state() == Application::Suspended) { |
1253 | - application->setState(Application::Running); |
1254 | + Q_EMIT focusRequested(appId); |
1255 | } |
1256 | } |
1257 | |
1258 | @@ -693,7 +568,7 @@ |
1259 | void ApplicationManager::onSettingsChanged(const QString &key) |
1260 | { |
1261 | if (key == "lifecycleExemptAppids") { |
1262 | - m_lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList(); |
1263 | + Application::lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList(); |
1264 | } |
1265 | } |
1266 | |
1267 | @@ -732,7 +607,6 @@ |
1268 | |
1269 | if (info->startsWith("maliit-server") || info->contains("qt5/libexec/QtWebProcess")) { |
1270 | authorized = true; |
1271 | - m_hiddenPIDs << pid; |
1272 | return; |
1273 | } |
1274 | |
1275 | @@ -792,15 +666,12 @@ |
1276 | |
1277 | QStringList arguments(info->asStringList()); |
1278 | application = new Application( |
1279 | - m_taskController, |
1280 | m_sharedWakelock, |
1281 | desktopData, |
1282 | - Application::Starting, |
1283 | arguments, |
1284 | this); |
1285 | application->setPid(pid); |
1286 | application->setStage(stage); |
1287 | - application->setCanBeResumed(false); |
1288 | add(application); |
1289 | authorized = true; |
1290 | } |
1291 | @@ -812,66 +683,56 @@ |
1292 | |
1293 | void ApplicationManager::onSessionStopping(std::shared_ptr<ms::Session> const& session) |
1294 | { |
1295 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionStopping - sessionName=" << session->name().c_str(); |
1296 | - |
1297 | - // in case application closed not by hand of shell, check again here: |
1298 | Application* application = findApplicationWithSession(session); |
1299 | if (application) { |
1300 | - /* Can remove the application from the running apps list immediately in these curcumstances: |
1301 | - * 1. application is not managed by upstart (this message from Mir is only notice the app has stopped, must do |
1302 | - * it here) |
1303 | - * 2. application is managed by upstart, but has stopped before it managed to create a surface, we can assume |
1304 | - * it crashed on startup, and thus cannot be resumed - so remove it. |
1305 | - * 3. application is managed by upstart and is in foreground (i.e. has Running state), if Mir reports the |
1306 | - * application disconnects, it either crashed or stopped itself. Either case, remove it. |
1307 | - */ |
1308 | - if (!application->canBeResumed() |
1309 | - || application->state() == Application::Starting |
1310 | - || application->state() == Application::Running) { |
1311 | - m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
1312 | - remove(application); |
1313 | - |
1314 | - // (ricmm) -- To be on the safe side, better wipe the application QML compile cache if it crashes on startup |
1315 | - QString path(QDir::homePath() + QStringLiteral("/.cache/QML/Apps/")); |
1316 | - QDir dir(path); |
1317 | - QStringList apps = dir.entryList(); |
1318 | - for (int i = 0; i < apps.size(); i++) { |
1319 | - if (apps.at(i).contains(application->appId())) { |
1320 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionStopping appId=" << apps.at(i) << " Wiping QML Cache"; |
1321 | - dir.cd(apps.at(i)); |
1322 | - dir.removeRecursively(); |
1323 | - break; |
1324 | - } |
1325 | - } |
1326 | - |
1327 | - delete application; |
1328 | - |
1329 | - if (application == m_focusedApplication) { |
1330 | - m_focusedApplication = nullptr; |
1331 | - Q_EMIT focusedApplicationIdChanged(); |
1332 | - } |
1333 | + m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
1334 | + } |
1335 | +} |
1336 | + |
1337 | +void ApplicationManager::onSessionAboutToCreateSurface(const std::shared_ptr<mir::scene::Session> &session, |
1338 | + qtmir::SurfaceParameters ¶ms) |
1339 | +{ |
1340 | + qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionAboutToCreateSurface - sessionName=" |
1341 | + << session->name().c_str() << "geometry=" << params.geometry |
1342 | + << "state" << params.state; |
1343 | + |
1344 | + if (m_surfaceAboutToBeCreatedCallback.isCallable()) { |
1345 | + QJSValue argument = m_jsEngine->newObject(); |
1346 | + argument.setProperty("width", params.geometry.width()); |
1347 | + argument.setProperty("height", params.geometry.height()); |
1348 | + argument.setProperty("state", params.state); |
1349 | + |
1350 | + Application* application = findApplicationWithSession(session.get()); |
1351 | + if (application) |
1352 | + argument.setProperty("appId", application->appId()); |
1353 | + |
1354 | + QJSValue output = m_surfaceAboutToBeCreatedCallback.call(QJSValueList() << argument); |
1355 | + if (output.isObject()) { |
1356 | + QJSValue width = output.property("width"); |
1357 | + QJSValue height = output.property("height"); |
1358 | + QJSValue state = output.property("state"); |
1359 | + if (width.isNumber()) |
1360 | + params.geometry.setWidth(width.toInt()); |
1361 | + if (height.isNumber()) |
1362 | + params.geometry.setHeight(height.toInt()); |
1363 | + if (state.isNumber()) |
1364 | + params.state = static_cast<Globals::SurfaceState>(state.toInt()); |
1365 | } else { |
1366 | - // otherwise, we do not have enough information to make any changes to the model, so await events from |
1367 | - // upstart to go further, but set the app state |
1368 | - application->setState(Application::Stopped); |
1369 | + qWarning() << "ApplicationManager::onSessionAboutToCreateSurface - unrecognised object returned from JS callback!!" |
1370 | + << "Surface size has *not* been overridden by shell!"; |
1371 | } |
1372 | } |
1373 | - m_hiddenPIDs.removeOne(session->process_id()); |
1374 | } |
1375 | |
1376 | -void ApplicationManager::onSessionCreatedSurface(ms::Session const* session, |
1377 | - std::shared_ptr<ms::Surface> const& surface) |
1378 | +void ApplicationManager::onSessionCreatedSurface(const ms::Session *session, |
1379 | + const std::shared_ptr<ms::Surface> &surface) |
1380 | { |
1381 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionCreatedSurface - sessionName=" << session->name().c_str(); |
1382 | Q_UNUSED(surface); |
1383 | |
1384 | Application* application = findApplicationWithSession(session); |
1385 | - if (application && application->state() == Application::Starting) { |
1386 | + if (application) { |
1387 | m_dbusWindowStack->WindowCreated(0, application->appId()); |
1388 | - application->setState(Application::Running); |
1389 | - if ((application != m_mainStageApplication && application != m_sideStageApplication) || m_suspended) { |
1390 | - suspendApplication(application); |
1391 | - } |
1392 | } |
1393 | } |
1394 | |
1395 | @@ -900,16 +761,6 @@ |
1396 | return nullptr; |
1397 | } |
1398 | |
1399 | -Application* ApplicationManager::applicationForStage(Application::Stage stage) |
1400 | -{ |
1401 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::focusedApplicationForStage" << stage; |
1402 | - |
1403 | - if (stage == Application::MainStage) |
1404 | - return m_mainStageApplication; |
1405 | - else |
1406 | - return m_sideStageApplication; |
1407 | -} |
1408 | - |
1409 | void ApplicationManager::add(Application* application) |
1410 | { |
1411 | Q_ASSERT(application != nullptr); |
1412 | @@ -920,6 +771,28 @@ |
1413 | connect(application, &Application::stateChanged, this, [this](Application::State) { onAppDataChanged(RoleState); }); |
1414 | connect(application, &Application::stageChanged, this, [this](Application::Stage) { onAppDataChanged(RoleStage); }); |
1415 | |
1416 | + QString appId = application->appId(); |
1417 | + QString longAppId = application->longAppId(); |
1418 | + QStringList arguments = application->arguments(); |
1419 | + |
1420 | + // The connection is queued as a workaround an issue in the PhoneStage animation that |
1421 | + // happens when you tap on a killed app in the spread to bring it to foreground, causing |
1422 | + // a Application::respawn() to take place. |
1423 | + // In any case, it seems like in general QML works better when don't do too many things |
1424 | + // in the same event loop iteration. |
1425 | + connect(application, &Application::startProcessRequested, |
1426 | + this, [=]() { m_taskController->start(appId, arguments); }, |
1427 | + Qt::QueuedConnection); |
1428 | + |
1429 | + connect(application, &Application::suspendProcessRequested, this, [=]() { m_taskController->suspend(longAppId); } ); |
1430 | + connect(application, &Application::resumeProcessRequested, this, [=]() { m_taskController->resume(longAppId); } ); |
1431 | + |
1432 | + connect(application, &Application::stopped, this, [=]() { |
1433 | + remove(application); |
1434 | + application->deleteLater(); |
1435 | + }); |
1436 | + |
1437 | + |
1438 | beginInsertRows(QModelIndex(), m_applications.count(), m_applications.count()); |
1439 | m_applications.append(application); |
1440 | endInsertRows(); |
1441 | @@ -935,11 +808,6 @@ |
1442 | Q_ASSERT(application != nullptr); |
1443 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::remove - appId=" << application->appId(); |
1444 | |
1445 | - if (application == m_sideStageApplication) |
1446 | - m_sideStageApplication = nullptr; |
1447 | - if (application == m_mainStageApplication) |
1448 | - m_mainStageApplication = nullptr; |
1449 | - |
1450 | application->disconnect(this); |
1451 | |
1452 | int i = m_applications.indexOf(application); |
1453 | @@ -953,6 +821,11 @@ |
1454 | Q_EMIT emptyChanged(); |
1455 | } |
1456 | } |
1457 | + |
1458 | + if (application == m_focusedApplication) { |
1459 | + m_focusedApplication = nullptr; |
1460 | + Q_EMIT focusedApplicationIdChanged(); |
1461 | + } |
1462 | } |
1463 | |
1464 | void ApplicationManager::move(int from, int to) { |
1465 | |
1466 | === modified file 'src/modules/Unity/Application/application_manager.h' |
1467 | --- src/modules/Unity/Application/application_manager.h 2015-03-24 23:38:33 +0000 |
1468 | +++ src/modules/Unity/Application/application_manager.h 2015-07-13 21:57:32 +0000 |
1469 | @@ -1,5 +1,5 @@ |
1470 | /* |
1471 | - * Copyright (C) 2013 Canonical, Ltd. |
1472 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
1473 | * |
1474 | * This program is free software: you can redistribute it and/or modify it under |
1475 | * the terms of the GNU Lesser General Public License version 3, as published by |
1476 | @@ -21,6 +21,7 @@ |
1477 | #include <memory> |
1478 | |
1479 | // Qt |
1480 | +#include <QJSEngine> |
1481 | #include <QObject> |
1482 | #include <QStringList> |
1483 | |
1484 | @@ -28,6 +29,7 @@ |
1485 | #include <unity/shell/application/ApplicationManagerInterface.h> |
1486 | |
1487 | // local |
1488 | +#include "globals.h" |
1489 | #include "application.h" |
1490 | #include "desktopfilereader.h" |
1491 | |
1492 | @@ -40,6 +42,7 @@ |
1493 | } |
1494 | |
1495 | class MirServer; |
1496 | +class QJSValue; |
1497 | |
1498 | namespace qtmir { |
1499 | |
1500 | @@ -63,7 +66,7 @@ |
1501 | class Factory |
1502 | { |
1503 | public: |
1504 | - ApplicationManager* create(); |
1505 | + ApplicationManager* create(QJSEngine *jsEngine); |
1506 | }; |
1507 | |
1508 | // FIXME: these roles should be added to unity-api and removed from here |
1509 | @@ -79,7 +82,7 @@ |
1510 | }; |
1511 | Q_DECLARE_FLAGS(ExecFlags, Flag) |
1512 | |
1513 | - static ApplicationManager* singleton(); |
1514 | + static ApplicationManager* singleton(QJSEngine *jsEngine); |
1515 | |
1516 | explicit ApplicationManager( |
1517 | const QSharedPointer<MirServer> &mirServer, |
1518 | @@ -88,15 +91,16 @@ |
1519 | const QSharedPointer<DesktopFileReader::Factory> &desktopFileReaderFactory, |
1520 | const QSharedPointer<ProcInfo> &processInfo, |
1521 | const QSharedPointer<SettingsInterface> &settings, |
1522 | + QJSEngine *jsEngine, |
1523 | QObject *parent = 0); |
1524 | virtual ~ApplicationManager(); |
1525 | |
1526 | // ApplicationManagerInterface |
1527 | QString focusedApplicationId() const override; |
1528 | - bool suspended() const override; |
1529 | - void setSuspended(bool suspended) override; |
1530 | - bool forceDashActive() const override; |
1531 | - void setForceDashActive(bool forceDashActive) override; |
1532 | + |
1533 | + QJSValue surfaceAboutToBeCreatedCallback() const override; |
1534 | + void setSurfaceAboutToBeCreatedCallback(const QJSValue &callback) override; |
1535 | + |
1536 | Q_INVOKABLE qtmir::Application* get(int index) const override; |
1537 | Q_INVOKABLE qtmir::Application* findApplication(const QString &appId) const override; |
1538 | Q_INVOKABLE bool requestFocusApplication(const QString &appId) override; |
1539 | @@ -110,7 +114,7 @@ |
1540 | QVariant data(const QModelIndex & index, int role) const override; |
1541 | |
1542 | Q_INVOKABLE qtmir::Application *startApplication(const QString &appId, ExecFlags flags, |
1543 | - const QStringList &arguments = QStringList()); |
1544 | + const QStringList &arguments = QStringList()); |
1545 | Q_INVOKABLE void move(int from, int to); |
1546 | |
1547 | bool isEmpty() const { return rowCount() == 0; } |
1548 | @@ -121,20 +125,24 @@ |
1549 | public Q_SLOTS: |
1550 | void authorizeSession(const quint64 pid, bool &authorized); |
1551 | |
1552 | - void onSessionStarting(std::shared_ptr<mir::scene::Session> const& session); |
1553 | - void onSessionStopping(std::shared_ptr<mir::scene::Session> const& session); |
1554 | + void onSessionStarting(const std::shared_ptr<mir::scene::Session> &session); |
1555 | + void onSessionStopping(const std::shared_ptr<mir::scene::Session> &session); |
1556 | |
1557 | - void onSessionCreatedSurface(mir::scene::Session const*, std::shared_ptr<mir::scene::Surface> const&); |
1558 | + void onSessionAboutToCreateSurface(const std::shared_ptr<mir::scene::Session> &session, |
1559 | + SurfaceParameters &surfaceParameters); |
1560 | + void onSessionCreatedSurface(const mir::scene::Session *session, |
1561 | + const std::shared_ptr<mir::scene::Surface> &surface); |
1562 | |
1563 | void onProcessStarting(const QString& appId); |
1564 | void onProcessStopped(const QString& appId); |
1565 | + void onProcessSuspended(const QString& appId); |
1566 | void onProcessFailed(const QString& appId, const bool duringStartup); |
1567 | void onFocusRequested(const QString& appId); |
1568 | void onResumeRequested(const QString& appId); |
1569 | |
1570 | Q_SIGNALS: |
1571 | - void focusRequested(const QString &appId); |
1572 | void emptyChanged(); |
1573 | + void surfaceAboutToBeCreatedCallbackChanged(); |
1574 | |
1575 | private Q_SLOTS: |
1576 | void onAppDataChanged(const int role); |
1577 | @@ -146,9 +154,7 @@ |
1578 | void remove(Application* application); |
1579 | Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session); |
1580 | Application* findApplicationWithSession(const mir::scene::Session *session); |
1581 | - Application* applicationForStage(Application::Stage stage); |
1582 | QModelIndex findIndex(Application* application); |
1583 | - bool suspendApplication(Application *application); |
1584 | void resumeApplication(Application *application); |
1585 | QString toString() const; |
1586 | |
1587 | @@ -158,19 +164,15 @@ |
1588 | |
1589 | QList<Application*> m_applications; |
1590 | Application* m_focusedApplication; |
1591 | - Application* m_mainStageApplication; |
1592 | - Application* m_sideStageApplication; |
1593 | - QStringList m_lifecycleExceptions; |
1594 | DBusWindowStack* m_dbusWindowStack; |
1595 | QSharedPointer<TaskController> m_taskController; |
1596 | QSharedPointer<DesktopFileReader::Factory> m_desktopFileReaderFactory; |
1597 | QSharedPointer<ProcInfo> m_procInfo; |
1598 | QSharedPointer<SharedWakelock> m_sharedWakelock; |
1599 | QSharedPointer<SettingsInterface> m_settings; |
1600 | + QJSValue m_surfaceAboutToBeCreatedCallback; |
1601 | + QJSEngine *m_jsEngine; |
1602 | static ApplicationManager* the_application_manager; |
1603 | - QList<pid_t> m_hiddenPIDs; |
1604 | - bool m_suspended; |
1605 | - bool m_forceDashActive; |
1606 | |
1607 | friend class Application; |
1608 | friend class DBusWindowStack; |
1609 | |
1610 | === modified file 'src/modules/Unity/Application/applicationcontroller.h' |
1611 | --- src/modules/Unity/Application/applicationcontroller.h 2014-09-18 22:03:02 +0000 |
1612 | +++ src/modules/Unity/Application/applicationcontroller.h 2015-07-13 21:57:32 +0000 |
1613 | @@ -57,8 +57,9 @@ |
1614 | void applicationAboutToBeStarted(const QString &appId); |
1615 | void applicationStarted(const QString &appId); |
1616 | void applicationStopped(const QString &appId); |
1617 | + void applicationPaused(const QString &appId); |
1618 | void applicationFocusRequest(const QString &appId); |
1619 | - void applicationResumeRequest(const QString &appId); |
1620 | + void applicationResumeRequested(const QString &appId); |
1621 | |
1622 | void applicationError(const QString &appId, ApplicationController::Error error); |
1623 | |
1624 | |
1625 | === modified file 'src/modules/Unity/Application/applicationscreenshotprovider.cpp' |
1626 | --- src/modules/Unity/Application/applicationscreenshotprovider.cpp 2014-09-18 09:38:41 +0000 |
1627 | +++ src/modules/Unity/Application/applicationscreenshotprovider.cpp 2015-07-13 21:57:32 +0000 |
1628 | @@ -55,7 +55,7 @@ |
1629 | |
1630 | // TODO: if app not ready, return an app-provided splash image. If app has been stopped with saved state |
1631 | // return the screenshot that was saved to disk. |
1632 | - Session* session = app->session(); |
1633 | + SessionInterface* session = app->session(); |
1634 | if (!session || !session->session() || !session->session()->default_surface()) { |
1635 | qWarning() << "ApplicationScreenshotProvider - app session not found - asking for screenshot too early"; |
1636 | return QImage(); |
1637 | |
1638 | === modified file 'src/modules/Unity/Application/mirsurfaceitem.cpp' |
1639 | --- src/modules/Unity/Application/mirsurfaceitem.cpp 2015-05-21 18:38:27 +0000 |
1640 | +++ src/modules/Unity/Application/mirsurfaceitem.cpp 2015-07-13 21:57:32 +0000 |
1641 | @@ -190,13 +190,13 @@ |
1642 | MirShell *shell, |
1643 | std::shared_ptr<SurfaceObserver> observer, |
1644 | QQuickItem *parent) |
1645 | - : QQuickItem(parent) |
1646 | + : MirSurfaceItemInterface(parent) |
1647 | , m_surface(surface) |
1648 | , m_session(session) |
1649 | , m_shell(shell) |
1650 | , m_firstFrameDrawn(false) |
1651 | , m_live(true) |
1652 | - , m_orientationAngle(Angle0) |
1653 | + , m_orientationAngle(Globals::Angle0) |
1654 | , m_textureProvider(nullptr) |
1655 | , m_lastTouchEvent(nullptr) |
1656 | { |
1657 | @@ -296,22 +296,22 @@ |
1658 | return m_session.data(); |
1659 | } |
1660 | |
1661 | -MirSurfaceItem::Type MirSurfaceItem::type() const |
1662 | -{ |
1663 | - return static_cast<MirSurfaceItem::Type>(m_surface->type()); |
1664 | -} |
1665 | - |
1666 | -MirSurfaceItem::State MirSurfaceItem::state() const |
1667 | -{ |
1668 | - return static_cast<MirSurfaceItem::State>(m_surface->state()); |
1669 | -} |
1670 | - |
1671 | -MirSurfaceItem::OrientationAngle MirSurfaceItem::orientationAngle() const |
1672 | +Globals::SurfaceType MirSurfaceItem::type() const |
1673 | +{ |
1674 | + return static_cast<Globals::SurfaceType>(m_surface->type()); |
1675 | +} |
1676 | + |
1677 | +Globals::SurfaceState MirSurfaceItem::state() const |
1678 | +{ |
1679 | + return static_cast<Globals::SurfaceState>(m_surface->state()); |
1680 | +} |
1681 | + |
1682 | +Globals::OrientationAngle MirSurfaceItem::orientationAngle() const |
1683 | { |
1684 | return m_orientationAngle; |
1685 | } |
1686 | |
1687 | -void MirSurfaceItem::setOrientationAngle(MirSurfaceItem::OrientationAngle angle) |
1688 | +void MirSurfaceItem::setOrientationAngle(Globals::OrientationAngle angle) |
1689 | { |
1690 | qCDebug(QTMIR_SURFACES, "MirSurfaceItem::setOrientationAngle(%d)", angle); |
1691 | |
1692 | @@ -321,16 +321,16 @@ |
1693 | MirOrientation mirOrientation; |
1694 | |
1695 | switch (angle) { |
1696 | - case Angle0: |
1697 | + case Globals::Angle0: |
1698 | mirOrientation = mir_orientation_normal; |
1699 | break; |
1700 | - case Angle90: |
1701 | + case Globals::Angle90: |
1702 | mirOrientation = mir_orientation_right; |
1703 | break; |
1704 | - case Angle180: |
1705 | + case Globals::Angle180: |
1706 | mirOrientation = mir_orientation_inverted; |
1707 | break; |
1708 | - case Angle270: |
1709 | + case Globals::Angle270: |
1710 | mirOrientation = mir_orientation_left; |
1711 | break; |
1712 | default: |
1713 | @@ -375,7 +375,7 @@ |
1714 | { |
1715 | if (!m_firstFrameDrawn) { |
1716 | m_firstFrameDrawn = true; |
1717 | - Q_EMIT firstFrameDrawn(this); |
1718 | + Q_EMIT firstFrameDrawn(); |
1719 | } |
1720 | |
1721 | scheduleTextureUpdate(); |
1722 | @@ -456,7 +456,7 @@ |
1723 | |
1724 | void MirSurfaceItem::mousePressEvent(QMouseEvent *event) |
1725 | { |
1726 | - if (type() == InputMethod) { |
1727 | + if (type() == Globals::SurfaceType::InputMethod) { |
1728 | // FIXME: Hack to get the VKB use case working while we don't have the proper solution in place. |
1729 | if (isMouseInsideUbuntuKeyboard(event)) { |
1730 | auto ev = makeMirEvent(event, mir_pointer_action_button_down); |
1731 | @@ -562,7 +562,7 @@ |
1732 | |
1733 | touchEvent.updateTouchPointStatesAndType(); |
1734 | |
1735 | - auto ev = makeMirEvent(touchEvent.modifiers, touchEvent.touchPoints, |
1736 | + auto ev = makeMirEvent(touchEvent.modifiers, touchEvent.touchPoints, |
1737 | touchEvent.touchPointStates, touchEvent.timestamp); |
1738 | m_surface->consume(*ev); |
1739 | |
1740 | @@ -615,7 +615,7 @@ |
1741 | Qt::TouchPointStates touchPointStates) |
1742 | { |
1743 | bool accepted = true; |
1744 | - if (type() == InputMethod && eventType == QEvent::TouchBegin) { |
1745 | + if (type() == Globals::SurfaceType::InputMethod && eventType == QEvent::TouchBegin) { |
1746 | // FIXME: Hack to get the VKB use case working while we don't have the proper solution in place. |
1747 | if (hasTouchInsideUbuntuKeyboard(touchPoints)) { |
1748 | validateAndDeliverTouchEvent(eventType, timestamp, mods, touchPoints, touchPointStates); |
1749 | @@ -659,21 +659,21 @@ |
1750 | && pos.y() <= (ubuntuKeyboardInfo->y() + ubuntuKeyboardInfo->height()); |
1751 | } |
1752 | |
1753 | -void MirSurfaceItem::setType(const Type &type) |
1754 | +void MirSurfaceItem::setType(const Globals::SurfaceType &type) |
1755 | { |
1756 | if (this->type() != type) { |
1757 | m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_type, static_cast<int>(type)); |
1758 | } |
1759 | } |
1760 | |
1761 | -void MirSurfaceItem::setState(const State &state) |
1762 | +void MirSurfaceItem::setState(const Globals::SurfaceState &state) |
1763 | { |
1764 | if (this->state() != state) { |
1765 | m_shell->set_surface_attribute(m_session->session(), m_surface, mir_surface_attrib_state, static_cast<int>(state)); |
1766 | } |
1767 | } |
1768 | |
1769 | -void MirSurfaceItem::setLive(const bool live) |
1770 | +void MirSurfaceItem::setLive(bool live) |
1771 | { |
1772 | if (m_live != live) { |
1773 | m_live = live; |
1774 | |
1775 | === modified file 'src/modules/Unity/Application/mirsurfaceitem.h' |
1776 | --- src/modules/Unity/Application/mirsurfaceitem.h 2015-05-13 17:18:45 +0000 |
1777 | +++ src/modules/Unity/Application/mirsurfaceitem.h 2015-07-13 21:57:32 +0000 |
1778 | @@ -22,15 +22,13 @@ |
1779 | // Qt |
1780 | #include <QMutex> |
1781 | #include <QPointer> |
1782 | -#include <QSet> |
1783 | -#include <QQuickItem> |
1784 | #include <QTimer> |
1785 | #include <QQmlListProperty> |
1786 | |
1787 | // mir |
1788 | #include <mir/scene/surface.h> |
1789 | -#include <mir_toolkit/common.h> |
1790 | |
1791 | +#include "mirsurfaceiteminterface.h" |
1792 | #include "session_interface.h" |
1793 | |
1794 | class SurfaceObserver; |
1795 | @@ -41,24 +39,10 @@ |
1796 | class MirSurfaceManager; |
1797 | class QSGMirSurfaceNode; |
1798 | class QMirSurfaceTextureProvider; |
1799 | -class Application; |
1800 | |
1801 | -class MirSurfaceItem : public QQuickItem |
1802 | +class MirSurfaceItem : public MirSurfaceItemInterface |
1803 | { |
1804 | Q_OBJECT |
1805 | - Q_ENUMS(Type) |
1806 | - Q_ENUMS(State) |
1807 | - Q_ENUMS(OrientationAngle) |
1808 | - |
1809 | - Q_PROPERTY(Type type READ type NOTIFY typeChanged) |
1810 | - Q_PROPERTY(State state READ state NOTIFY stateChanged) |
1811 | - Q_PROPERTY(QString name READ name NOTIFY nameChanged) |
1812 | - Q_PROPERTY(bool live READ live NOTIFY liveChanged) |
1813 | - |
1814 | - // How many degrees, clockwise, the UI in the surface has to rotate to match with the |
1815 | - // shell UI orientation |
1816 | - Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle |
1817 | - NOTIFY orientationAngleChanged DESIGNABLE false) |
1818 | |
1819 | public: |
1820 | explicit MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface, |
1821 | @@ -66,57 +50,29 @@ |
1822 | MirShell *shell, |
1823 | std::shared_ptr<SurfaceObserver> observer, |
1824 | QQuickItem *parent = 0); |
1825 | - ~MirSurfaceItem(); |
1826 | - |
1827 | - enum Type { |
1828 | - Normal = mir_surface_type_normal, |
1829 | - Utility = mir_surface_type_utility, |
1830 | - Dialog = mir_surface_type_dialog, |
1831 | - Overlay = mir_surface_type_overlay, |
1832 | - Freestyle = mir_surface_type_freestyle, |
1833 | - Popover = mir_surface_type_popover, |
1834 | - InputMethod = mir_surface_type_inputmethod, |
1835 | - }; |
1836 | - |
1837 | - enum State { |
1838 | - Unknown = mir_surface_state_unknown, |
1839 | - Restored = mir_surface_state_restored, |
1840 | - Minimized = mir_surface_state_minimized, |
1841 | - Maximized = mir_surface_state_maximized, |
1842 | - VertMaximized = mir_surface_state_vertmaximized, |
1843 | - /* SemiMaximized = mir_surface_state_semimaximized, // see mircommon/mir_toolbox/common.h*/ |
1844 | - Fullscreen = mir_surface_state_fullscreen, |
1845 | - }; |
1846 | - |
1847 | - enum OrientationAngle { |
1848 | - Angle0 = 0, |
1849 | - Angle90 = 90, |
1850 | - Angle180 = 180, |
1851 | - Angle270 = 270 |
1852 | - }; |
1853 | + virtual ~MirSurfaceItem(); |
1854 | |
1855 | //getters |
1856 | - Type type() const; |
1857 | - State state() const; |
1858 | - QString name() const; |
1859 | - bool live() const; |
1860 | - SessionInterface *session() const; |
1861 | + Globals::SurfaceType type() const override; |
1862 | + Globals::SurfaceState state() const override; |
1863 | + QString name() const override; |
1864 | + bool live() const override; |
1865 | + SessionInterface *session() const override; |
1866 | + Globals::OrientationAngle orientationAngle() const override; |
1867 | |
1868 | - Q_INVOKABLE void release(); |
1869 | + Q_INVOKABLE void release() override; |
1870 | |
1871 | // Item surface/texture management |
1872 | bool isTextureProvider() const { return true; } |
1873 | QSGTextureProvider *textureProvider() const; |
1874 | |
1875 | - void stopFrameDropper(); |
1876 | - void startFrameDropper(); |
1877 | - |
1878 | - bool isFirstFrameDrawn() const { return m_firstFrameDrawn; } |
1879 | - |
1880 | - OrientationAngle orientationAngle() const; |
1881 | - void setOrientationAngle(OrientationAngle angle); |
1882 | - |
1883 | - void setSession(SessionInterface *app); |
1884 | + void stopFrameDropper() override; |
1885 | + void startFrameDropper() override; |
1886 | + |
1887 | + bool isFirstFrameDrawn() const override { return m_firstFrameDrawn; } |
1888 | + |
1889 | + void setOrientationAngle(Globals::OrientationAngle angle) override; |
1890 | + void setSession(SessionInterface *app) override; |
1891 | |
1892 | // to allow easy touch event injection from tests |
1893 | bool processTouchEvent(int eventType, |
1894 | @@ -125,14 +81,6 @@ |
1895 | const QList<QTouchEvent::TouchPoint> &touchPoints, |
1896 | Qt::TouchPointStates touchPointStates); |
1897 | |
1898 | -Q_SIGNALS: |
1899 | - void typeChanged(); |
1900 | - void stateChanged(); |
1901 | - void nameChanged(); |
1902 | - void orientationAngleChanged(OrientationAngle angle); |
1903 | - void liveChanged(bool live); |
1904 | - void firstFrameDrawn(MirSurfaceItem *item); |
1905 | - |
1906 | protected Q_SLOTS: |
1907 | void onSessionStateChanged(SessionInterface::State state); |
1908 | |
1909 | @@ -167,9 +115,9 @@ |
1910 | bool updateTexture(); |
1911 | void ensureProvider(); |
1912 | |
1913 | - void setType(const Type&); |
1914 | - void setState(const State&); |
1915 | - void setLive(const bool); |
1916 | + void setType(const Globals::SurfaceType&); |
1917 | + void setState(const Globals::SurfaceState&); |
1918 | + void setLive(bool) override; |
1919 | |
1920 | // called by MirSurfaceManager |
1921 | void setSurfaceValid(const bool); |
1922 | @@ -197,7 +145,7 @@ |
1923 | bool m_live; |
1924 | |
1925 | //FIXME - have to save the state as Mir has no getter for it (bug:1357429) |
1926 | - OrientationAngle m_orientationAngle; |
1927 | + Globals::OrientationAngle m_orientationAngle; |
1928 | |
1929 | QMirSurfaceTextureProvider *m_textureProvider; |
1930 | |
1931 | @@ -226,13 +174,8 @@ |
1932 | QList<QTouchEvent::TouchPoint> touchPoints; |
1933 | Qt::TouchPointStates touchPointStates; |
1934 | } *m_lastTouchEvent; |
1935 | - |
1936 | - friend class MirSurfaceManager; |
1937 | }; |
1938 | |
1939 | } // namespace qtmir |
1940 | |
1941 | -Q_DECLARE_METATYPE(qtmir::MirSurfaceItem*) |
1942 | -Q_DECLARE_METATYPE(qtmir::MirSurfaceItem::OrientationAngle) |
1943 | - |
1944 | #endif // MIRSURFACEITEM_H |
1945 | |
1946 | === added file 'src/modules/Unity/Application/mirsurfaceiteminterface.h' |
1947 | --- src/modules/Unity/Application/mirsurfaceiteminterface.h 1970-01-01 00:00:00 +0000 |
1948 | +++ src/modules/Unity/Application/mirsurfaceiteminterface.h 2015-07-13 21:57:32 +0000 |
1949 | @@ -0,0 +1,89 @@ |
1950 | +/* |
1951 | + * Copyright (C) 2015 Canonical, Ltd. |
1952 | + * |
1953 | + * This program is free software: you can redistribute it and/or modify it under |
1954 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1955 | + * the Free Software Foundation. |
1956 | + * |
1957 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1958 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1959 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1960 | + * Lesser General Public License for more details. |
1961 | + * |
1962 | + * You should have received a copy of the GNU Lesser General Public License |
1963 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1964 | + */ |
1965 | + |
1966 | +#ifndef MIRSURFACEITEMINTERFACE_H |
1967 | +#define MIRSURFACEITEMINTERFACE_H |
1968 | + |
1969 | +// Qt |
1970 | +#include <QQuickItem> |
1971 | + |
1972 | +// mir |
1973 | +#include <mir_toolkit/common.h> |
1974 | + |
1975 | +#include "session_interface.h" |
1976 | +#include "globals.h" |
1977 | + |
1978 | +namespace qtmir { |
1979 | + |
1980 | +class MirSurfaceItemInterface : public QQuickItem |
1981 | +{ |
1982 | + Q_OBJECT |
1983 | + Q_ENUMS(Type) |
1984 | + Q_ENUMS(State) |
1985 | + Q_ENUMS(OrientationAngle) |
1986 | + |
1987 | + Q_PROPERTY(qtmir::Globals::SurfaceType type READ type NOTIFY typeChanged) |
1988 | + Q_PROPERTY(qtmir::Globals::SurfaceState state READ state NOTIFY stateChanged) |
1989 | + Q_PROPERTY(QString name READ name NOTIFY nameChanged) |
1990 | + Q_PROPERTY(bool live READ live NOTIFY liveChanged) |
1991 | + |
1992 | + // How many degrees, clockwise, the UI in the surface has to rotate to match with the |
1993 | + // shell UI orientation |
1994 | + Q_PROPERTY(qtmir::Globals::OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle |
1995 | + NOTIFY orientationAngleChanged DESIGNABLE false) |
1996 | + |
1997 | +public: |
1998 | + MirSurfaceItemInterface(QQuickItem *parent) : QQuickItem(parent) {} |
1999 | + virtual ~MirSurfaceItemInterface() {} |
2000 | + |
2001 | + //getters |
2002 | + virtual Globals::SurfaceType type() const = 0; |
2003 | + virtual Globals::SurfaceState state() const = 0; |
2004 | + virtual QString name() const = 0; |
2005 | + virtual bool live() const = 0; |
2006 | + virtual SessionInterface *session() const = 0; |
2007 | + virtual Globals::OrientationAngle orientationAngle() const = 0; |
2008 | + |
2009 | + virtual Q_INVOKABLE void release() = 0; |
2010 | + |
2011 | + virtual void stopFrameDropper() = 0; |
2012 | + virtual void startFrameDropper() = 0; |
2013 | + |
2014 | + virtual bool isFirstFrameDrawn() const = 0; |
2015 | + |
2016 | + virtual void setOrientationAngle(Globals::OrientationAngle angle) = 0; |
2017 | + virtual void setSession(SessionInterface *app) = 0; |
2018 | + |
2019 | +Q_SIGNALS: |
2020 | + void typeChanged(); |
2021 | + void stateChanged(); |
2022 | + void nameChanged(); |
2023 | + void orientationAngleChanged(Globals::OrientationAngle angle); |
2024 | + void liveChanged(bool live); |
2025 | + void firstFrameDrawn(); |
2026 | + |
2027 | +private: |
2028 | + virtual void setLive(bool) = 0; |
2029 | + |
2030 | + friend class MirSurfaceManager; |
2031 | +}; |
2032 | + |
2033 | +} // namespace qtmir |
2034 | + |
2035 | +Q_DECLARE_METATYPE(qtmir::MirSurfaceItemInterface*) |
2036 | + |
2037 | +#endif // MIRSURFACEITEMINTERFACE_H |
2038 | + |
2039 | |
2040 | === modified file 'src/modules/Unity/Application/mirsurfaceitemmodel.h' |
2041 | --- src/modules/Unity/Application/mirsurfaceitemmodel.h 2014-08-29 11:15:51 +0000 |
2042 | +++ src/modules/Unity/Application/mirsurfaceitemmodel.h 2015-07-13 21:57:32 +0000 |
2043 | @@ -22,8 +22,8 @@ |
2044 | |
2045 | namespace qtmir { |
2046 | |
2047 | -class MirSurfaceItem; |
2048 | -typedef ObjectListModel<MirSurfaceItem> MirSurfaceItemModel; |
2049 | +class MirSurfaceItemInterface; |
2050 | +typedef ObjectListModel<MirSurfaceItemInterface> MirSurfaceItemModel; |
2051 | |
2052 | } // namespace qtmir |
2053 | |
2054 | |
2055 | === modified file 'src/modules/Unity/Application/mirsurfacemanager.cpp' |
2056 | --- src/modules/Unity/Application/mirsurfacemanager.cpp 2015-03-11 10:10:49 +0000 |
2057 | +++ src/modules/Unity/Application/mirsurfacemanager.cpp 2015-07-13 21:57:32 +0000 |
2058 | @@ -51,7 +51,7 @@ |
2059 | manager, &MirSurfaceManager::onSessionDestroyingSurface); |
2060 | } |
2061 | |
2062 | -MirSurfaceManager* MirSurfaceManager::singleton() |
2063 | +MirSurfaceManager* MirSurfaceManager::singleton(QJSEngine *jsEngine) |
2064 | { |
2065 | if (!the_surface_manager) { |
2066 | |
2067 | @@ -66,7 +66,7 @@ |
2068 | SessionListener *sessionListener = static_cast<SessionListener*>(nativeInterface->nativeResourceForIntegration("SessionListener")); |
2069 | MirShell *shell = static_cast<MirShell*>(nativeInterface->nativeResourceForIntegration("Shell")); |
2070 | |
2071 | - the_surface_manager = new MirSurfaceManager(nativeInterface->m_mirServer, shell, SessionManager::singleton()); |
2072 | + the_surface_manager = new MirSurfaceManager(nativeInterface->m_mirServer, shell, SessionManager::singleton(jsEngine)); |
2073 | |
2074 | connectToSessionListener(the_surface_manager, sessionListener); |
2075 | } |
2076 | @@ -112,11 +112,11 @@ |
2077 | session->setSurface(qmlSurface); |
2078 | |
2079 | // Only notify QML of surface creation once it has drawn its first frame. |
2080 | - connect(qmlSurface, &MirSurfaceItem::firstFrameDrawn, this, [&](MirSurfaceItem *item) { |
2081 | + connect(qmlSurface, &MirSurfaceItemInterface::firstFrameDrawn, this, [=]() { |
2082 | tracepoint(qtmir, firstFrameDrawn); |
2083 | - Q_EMIT surfaceCreated(item); |
2084 | + Q_EMIT surfaceCreated(qmlSurface); |
2085 | |
2086 | - insert(0, item); |
2087 | + insert(0, qmlSurface); |
2088 | }); |
2089 | |
2090 | // clean up after MirSurfaceItem is destroyed |
2091 | @@ -139,7 +139,7 @@ |
2092 | qCDebug(QTMIR_SURFACES) << "MirSurfaceManager::onSessionDestroyingSurface - session=" << session |
2093 | << "surface=" << surface.get() << "surface.name=" << surface->name().c_str(); |
2094 | |
2095 | - MirSurfaceItem* item = nullptr; |
2096 | + MirSurfaceItemInterface* item = nullptr; |
2097 | { |
2098 | QMutexLocker lock(&m_mutex); |
2099 | auto it = m_mirSurfaceToItemHash.find(surface.get()); |
2100 | |
2101 | === modified file 'src/modules/Unity/Application/mirsurfacemanager.h' |
2102 | --- src/modules/Unity/Application/mirsurfacemanager.h 2015-03-11 10:10:49 +0000 |
2103 | +++ src/modules/Unity/Application/mirsurfacemanager.h 2015-07-13 21:57:32 +0000 |
2104 | @@ -61,11 +61,11 @@ |
2105 | ); |
2106 | ~MirSurfaceManager(); |
2107 | |
2108 | - static MirSurfaceManager* singleton(); |
2109 | + static MirSurfaceManager* singleton(QJSEngine *jsEngine); |
2110 | |
2111 | Q_SIGNALS: |
2112 | - void surfaceCreated(MirSurfaceItem* surface); |
2113 | - void surfaceDestroyed(MirSurfaceItem* surface); |
2114 | + void surfaceCreated(MirSurfaceItemInterface* surface); |
2115 | + void surfaceDestroyed(MirSurfaceItemInterface* surface); |
2116 | // void surfaceResized(MirSurface*); |
2117 | // void fullscreenSurfaceChanged(); |
2118 | |
2119 | @@ -74,7 +74,7 @@ |
2120 | void onSessionDestroyingSurface(const mir::scene::Session *, const std::shared_ptr<mir::scene::Surface> &); |
2121 | |
2122 | protected: |
2123 | - QHash<const mir::scene::Surface *, MirSurfaceItem *> m_mirSurfaceToItemHash; |
2124 | + QHash<const mir::scene::Surface *, MirSurfaceItemInterface *> m_mirSurfaceToItemHash; |
2125 | QMutex m_mutex; |
2126 | |
2127 | private: |
2128 | |
2129 | === modified file 'src/modules/Unity/Application/plugin.cpp' |
2130 | --- src/modules/Unity/Application/plugin.cpp 2015-02-05 10:28:31 +0000 |
2131 | +++ src/modules/Unity/Application/plugin.cpp 2015-07-13 21:57:32 +0000 |
2132 | @@ -28,41 +28,36 @@ |
2133 | |
2134 | // qtmir |
2135 | #include "logging.h" |
2136 | - |
2137 | -using namespace qtmir; |
2138 | - |
2139 | -static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) { |
2140 | - Q_UNUSED(engine); |
2141 | - Q_UNUSED(scriptEngine); |
2142 | - qCDebug(QTMIR_APPLICATIONS) << "applicationManagerSingleton - engine=" << engine << "scriptEngine=" << scriptEngine; |
2143 | - |
2144 | - return qtmir::ApplicationManager::singleton(); |
2145 | -} |
2146 | - |
2147 | -static QObject* surfaceManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) { |
2148 | - Q_UNUSED(engine); |
2149 | - Q_UNUSED(scriptEngine); |
2150 | - qCDebug(QTMIR_APPLICATIONS) << "surfaceManagerSingleton - engine=" << engine << "scriptEngine=" << scriptEngine; |
2151 | - |
2152 | - return qtmir::MirSurfaceManager::singleton(); |
2153 | -} |
2154 | - |
2155 | -static QObject* sessionManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) { |
2156 | - Q_UNUSED(engine); |
2157 | - Q_UNUSED(scriptEngine); |
2158 | - return qtmir::SessionManager::singleton(); |
2159 | -} |
2160 | +#include "globals.h" |
2161 | |
2162 | namespace { |
2163 | -QObject* ubuntuKeyboardInfoSingleton(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/) { |
2164 | - if (!UbuntuKeyboardInfo::instance()) { |
2165 | - new UbuntuKeyboardInfo; |
2166 | + |
2167 | +QObject* applicationManagerSingleton(QQmlEngine* /*engine*/, QJSEngine* jsEngine) |
2168 | +{ |
2169 | + return qtmir::ApplicationManager::singleton(jsEngine); |
2170 | +} |
2171 | + |
2172 | +QObject* surfaceManagerSingleton(QQmlEngine* /*engine*/, QJSEngine* jsEngine) |
2173 | +{ |
2174 | + return qtmir::MirSurfaceManager::singleton(jsEngine); |
2175 | +} |
2176 | + |
2177 | +QObject* sessionManagerSingleton(QQmlEngine* /*engine*/, QJSEngine* jsEngine) |
2178 | +{ |
2179 | + return qtmir::SessionManager::singleton(jsEngine); |
2180 | +} |
2181 | + |
2182 | +QObject* ubuntuKeyboardInfoSingleton(QQmlEngine* /*engine*/, QJSEngine* /*scriptEngine*/) |
2183 | +{ |
2184 | + if (!qtmir::UbuntuKeyboardInfo::instance()) { |
2185 | + new qtmir::UbuntuKeyboardInfo; |
2186 | } |
2187 | - return UbuntuKeyboardInfo::instance(); |
2188 | + return qtmir::UbuntuKeyboardInfo::instance(); |
2189 | } |
2190 | } // anonymous namespace |
2191 | |
2192 | -class UnityApplicationPlugin : public QQmlExtensionPlugin { |
2193 | +class UnityApplicationPlugin : public QQmlExtensionPlugin |
2194 | +{ |
2195 | Q_OBJECT |
2196 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") |
2197 | |
2198 | @@ -71,9 +66,12 @@ |
2199 | qCDebug(QTMIR_APPLICATIONS) << "UnityApplicationPlugin::registerTypes - this=" << this << "uri=" << uri; |
2200 | Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Application")); |
2201 | |
2202 | + qmlRegisterUncreatableType<qtmir::Globals>( |
2203 | + uri, 0, 1, "QtMir", "QtMir provides enum values, it can't be instantiated"); |
2204 | + |
2205 | qRegisterMetaType<qtmir::ApplicationManager*>("ApplicationManager*"); //need for queueing signals |
2206 | qRegisterMetaType<qtmir::Application*>("Application*"); |
2207 | - qRegisterMetaType<qtmir::MirSurfaceItem*>("MirSurfaceItem*"); |
2208 | + qRegisterMetaType<qtmir::MirSurfaceItemInterface*>("MirSurfaceItemInterface*"); |
2209 | qRegisterMetaType<qtmir::MirSurfaceItemModel*>("MirSurfaceItemModel*"); |
2210 | qRegisterMetaType<qtmir::Session*>("Session*"); |
2211 | qRegisterMetaType<qtmir::SessionInterface*>("SessionInterface*"); |
2212 | @@ -92,7 +90,7 @@ |
2213 | uri, 0, 1, "SurfaceManager", surfaceManagerSingleton); |
2214 | qmlRegisterSingletonType<qtmir::SessionManager>( |
2215 | uri, 0, 1, "SessionManager", sessionManagerSingleton); |
2216 | - qmlRegisterUncreatableType<qtmir::MirSurfaceItem>( |
2217 | + qmlRegisterUncreatableType<qtmir::MirSurfaceItemInterface>( |
2218 | uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML"); |
2219 | qmlRegisterUncreatableType<qtmir::Session>( |
2220 | uri, 0, 1, "Session", "Session can't be instantiated from QML"); |
2221 | @@ -105,7 +103,7 @@ |
2222 | QQmlExtensionPlugin::initializeEngine(engine, uri); |
2223 | |
2224 | qtmir::ApplicationManager* appManager |
2225 | - = static_cast<qtmir::ApplicationManager*>(applicationManagerSingleton(engine, nullptr)); |
2226 | + = static_cast<qtmir::ApplicationManager*>(applicationManagerSingleton(engine, engine)); |
2227 | engine->addImageProvider(QLatin1String("application"), new qtmir::ApplicationScreenshotProvider(appManager)); |
2228 | } |
2229 | }; |
2230 | |
2231 | === modified file 'src/modules/Unity/Application/session.cpp' |
2232 | --- src/modules/Unity/Application/session.cpp 2015-01-15 15:19:26 +0000 |
2233 | +++ src/modules/Unity/Application/session.cpp 2015-07-13 21:57:32 +0000 |
2234 | @@ -1,5 +1,5 @@ |
2235 | /* |
2236 | - * Copyright (C) 2014 Canonical, Ltd. |
2237 | + * Copyright (C) 2014,2015 Canonical, Ltd. |
2238 | * |
2239 | * This program is free software; you can redistribute it and/or modify |
2240 | * it under the terms of the GNU General Public License as published by |
2241 | @@ -60,14 +60,7 @@ |
2242 | QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); |
2243 | |
2244 | m_suspendTimer->setSingleShot(true); |
2245 | - connect(m_suspendTimer, &QTimer::timeout, this, [this]() { |
2246 | - if (m_surface) { |
2247 | - m_surface->stopFrameDropper(); |
2248 | - } else { |
2249 | - qDebug() << "Application::suspend - no surface to call stopFrameDropper() on!"; |
2250 | - } |
2251 | - Q_EMIT suspended(); |
2252 | - }); |
2253 | + connect(m_suspendTimer, &QTimer::timeout, this, &Session::doSuspend); |
2254 | } |
2255 | |
2256 | Session::~Session() |
2257 | @@ -89,6 +82,17 @@ |
2258 | delete m_children; m_children = nullptr; |
2259 | } |
2260 | |
2261 | +void Session::doSuspend() |
2262 | +{ |
2263 | + Q_ASSERT(m_state == Session::Suspending); |
2264 | + if (m_surface) { |
2265 | + m_surface->stopFrameDropper(); |
2266 | + } else { |
2267 | + qDebug() << "Application::suspend - no surface to call stopFrameDropper() on!"; |
2268 | + } |
2269 | + setState(Suspended); |
2270 | +} |
2271 | + |
2272 | void Session::release() |
2273 | { |
2274 | qCDebug(QTMIR_SESSIONS) << "Session::release " << name(); |
2275 | @@ -120,7 +124,7 @@ |
2276 | return m_application; |
2277 | } |
2278 | |
2279 | -MirSurfaceItem* Session::surface() const |
2280 | +MirSurfaceItemInterface* Session::surface() const |
2281 | { |
2282 | // Only notify QML of surface creation once it has drawn its first frame. |
2283 | if (m_surface && m_surface->isFirstFrameDrawn()) { |
2284 | @@ -140,6 +144,13 @@ |
2285 | return m_state; |
2286 | } |
2287 | |
2288 | +void Session::setState(State state) { |
2289 | + if (state != m_state) { |
2290 | + m_state = state; |
2291 | + Q_EMIT stateChanged(m_state); |
2292 | + } |
2293 | +} |
2294 | + |
2295 | bool Session::fullscreen() const |
2296 | { |
2297 | return m_fullscreen; |
2298 | @@ -159,7 +170,7 @@ |
2299 | Q_EMIT applicationChanged(application); |
2300 | } |
2301 | |
2302 | -void Session::setSurface(MirSurfaceItem *newSurface) |
2303 | +void Session::setSurface(MirSurfaceItemInterface *newSurface) |
2304 | { |
2305 | qCDebug(QTMIR_SESSIONS) << "Session::setSurface - session=" << name() << "surface=" << newSurface; |
2306 | |
2307 | @@ -173,34 +184,46 @@ |
2308 | m_surface->setParent(nullptr); |
2309 | } |
2310 | |
2311 | - MirSurfaceItem *previousSurface = surface(); |
2312 | + MirSurfaceItemInterface *previousSurface = surface(); |
2313 | m_surface = newSurface; |
2314 | |
2315 | if (newSurface) { |
2316 | m_surface->setParent(this); |
2317 | m_surface->setSession(this); |
2318 | |
2319 | + connect(newSurface, &MirSurfaceItemInterface::stateChanged, |
2320 | + this, &Session::updateFullscreenProperty); |
2321 | + |
2322 | // Only notify QML of surface creation once it has drawn its first frame. |
2323 | - if (!surface()) { |
2324 | - connect(newSurface, &MirSurfaceItem::firstFrameDrawn, |
2325 | - this, [this] { Q_EMIT surfaceChanged(m_surface); }); |
2326 | + if (m_surface->isFirstFrameDrawn()) { |
2327 | + setState(Running); |
2328 | + } else { |
2329 | + connect(newSurface, &MirSurfaceItemInterface::firstFrameDrawn, |
2330 | + this, &Session::onFirstSurfaceFrameDrawn); |
2331 | } |
2332 | - |
2333 | - connect(newSurface, &MirSurfaceItem::stateChanged, |
2334 | - this, &Session::updateFullscreenProperty); |
2335 | } |
2336 | |
2337 | if (previousSurface != surface()) { |
2338 | + qCDebug(QTMIR_SESSIONS).nospace() << "Session::surfaceChanged - session=" << this |
2339 | + << " surface=" << m_surface; |
2340 | Q_EMIT surfaceChanged(m_surface); |
2341 | } |
2342 | |
2343 | updateFullscreenProperty(); |
2344 | } |
2345 | |
2346 | +void Session::onFirstSurfaceFrameDrawn() |
2347 | +{ |
2348 | + qCDebug(QTMIR_SESSIONS).nospace() << "Session::surfaceChanged - session=" << this |
2349 | + << " surface=" << m_surface; |
2350 | + Q_EMIT surfaceChanged(m_surface); |
2351 | + setState(Running); |
2352 | +} |
2353 | + |
2354 | void Session::updateFullscreenProperty() |
2355 | { |
2356 | if (m_surface) { |
2357 | - setFullscreen(m_surface->state() == MirSurfaceItem::Fullscreen); |
2358 | + setFullscreen(m_surface->state() == Globals::SurfaceState::Fullscreen); |
2359 | } else { |
2360 | // Keep the current value of the fullscreen property until we get a new |
2361 | // surface |
2362 | @@ -216,59 +239,71 @@ |
2363 | } |
2364 | } |
2365 | |
2366 | -void Session::setState(State state) |
2367 | -{ |
2368 | - qCDebug(QTMIR_SESSIONS) << "Session::setState - session=" << this << "state=" << applicationStateToStr(state); |
2369 | - if (m_state != state) { |
2370 | - switch (state) |
2371 | - { |
2372 | - case Session::State::Suspended: |
2373 | - if (m_state == Session::State::Running) { |
2374 | - session()->set_lifecycle_state(mir_lifecycle_state_will_suspend); |
2375 | - m_suspendTimer->start(1500); |
2376 | - } |
2377 | - break; |
2378 | - case Session::State::Running: |
2379 | - if (m_suspendTimer->isActive()) |
2380 | - m_suspendTimer->stop(); |
2381 | - |
2382 | - if (m_state == Session::State::Suspended) { |
2383 | - if (m_surface) |
2384 | - m_surface->startFrameDropper(); |
2385 | - Q_EMIT resumed(); |
2386 | - session()->set_lifecycle_state(mir_lifecycle_state_resumed); |
2387 | - } |
2388 | - break; |
2389 | - case Session::State::Stopped: |
2390 | - stopPromptSessions(); |
2391 | - if (m_suspendTimer->isActive()) |
2392 | - m_suspendTimer->stop(); |
2393 | - if (m_surface) |
2394 | - m_surface->stopFrameDropper(); |
2395 | - break; |
2396 | - default: |
2397 | - break; |
2398 | - } |
2399 | - |
2400 | - m_state = state; |
2401 | - Q_EMIT stateChanged(state); |
2402 | - |
2403 | - foreachPromptSession([this, state](const std::shared_ptr<ms::PromptSession>& promptSession) { |
2404 | - switch (state) { |
2405 | - case Session::State::Suspended: |
2406 | - m_promptSessionManager->suspend_prompt_session(promptSession); |
2407 | - break; |
2408 | - case Session::State::Running: |
2409 | - m_promptSessionManager->resume_prompt_session(promptSession); |
2410 | - break; |
2411 | - default: |
2412 | - break; |
2413 | - } |
2414 | - }); |
2415 | - |
2416 | - foreachChildSession([state](SessionInterface* session) { |
2417 | - session->setState(state); |
2418 | - }); |
2419 | +void Session::suspend() |
2420 | +{ |
2421 | + qCDebug(QTMIR_SESSIONS) << "Session::suspend - session=" << this << "state=" << applicationStateToStr(m_state); |
2422 | + if (m_state == Running) { |
2423 | + session()->set_lifecycle_state(mir_lifecycle_state_will_suspend); |
2424 | + m_suspendTimer->start(1500); |
2425 | + |
2426 | + foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) { |
2427 | + m_promptSessionManager->suspend_prompt_session(promptSession); |
2428 | + }); |
2429 | + |
2430 | + foreachChildSession([](SessionInterface* session) { |
2431 | + session->suspend(); |
2432 | + }); |
2433 | + |
2434 | + setState(Suspending); |
2435 | + } |
2436 | +} |
2437 | + |
2438 | +void Session::resume() |
2439 | +{ |
2440 | + qCDebug(QTMIR_SESSIONS) << "Session::resume - session=" << this << "state=" << applicationStateToStr(m_state); |
2441 | + |
2442 | + if (m_state == Suspending || m_state == Suspended) { |
2443 | + doResume(); |
2444 | + } |
2445 | +} |
2446 | + |
2447 | +void Session::doResume() |
2448 | +{ |
2449 | + if (m_state == Suspending) { |
2450 | + Q_ASSERT(m_suspendTimer->isActive()); |
2451 | + m_suspendTimer->stop(); |
2452 | + } else if (m_state == Suspended) { |
2453 | + Q_ASSERT(m_surface); |
2454 | + m_surface->startFrameDropper(); |
2455 | + } |
2456 | + |
2457 | + session()->set_lifecycle_state(mir_lifecycle_state_resumed); |
2458 | + |
2459 | + foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) { |
2460 | + m_promptSessionManager->resume_prompt_session(promptSession); |
2461 | + }); |
2462 | + |
2463 | + foreachChildSession([](SessionInterface* session) { |
2464 | + session->resume(); |
2465 | + }); |
2466 | + |
2467 | + setState(Running); |
2468 | +} |
2469 | + |
2470 | +void Session::stop() |
2471 | +{ |
2472 | + if (m_state != Stopped) { |
2473 | + stopPromptSessions(); |
2474 | + if (m_suspendTimer->isActive()) |
2475 | + m_suspendTimer->stop(); |
2476 | + if (m_surface) |
2477 | + m_surface->stopFrameDropper(); |
2478 | + |
2479 | + foreachChildSession([](SessionInterface* session) { |
2480 | + session->stop(); |
2481 | + }); |
2482 | + |
2483 | + setState(Stopped); |
2484 | } |
2485 | } |
2486 | |
2487 | @@ -277,6 +312,9 @@ |
2488 | if (m_live != live) { |
2489 | m_live = live; |
2490 | Q_EMIT liveChanged(m_live); |
2491 | + if (!live) { |
2492 | + setState(Stopped); |
2493 | + } |
2494 | } |
2495 | } |
2496 | |
2497 | @@ -302,7 +340,19 @@ |
2498 | static_cast<Session*>(session)->setParentSession(this); |
2499 | m_children->insert(index, session); |
2500 | |
2501 | - session->setState(state()); |
2502 | + switch (m_state) { |
2503 | + case Starting: |
2504 | + case Running: |
2505 | + session->resume(); |
2506 | + break; |
2507 | + case Suspending: |
2508 | + case Suspended: |
2509 | + session->suspend(); |
2510 | + break; |
2511 | + case Stopped: |
2512 | + session->stop(); |
2513 | + break; |
2514 | + } |
2515 | } |
2516 | |
2517 | void Session::removeChildSession(SessionInterface* session) |
2518 | |
2519 | === modified file 'src/modules/Unity/Application/session.h' |
2520 | --- src/modules/Unity/Application/session.h 2014-09-11 16:18:40 +0000 |
2521 | +++ src/modules/Unity/Application/session.h 2015-07-13 21:57:32 +0000 |
2522 | @@ -1,5 +1,5 @@ |
2523 | /* |
2524 | - * Copyright (C) 2014 Canonical, Ltd. |
2525 | + * Copyright (C) 2014-2015 Canonical, Ltd. |
2526 | * |
2527 | * This program is free software; you can redistribute it and/or modify |
2528 | * it under the terms of the GNU General Public License as published by |
2529 | @@ -52,15 +52,18 @@ |
2530 | //getters |
2531 | QString name() const override; |
2532 | unity::shell::application::ApplicationInfoInterface* application() const override; |
2533 | - MirSurfaceItem* surface() const override; |
2534 | + MirSurfaceItemInterface* surface() const override; |
2535 | SessionInterface* parentSession() const override; |
2536 | State state() const override; |
2537 | bool fullscreen() const override; |
2538 | bool live() const override; |
2539 | |
2540 | void setApplication(unity::shell::application::ApplicationInfoInterface* item) override; |
2541 | - void setSurface(MirSurfaceItem* surface) override; |
2542 | - void setState(State state) override; |
2543 | + void setSurface(MirSurfaceItemInterface* surface) override; |
2544 | + |
2545 | + void suspend() override; |
2546 | + void resume() override; |
2547 | + void stop() override; |
2548 | |
2549 | void addChildSession(SessionInterface* session) override; |
2550 | void insertChildSession(uint index, SessionInterface* session) override; |
2551 | @@ -74,23 +77,29 @@ |
2552 | |
2553 | SessionModel* childSessions() const override; |
2554 | |
2555 | -protected: |
2556 | void setFullscreen(bool fullscreen) override; |
2557 | void setLive(const bool) override; |
2558 | void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) override; |
2559 | void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) override; |
2560 | |
2561 | +public Q_SLOTS: |
2562 | + // it's public to ease testing |
2563 | + void doSuspend(); |
2564 | + |
2565 | private Q_SLOTS: |
2566 | void updateFullscreenProperty(); |
2567 | + void onFirstSurfaceFrameDrawn(); |
2568 | |
2569 | private: |
2570 | void setParentSession(Session* session); |
2571 | + void setState(State state); |
2572 | + void doResume(); |
2573 | |
2574 | void stopPromptSessions(); |
2575 | |
2576 | std::shared_ptr<mir::scene::Session> m_session; |
2577 | Application* m_application; |
2578 | - MirSurfaceItem* m_surface; |
2579 | + MirSurfaceItemInterface* m_surface; |
2580 | SessionInterface* m_parentSession; |
2581 | SessionModel* m_children; |
2582 | bool m_fullscreen; |
2583 | @@ -103,6 +112,4 @@ |
2584 | |
2585 | } // namespace qtmir |
2586 | |
2587 | -Q_DECLARE_METATYPE(qtmir::Session*) |
2588 | - |
2589 | #endif // SESSION_H |
2590 | |
2591 | === modified file 'src/modules/Unity/Application/session_interface.h' |
2592 | --- src/modules/Unity/Application/session_interface.h 2014-09-22 18:06:58 +0000 |
2593 | +++ src/modules/Unity/Application/session_interface.h 2015-07-13 21:57:32 +0000 |
2594 | @@ -1,5 +1,5 @@ |
2595 | /* |
2596 | - * Copyright (C) 2014 Canonical, Ltd. |
2597 | + * Copyright (C) 2014,2015 Canonical, Ltd. |
2598 | * |
2599 | * This program is free software; you can redistribute it and/or modify |
2600 | * it under the terms of the GNU General Public License as published by |
2601 | @@ -35,11 +35,11 @@ |
2602 | |
2603 | namespace qtmir { |
2604 | |
2605 | -class MirSurfaceItem; |
2606 | +class MirSurfaceItemInterface; |
2607 | |
2608 | class SessionInterface : public QObject { |
2609 | Q_OBJECT |
2610 | - Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged) |
2611 | + Q_PROPERTY(MirSurfaceItemInterface* surface READ surface NOTIFY surfaceChanged) |
2612 | Q_PROPERTY(unity::shell::application::ApplicationInfoInterface* application READ application NOTIFY applicationChanged DESIGNABLE false) |
2613 | Q_PROPERTY(SessionInterface* parentSession READ parentSession NOTIFY parentSessionChanged DESIGNABLE false) |
2614 | Q_PROPERTY(SessionModel* childSessions READ childSessions DESIGNABLE false CONSTANT) |
2615 | @@ -49,58 +49,66 @@ |
2616 | SessionInterface(QObject *parent = 0) : QObject(parent) {} |
2617 | virtual ~SessionInterface() {} |
2618 | |
2619 | - // Session State |
2620 | - typedef unity::shell::application::ApplicationInfoInterface::State State; |
2621 | + enum State { |
2622 | + Starting, |
2623 | + Running, |
2624 | + Suspending, |
2625 | + Suspended, |
2626 | + Stopped |
2627 | + }; |
2628 | |
2629 | Q_INVOKABLE virtual void release() = 0; |
2630 | |
2631 | //getters |
2632 | virtual QString name() const = 0; |
2633 | virtual unity::shell::application::ApplicationInfoInterface* application() const = 0; |
2634 | - virtual MirSurfaceItem* surface() const = 0; |
2635 | + virtual MirSurfaceItemInterface* surface() const = 0; |
2636 | virtual SessionInterface* parentSession() const = 0; |
2637 | + virtual SessionModel* childSessions() const = 0; |
2638 | virtual State state() const = 0; |
2639 | virtual bool fullscreen() const = 0; |
2640 | virtual bool live() const = 0; |
2641 | |
2642 | + virtual std::shared_ptr<mir::scene::Session> session() const = 0; |
2643 | + |
2644 | + // For MirSurfaceItem and MirSurfaceManager use |
2645 | + |
2646 | + virtual void setSurface(MirSurfaceItemInterface* surface) = 0; |
2647 | + |
2648 | + // For Application use |
2649 | + |
2650 | virtual void setApplication(unity::shell::application::ApplicationInfoInterface* item) = 0; |
2651 | - virtual void setSurface(MirSurfaceItem* surface) = 0; |
2652 | - virtual void setState(State state) = 0; |
2653 | + virtual void suspend() = 0; |
2654 | + virtual void resume() = 0; |
2655 | + virtual void stop() = 0; |
2656 | + |
2657 | + // For SessionManager use |
2658 | |
2659 | virtual void addChildSession(SessionInterface* session) = 0; |
2660 | virtual void insertChildSession(uint index, SessionInterface* session) = 0; |
2661 | virtual void removeChildSession(SessionInterface* session) = 0; |
2662 | virtual void foreachChildSession(std::function<void(SessionInterface* session)> f) const = 0; |
2663 | |
2664 | - virtual std::shared_ptr<mir::scene::Session> session() const = 0; |
2665 | - |
2666 | virtual std::shared_ptr<mir::scene::PromptSession> activePromptSession() const = 0; |
2667 | virtual void foreachPromptSession(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)> f) const = 0; |
2668 | |
2669 | - virtual SessionModel* childSessions() const = 0; |
2670 | + virtual void setFullscreen(bool fullscreen) = 0; |
2671 | + virtual void setLive(const bool) = 0; |
2672 | + virtual void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0; |
2673 | + virtual void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0; |
2674 | |
2675 | Q_SIGNALS: |
2676 | - void surfaceChanged(MirSurfaceItem*); |
2677 | + void surfaceChanged(MirSurfaceItemInterface*); |
2678 | void parentSessionChanged(SessionInterface*); |
2679 | void applicationChanged(unity::shell::application::ApplicationInfoInterface* application); |
2680 | void aboutToBeDestroyed(); |
2681 | void stateChanged(State state); |
2682 | void fullscreenChanged(bool fullscreen); |
2683 | void liveChanged(bool live); |
2684 | - |
2685 | - void suspended(); |
2686 | - void resumed(); |
2687 | - |
2688 | -protected: |
2689 | - virtual void setFullscreen(bool fullscreen) = 0; |
2690 | - virtual void setLive(const bool) = 0; |
2691 | - virtual void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0; |
2692 | - virtual void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0; |
2693 | - |
2694 | - friend class SessionManager; |
2695 | }; |
2696 | |
2697 | } // namespace qtmir |
2698 | |
2699 | +Q_DECLARE_METATYPE(qtmir::SessionInterface*) |
2700 | |
2701 | #endif // SESSION_INTERFACE_H |
2702 | |
2703 | === modified file 'src/modules/Unity/Application/sessionmanager.cpp' |
2704 | --- src/modules/Unity/Application/sessionmanager.cpp 2015-01-28 14:25:36 +0000 |
2705 | +++ src/modules/Unity/Application/sessionmanager.cpp 2015-07-13 21:57:32 +0000 |
2706 | @@ -63,7 +63,7 @@ |
2707 | manager, &SessionManager::onPromptProviderRemoved); |
2708 | } |
2709 | |
2710 | -SessionManager* SessionManager::singleton() |
2711 | +SessionManager* SessionManager::singleton(QJSEngine *jsEngine) |
2712 | { |
2713 | if (!the_session_manager) { |
2714 | |
2715 | @@ -78,7 +78,7 @@ |
2716 | SessionListener *sessionListener = static_cast<SessionListener*>(nativeInterface->nativeResourceForIntegration("SessionListener")); |
2717 | PromptSessionListener *promptSessionListener = static_cast<PromptSessionListener*>(nativeInterface->nativeResourceForIntegration("PromptSessionListener")); |
2718 | |
2719 | - the_session_manager = new SessionManager(nativeInterface->m_mirServer, ApplicationManager::singleton()); |
2720 | + the_session_manager = new SessionManager(nativeInterface->m_mirServer, ApplicationManager::singleton(jsEngine)); |
2721 | |
2722 | connectToSessionListener(the_session_manager, sessionListener); |
2723 | connectToPromptSessionListener(the_session_manager, promptSessionListener); |
2724 | |
2725 | === modified file 'src/modules/Unity/Application/sessionmanager.h' |
2726 | --- src/modules/Unity/Application/sessionmanager.h 2014-12-01 11:05:01 +0000 |
2727 | +++ src/modules/Unity/Application/sessionmanager.h 2015-07-13 21:57:32 +0000 |
2728 | @@ -38,6 +38,8 @@ |
2729 | } |
2730 | } |
2731 | |
2732 | +class QJSEngine; |
2733 | + |
2734 | class MirServer; |
2735 | |
2736 | namespace qtmir { |
2737 | @@ -57,7 +59,7 @@ |
2738 | ); |
2739 | ~SessionManager(); |
2740 | |
2741 | - static SessionManager* singleton(); |
2742 | + static SessionManager* singleton(QJSEngine *jsEngine); |
2743 | |
2744 | SessionInterface *findSession(const mir::scene::Session* session) const; |
2745 | |
2746 | |
2747 | === modified file 'src/modules/Unity/Application/taskcontroller.cpp' |
2748 | --- src/modules/Unity/Application/taskcontroller.cpp 2014-10-20 18:48:53 +0000 |
2749 | +++ src/modules/Unity/Application/taskcontroller.cpp 2015-07-13 21:57:32 +0000 |
2750 | @@ -50,14 +50,19 @@ |
2751 | &TaskController::processStopped); |
2752 | |
2753 | connect(m_appController.data(), |
2754 | + &ApplicationController::applicationPaused, |
2755 | + this, |
2756 | + &TaskController::processSuspended); |
2757 | + |
2758 | + connect(m_appController.data(), |
2759 | &ApplicationController::applicationFocusRequest, |
2760 | this, |
2761 | - &TaskController::onApplicationFocusRequest); |
2762 | + &TaskController::focusRequested); |
2763 | |
2764 | connect(m_appController.data(), |
2765 | - &ApplicationController::applicationResumeRequest, |
2766 | + &ApplicationController::applicationResumeRequested, |
2767 | this, |
2768 | - &TaskController::onApplicationResumeRequest); |
2769 | + &TaskController::resumeRequested); |
2770 | |
2771 | connect(m_appController.data(), |
2772 | &ApplicationController::applicationError, |
2773 | @@ -108,16 +113,6 @@ |
2774 | return m_appController->resumeApplicationWithAppId(appId); |
2775 | } |
2776 | |
2777 | -void TaskController::onApplicationFocusRequest(const QString& id) |
2778 | -{ |
2779 | - Q_EMIT requestFocus(id); |
2780 | -} |
2781 | - |
2782 | -void TaskController::onApplicationResumeRequest(const QString& id) |
2783 | -{ |
2784 | - Q_EMIT requestResume(id); |
2785 | -} |
2786 | - |
2787 | void TaskController::onApplicationError(const QString& id, ApplicationController::Error error) |
2788 | { |
2789 | Q_EMIT processFailed(id, (error == ApplicationController::Error::APPLICATION_FAILED_TO_START) ); |
2790 | |
2791 | === modified file 'src/modules/Unity/Application/taskcontroller.h' |
2792 | --- src/modules/Unity/Application/taskcontroller.h 2014-10-07 03:21:30 +0000 |
2793 | +++ src/modules/Unity/Application/taskcontroller.h 2015-07-13 21:57:32 +0000 |
2794 | @@ -1,5 +1,5 @@ |
2795 | /* |
2796 | - * Copyright (C) 2013-2014 Canonical, Ltd. |
2797 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
2798 | * |
2799 | * This program is free software: you can redistribute it and/or modify it under |
2800 | * the terms of the GNU Lesser General Public License version 3, as published by |
2801 | @@ -48,14 +48,12 @@ |
2802 | Q_SIGNALS: |
2803 | void processStarting(const QString &appId); |
2804 | void processStopped(const QString &appId); |
2805 | + void processSuspended(const QString &appId); |
2806 | void processFailed(const QString &appId, const bool duringStartup); |
2807 | - void requestFocus(const QString &appId); |
2808 | - void requestResume(const QString &appId); |
2809 | + void focusRequested(const QString &appId); |
2810 | + void resumeRequested(const QString &appId); |
2811 | |
2812 | private Q_SLOTS: |
2813 | - void onApplicationFocusRequest(const QString &id); |
2814 | - void onApplicationResumeRequest(const QString &id); |
2815 | - |
2816 | void onApplicationError(const QString &id, ApplicationController::Error error); |
2817 | |
2818 | private: |
2819 | |
2820 | === modified file 'src/modules/Unity/Application/upstart/applicationcontroller.cpp' |
2821 | --- src/modules/Unity/Application/upstart/applicationcontroller.cpp 2014-11-13 15:47:30 +0000 |
2822 | +++ src/modules/Unity/Application/upstart/applicationcontroller.cpp 2015-07-13 21:57:32 +0000 |
2823 | @@ -1,5 +1,5 @@ |
2824 | /* |
2825 | - * Copyright (C) 2014 Canonical, Ltd. |
2826 | + * Copyright (C) 2014,2015 Canonical, Ltd. |
2827 | * |
2828 | * This program is free software: you can redistribute it and/or modify it under |
2829 | * the terms of the GNU Lesser General Public License version 3, as published by |
2830 | @@ -40,6 +40,7 @@ |
2831 | UbuntuAppLaunchAppObserver stopCallback = nullptr; |
2832 | UbuntuAppLaunchAppObserver focusCallback = nullptr; |
2833 | UbuntuAppLaunchAppObserver resumeCallback = nullptr; |
2834 | + UbuntuAppLaunchAppPausedResumedObserver pausedCallback = nullptr; |
2835 | UbuntuAppLaunchAppFailedObserver failureCallback = nullptr; |
2836 | }; |
2837 | |
2838 | @@ -125,7 +126,12 @@ |
2839 | |
2840 | impl->resumeCallback = [](const gchar * appId, gpointer userData) { |
2841 | auto thiz = static_cast<ApplicationController*>(userData); |
2842 | - Q_EMIT(thiz->applicationResumeRequest(toShortAppIdIfPossible(appId))); |
2843 | + Q_EMIT(thiz->applicationResumeRequested(toShortAppIdIfPossible(appId))); |
2844 | + }; |
2845 | + |
2846 | + impl->pausedCallback = [](const gchar * appId, GPid *, gpointer userData) { |
2847 | + auto thiz = static_cast<ApplicationController*>(userData); |
2848 | + Q_EMIT(thiz->applicationPaused(toShortAppIdIfPossible(appId))); |
2849 | }; |
2850 | |
2851 | impl->failureCallback = [](const gchar * appId, UbuntuAppLaunchAppFailed failureType, gpointer userData) { |
2852 | @@ -145,6 +151,7 @@ |
2853 | ubuntu_app_launch_observer_add_app_stop(impl->stopCallback, this); |
2854 | ubuntu_app_launch_observer_add_app_focus(impl->focusCallback, this); |
2855 | ubuntu_app_launch_observer_add_app_resume(impl->resumeCallback, this); |
2856 | + ubuntu_app_launch_observer_add_app_paused(impl->pausedCallback, this); |
2857 | ubuntu_app_launch_observer_add_app_failed(impl->failureCallback, this); |
2858 | } |
2859 | |
2860 | @@ -155,6 +162,7 @@ |
2861 | ubuntu_app_launch_observer_delete_app_stop(impl->stopCallback, this); |
2862 | ubuntu_app_launch_observer_delete_app_focus(impl->focusCallback, this); |
2863 | ubuntu_app_launch_observer_delete_app_resume(impl->resumeCallback, this); |
2864 | + ubuntu_app_launch_observer_delete_app_paused(impl->pausedCallback, this); |
2865 | ubuntu_app_launch_observer_delete_app_failed(impl->failureCallback, this); |
2866 | } |
2867 | |
2868 | |
2869 | === modified file 'src/platforms/mirserver/CMakeLists.txt' |
2870 | --- src/platforms/mirserver/CMakeLists.txt 2015-05-19 15:10:48 +0000 |
2871 | +++ src/platforms/mirserver/CMakeLists.txt 2015-07-13 21:57:32 +0000 |
2872 | @@ -31,6 +31,8 @@ |
2873 | ${QT5PLATFORM_SUPPORT_INCLUDE_DIRS} |
2874 | ${Qt5Gui_PRIVATE_INCLUDE_DIRS} |
2875 | ${QT5_PLATFORMSUPPORT_INCLUDE_DIRS} |
2876 | + |
2877 | + ${APPLICATION_API_INCLUDE_DIRS} |
2878 | ) |
2879 | |
2880 | # We have to remove -pedantic for tracepoints.c |
2881 | |
2882 | === modified file 'src/platforms/mirserver/mirserver.cpp' |
2883 | --- src/platforms/mirserver/mirserver.cpp 2015-02-09 16:28:40 +0000 |
2884 | +++ src/platforms/mirserver/mirserver.cpp 2015-07-13 21:57:32 +0000 |
2885 | @@ -92,8 +92,7 @@ |
2886 | the_input_targeter(), |
2887 | the_surface_coordinator(), |
2888 | the_session_coordinator(), |
2889 | - the_prompt_session_manager(), |
2890 | - the_shell_display_layout()); |
2891 | + the_prompt_session_manager()); |
2892 | |
2893 | m_shell = shell; |
2894 | return shell; |
2895 | |
2896 | === modified file 'src/platforms/mirserver/mirshell.cpp' |
2897 | --- src/platforms/mirserver/mirshell.cpp 2015-05-13 09:40:03 +0000 |
2898 | +++ src/platforms/mirserver/mirshell.cpp 2015-07-13 21:57:32 +0000 |
2899 | @@ -71,37 +71,42 @@ |
2900 | const std::shared_ptr<mir::shell::InputTargeter> &inputTargeter, |
2901 | const std::shared_ptr<mir::scene::SurfaceCoordinator> &surfaceCoordinator, |
2902 | const std::shared_ptr<mir::scene::SessionCoordinator> &sessionCoordinator, |
2903 | - const std::shared_ptr<mir::scene::PromptSessionManager> &promptSessionManager, |
2904 | - const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout) : |
2905 | + const std::shared_ptr<mir::scene::PromptSessionManager> &promptSessionManager) : |
2906 | AbstractShell(inputTargeter, surfaceCoordinator, sessionCoordinator, promptSessionManager, |
2907 | - [](mir::shell::FocusController*) { return std::make_shared<NullWindowManager>(); }), |
2908 | - m_displayLayout{displayLayout} |
2909 | + [](mir::shell::FocusController*) { return std::make_shared<NullWindowManager>(); }) |
2910 | { |
2911 | qCDebug(QTMIR_MIR_MESSAGES) << "MirShell::MirShell"; |
2912 | } |
2913 | |
2914 | -mir::frontend::SurfaceId MirShell::create_surface(const std::shared_ptr<ms::Session> &session, const ms::SurfaceCreationParameters &requestParameters) |
2915 | +mir::frontend::SurfaceId MirShell::create_surface(const std::shared_ptr<ms::Session> &session, |
2916 | + const ms::SurfaceCreationParameters &requestParameters) |
2917 | { |
2918 | + using namespace mir::geometry; |
2919 | + using namespace qtmir; |
2920 | tracepoint(qtmirserver, surfacePlacementStart); |
2921 | |
2922 | - // TODO: Callback unity8 so that it can make a decision on that. |
2923 | - // unity8 must bear in mind that the called function will be on a Mir thread though. |
2924 | - // The QPA shouldn't be deciding for itself on such things. |
2925 | - |
2926 | - ms::SurfaceCreationParameters placedParameters = requestParameters; |
2927 | - |
2928 | - // Just make it fullscreen for now |
2929 | - mir::geometry::Rectangle rect{requestParameters.top_left, requestParameters.size}; |
2930 | - m_displayLayout->size_to_output(rect); |
2931 | - placedParameters.size = rect.size; |
2932 | - |
2933 | - qCDebug(QTMIR_MIR_MESSAGES) << "MirShell::create_surface(): size requested (" |
2934 | - << requestParameters.size.width.as_int() << "," << requestParameters.size.height.as_int() << ") and placed (" |
2935 | - << placedParameters.size.width.as_int() << "," << placedParameters.size.height.as_int() << ")"; |
2936 | - |
2937 | - tracepoint(qtmirserver, surfacePlacementEnd); |
2938 | - |
2939 | - return AbstractShell::create_surface(session, placedParameters); |
2940 | + SurfaceParameters params; |
2941 | + params.geometry.setWidth(requestParameters.size.width.as_int()); |
2942 | + params.geometry.setHeight(requestParameters.size.height.as_int()); |
2943 | + if (requestParameters.state.is_set()) { |
2944 | + params.state = static_cast<Globals::SurfaceState>(requestParameters.state.value()); |
2945 | + } else { |
2946 | + params.state = Globals::SurfaceState::Unknown; |
2947 | + } |
2948 | + |
2949 | + Q_EMIT sessionAboutToCreateSurface(session, params); // can be connected to via Qt::BlockingQueuedConnection |
2950 | + // to alter surface initial geometry and state |
2951 | + |
2952 | + ms::SurfaceCreationParameters placedParameters = requestParameters; |
2953 | + placedParameters.size = Size{ Width{params.geometry.width()}, Height{params.geometry.height()} }; |
2954 | + |
2955 | + qCDebug(QTMIR_MIR_MESSAGES) << "MirPlacementStrategy: requested (" |
2956 | + << requestParameters.size.width.as_int() << "," << requestParameters.size.height.as_int() << ") and returned (" |
2957 | + << placedParameters.size.width.as_int() << "," << placedParameters.size.height.as_int() << ")"; |
2958 | + |
2959 | + tracepoint(qtmirserver, surfacePlacementEnd); |
2960 | + |
2961 | + return AbstractShell::create_surface(session, placedParameters); |
2962 | } |
2963 | |
2964 | void NullWindowManager::add_session(std::shared_ptr<ms::Session> const& /*session*/) |
2965 | |
2966 | === modified file 'src/platforms/mirserver/mirshell.h' |
2967 | --- src/platforms/mirserver/mirshell.h 2015-03-11 10:10:49 +0000 |
2968 | +++ src/platforms/mirserver/mirshell.h 2015-07-13 21:57:32 +0000 |
2969 | @@ -17,14 +17,15 @@ |
2970 | #ifndef QPAMIRSERVER_SHELL_H |
2971 | #define QPAMIRSERVER_SHELL_H |
2972 | |
2973 | +// Mir |
2974 | #include <mir/shell/abstract_shell.h> |
2975 | + |
2976 | +// Qt |
2977 | #include <QObject> |
2978 | |
2979 | -namespace mir { |
2980 | - namespace shell { |
2981 | - class DisplayLayout; |
2982 | - } |
2983 | -} |
2984 | +// local |
2985 | +#include "globals.h" |
2986 | + |
2987 | |
2988 | class MirShell : public QObject, public mir::shell::AbstractShell |
2989 | { |
2990 | @@ -35,13 +36,16 @@ |
2991 | const std::shared_ptr<mir::shell::InputTargeter> &inputTargeter, |
2992 | const std::shared_ptr<mir::scene::SurfaceCoordinator> &surfaceCoordinator, |
2993 | const std::shared_ptr<mir::scene::SessionCoordinator> &sessionCoordinator, |
2994 | - const std::shared_ptr<mir::scene::PromptSessionManager> &promptSessionManager, |
2995 | - const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout); |
2996 | - |
2997 | - virtual mir::frontend::SurfaceId create_surface(const std::shared_ptr<mir::scene::Session>& session, const mir::scene::SurfaceCreationParameters ¶ms); |
2998 | - |
2999 | -private: |
3000 | - std::shared_ptr<mir::shell::DisplayLayout> const m_displayLayout; |
3001 | + const std::shared_ptr<mir::scene::PromptSessionManager> &promptSessionManager); |
3002 | + |
3003 | + virtual mir::frontend::SurfaceId create_surface(const std::shared_ptr<mir::scene::Session> &session, |
3004 | + const mir::scene::SurfaceCreationParameters ¶ms); |
3005 | + |
3006 | +Q_SIGNALS: |
3007 | + void sessionAboutToCreateSurface(const std::shared_ptr<mir::scene::Session> &session, |
3008 | + qtmir::SurfaceParameters ¶ms); // requires Qt::BlockingQueuedConnection!! |
3009 | + |
3010 | + void surfaceAttributeChanged(mir::scene::Surface const*, const MirSurfaceAttrib, const int); |
3011 | }; |
3012 | |
3013 | #endif /* QPAMIRSERVER_SHELL_H */ |
3014 | |
3015 | === modified file 'tests/modules/Application/CMakeLists.txt' |
3016 | --- tests/modules/Application/CMakeLists.txt 2015-05-21 18:48:59 +0000 |
3017 | +++ tests/modules/Application/CMakeLists.txt 2015-07-13 21:57:32 +0000 |
3018 | @@ -1,9 +1,12 @@ |
3019 | set( |
3020 | APPLICATION_TEST_SOURCES |
3021 | application_test.cpp |
3022 | + ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp |
3023 | ) |
3024 | |
3025 | include_directories( |
3026 | + ${APPLICATION_API_INCLUDE_DIRS} |
3027 | + ${CMAKE_SOURCE_DIR}/src/common |
3028 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
3029 | ${CMAKE_SOURCE_DIR}/src/modules |
3030 | ${CMAKE_SOURCE_DIR}/tests/modules/common |
3031 | @@ -18,6 +21,8 @@ |
3032 | unityapplicationplugin |
3033 | qpa-mirserver |
3034 | |
3035 | + Qt5::Test |
3036 | + |
3037 | ${GTEST_BOTH_LIBRARIES} |
3038 | ${GMOCK_LIBRARIES} |
3039 | ) |
3040 | |
3041 | === modified file 'tests/modules/Application/application_test.cpp' |
3042 | --- tests/modules/Application/application_test.cpp 2015-03-04 22:13:06 +0000 |
3043 | +++ tests/modules/Application/application_test.cpp 2015-07-13 21:57:32 +0000 |
3044 | @@ -20,6 +20,10 @@ |
3045 | |
3046 | #include "qtmir_test.h" |
3047 | |
3048 | +#include <mock_session.h> |
3049 | + |
3050 | +#include <QScopedPointer> |
3051 | +#include <QSignalSpy> |
3052 | |
3053 | using namespace qtmir; |
3054 | |
3055 | @@ -30,93 +34,163 @@ |
3056 | {} |
3057 | }; |
3058 | |
3059 | -TEST_F(ApplicationTests, checkFocusAcquiresWakeLock) |
3060 | -{ |
3061 | - using namespace ::testing; |
3062 | - |
3063 | - EXPECT_CALL(sharedWakelock, acquire(_)).Times(1); |
3064 | - |
3065 | - startApplication(123, "app"); |
3066 | - applicationManager.focusApplication("app"); |
3067 | -} |
3068 | - |
3069 | -TEST_F(ApplicationTests, checkSuspendReleasesWakeLock) |
3070 | -{ |
3071 | - using namespace ::testing; |
3072 | - |
3073 | - auto app = startApplication(123, "app"); |
3074 | - auto session = app->session(); |
3075 | - |
3076 | - applicationManager.focusApplication("app"); |
3077 | - |
3078 | - Q_EMIT session->suspended(); |
3079 | +TEST_F(ApplicationTests, acquiresWakelockWhenRunningAndReleasesWhenSuspended) |
3080 | +{ |
3081 | + using namespace ::testing; |
3082 | + QString appId("foo-app"); |
3083 | + |
3084 | + auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
3085 | + ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); |
3086 | + |
3087 | + QScopedPointer<Application> application(new Application( |
3088 | + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), |
3089 | + desktopFileReader, QStringList(), nullptr)); |
3090 | + |
3091 | + application->setProcessState(Application::ProcessRunning); |
3092 | + |
3093 | + NiceMock<MockSession> *session = new NiceMock<MockSession>; |
3094 | + |
3095 | + EXPECT_CALL(*session, setApplication(_)); |
3096 | + EXPECT_CALL(*session, fullscreen()).WillRepeatedly(Return(false)); |
3097 | + |
3098 | + application->setSession(session); |
3099 | + |
3100 | + ASSERT_EQ(Application::InternalState::Starting, application->internalState()); |
3101 | + |
3102 | + session->setState(SessionInterface::Running); |
3103 | + |
3104 | + EXPECT_TRUE(sharedWakelock.enabled()); |
3105 | + |
3106 | + ASSERT_EQ(Application::InternalState::Running, application->internalState()); |
3107 | + |
3108 | + application->setRequestedState(Application::RequestedSuspended); |
3109 | + |
3110 | + ASSERT_EQ(SessionInterface::Suspending, session->state()); |
3111 | + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); |
3112 | + |
3113 | + session->setState(SessionInterface::Suspended); |
3114 | + |
3115 | + ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState()); |
3116 | + |
3117 | + application->setProcessState(Application::ProcessSuspended); |
3118 | + |
3119 | + ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); |
3120 | + |
3121 | EXPECT_FALSE(sharedWakelock.enabled()); |
3122 | } |
3123 | |
3124 | TEST_F(ApplicationTests, checkResumeAcquiresWakeLock) |
3125 | { |
3126 | using namespace ::testing; |
3127 | - |
3128 | - EXPECT_CALL(sharedWakelock, acquire(_)).Times(1); |
3129 | - |
3130 | - auto app = startApplication(123, "app"); |
3131 | - auto session = app->session(); |
3132 | - |
3133 | - Q_EMIT session->resumed(); |
3134 | + QString appId("foo-app"); |
3135 | + |
3136 | + auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
3137 | + ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); |
3138 | + |
3139 | + QScopedPointer<Application> application(new Application( |
3140 | + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), |
3141 | + desktopFileReader, QStringList(), nullptr)); |
3142 | + NiceMock<MockSession> *session = new NiceMock<MockSession>; |
3143 | + |
3144 | + // Get it running and then suspend it |
3145 | + application->setProcessState(Application::ProcessRunning); |
3146 | + application->setSession(session); |
3147 | + session->setState(SessionInterface::Running); |
3148 | + application->setRequestedState(Application::RequestedSuspended); |
3149 | + session->setState(SessionInterface::Suspended); |
3150 | + application->setProcessState(Application::ProcessSuspended); |
3151 | + ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); |
3152 | + |
3153 | + EXPECT_FALSE(sharedWakelock.enabled()); |
3154 | + |
3155 | + application->setRequestedState(Application::RequestedRunning); |
3156 | + |
3157 | + ASSERT_EQ(Application::InternalState::Running, application->internalState()); |
3158 | + |
3159 | + EXPECT_TRUE(sharedWakelock.enabled()); |
3160 | } |
3161 | |
3162 | TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock) |
3163 | { |
3164 | using namespace ::testing; |
3165 | - |
3166 | - EXPECT_CALL(sharedWakelock, acquire(_)).Times(1); |
3167 | - const QString appId = "app"; |
3168 | - |
3169 | - auto app = startApplication(123, "app"); |
3170 | - |
3171 | - // as respawn fires startApplicationWithAppIdAndArgs again, keep gmock quiet about another call |
3172 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
3173 | - .Times(1) |
3174 | - .WillRepeatedly(Return(true)); |
3175 | - |
3176 | - // respawn by setting app state as Stopped, delete the Session associated, then set to Running state |
3177 | - app->setState(Session::State::Stopped); |
3178 | - delete app->session(); |
3179 | - app->setState(Session::State::Running); |
3180 | -} |
3181 | - |
3182 | -TEST_F(ApplicationTests, checkDashFocusDoesNotAcquireWakeLock) |
3183 | -{ |
3184 | - using namespace ::testing; |
3185 | - |
3186 | - EXPECT_CALL(sharedWakelock, acquire(_)).Times(0); |
3187 | - |
3188 | - startApplication(123, "unity8-dash"); |
3189 | - applicationManager.focusApplication("unity8-dash"); |
3190 | -} |
3191 | - |
3192 | -TEST_F(ApplicationTests, checkDashSuspendDoesNotImpactWakeLock) |
3193 | -{ |
3194 | - using namespace ::testing; |
3195 | - |
3196 | - auto app = startApplication(123, "unity8-dash"); |
3197 | - auto session = app->session(); |
3198 | - |
3199 | - applicationManager.focusApplication("unity8-dash"); |
3200 | - |
3201 | - Q_EMIT session->suspended(); |
3202 | + QString appId("foo-app"); |
3203 | + |
3204 | + auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
3205 | + ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); |
3206 | + |
3207 | + QScopedPointer<Application> application(new Application( |
3208 | + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), |
3209 | + desktopFileReader, QStringList(), nullptr)); |
3210 | + NiceMock<MockSession> *session = new NiceMock<MockSession>; |
3211 | + |
3212 | + // Get it running, suspend it, and finally stop it |
3213 | + application->setProcessState(Application::ProcessRunning); |
3214 | + application->setSession(session); |
3215 | + session->setState(SessionInterface::Running); |
3216 | + application->setRequestedState(Application::RequestedSuspended); |
3217 | + session->setState(SessionInterface::Suspended); |
3218 | + application->setProcessState(Application::ProcessSuspended); |
3219 | + ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); |
3220 | + session->setState(SessionInterface::Stopped); |
3221 | + application->setProcessState(Application::ProcessStopped); |
3222 | + ASSERT_EQ(Application::InternalState::StoppedUnexpectedly, application->internalState()); |
3223 | + |
3224 | EXPECT_FALSE(sharedWakelock.enabled()); |
3225 | + |
3226 | + QSignalSpy spyStartProcess(application.data(), SIGNAL(startProcessRequested())); |
3227 | + application->setRequestedState(Application::RequestedRunning); |
3228 | + ASSERT_EQ(1, spyStartProcess.count()); |
3229 | + application->setProcessState(Application::ProcessRunning); |
3230 | + |
3231 | + ASSERT_EQ(Application::InternalState::Starting, application->internalState()); |
3232 | + |
3233 | + EXPECT_TRUE(sharedWakelock.enabled()); |
3234 | } |
3235 | |
3236 | -TEST_F(ApplicationTests, checkDashResumeDoesNotAcquireWakeLock) |
3237 | +TEST_F(ApplicationTests, checkDashDoesNotImpactWakeLock) |
3238 | { |
3239 | using namespace ::testing; |
3240 | + QString appId("unity8-dash"); |
3241 | |
3242 | EXPECT_CALL(sharedWakelock, acquire(_)).Times(0); |
3243 | - |
3244 | - auto app = startApplication(123, "unity8-dash"); |
3245 | - auto session = app->session(); |
3246 | - |
3247 | - Q_EMIT session->resumed(); |
3248 | + EXPECT_CALL(sharedWakelock, release(_)).Times(0); |
3249 | + |
3250 | + auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
3251 | + ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true)); |
3252 | + |
3253 | + QScopedPointer<Application> application(new Application( |
3254 | + QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}), |
3255 | + desktopFileReader, QStringList(), nullptr)); |
3256 | + |
3257 | + application->setProcessState(Application::ProcessRunning); |
3258 | + |
3259 | + NiceMock<MockSession> *session = new NiceMock<MockSession>; |
3260 | + |
3261 | + EXPECT_CALL(*session, setApplication(_)); |
3262 | + EXPECT_CALL(*session, fullscreen()).WillRepeatedly(Return(false)); |
3263 | + |
3264 | + application->setSession(session); |
3265 | + |
3266 | + ASSERT_EQ(Application::InternalState::Starting, application->internalState()); |
3267 | + |
3268 | + session->setState(SessionInterface::Running); |
3269 | + |
3270 | + ASSERT_EQ(Application::InternalState::Running, application->internalState()); |
3271 | + |
3272 | + application->setRequestedState(Application::RequestedSuspended); |
3273 | + |
3274 | + ASSERT_EQ(SessionInterface::Suspending, session->state()); |
3275 | + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); |
3276 | + |
3277 | + session->setState(SessionInterface::Suspended); |
3278 | + |
3279 | + ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState()); |
3280 | + |
3281 | + application->setProcessState(Application::ProcessSuspended); |
3282 | + |
3283 | + ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); |
3284 | + |
3285 | + application->setRequestedState(Application::RequestedRunning); |
3286 | + |
3287 | + ASSERT_EQ(Application::InternalState::Running, application->internalState()); |
3288 | } |
3289 | - |
3290 | |
3291 | === modified file 'tests/modules/ApplicationManager/CMakeLists.txt' |
3292 | --- tests/modules/ApplicationManager/CMakeLists.txt 2015-05-21 18:48:59 +0000 |
3293 | +++ tests/modules/ApplicationManager/CMakeLists.txt 2015-07-13 21:57:32 +0000 |
3294 | @@ -2,9 +2,13 @@ |
3295 | APPLICATION_MANAGER_TEST_SOURCES |
3296 | application_manager_test.cpp |
3297 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
3298 | + ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp |
3299 | + ../common/fake_mirsurfaceitem.h |
3300 | ) |
3301 | |
3302 | include_directories( |
3303 | + ${APPLICATION_API_INCLUDE_DIRS} |
3304 | + ${CMAKE_SOURCE_DIR}/src/common |
3305 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
3306 | ${CMAKE_SOURCE_DIR}/src/modules |
3307 | ${CMAKE_SOURCE_DIR}/tests/modules/common |
3308 | @@ -15,7 +19,7 @@ |
3309 | |
3310 | target_link_libraries( |
3311 | applicationmanager_test |
3312 | - |
3313 | + |
3314 | qpa-mirserver |
3315 | unityapplicationplugin |
3316 | |
3317 | |
3318 | === modified file 'tests/modules/ApplicationManager/application_manager_test.cpp' |
3319 | --- tests/modules/ApplicationManager/application_manager_test.cpp 2015-05-13 17:18:45 +0000 |
3320 | +++ tests/modules/ApplicationManager/application_manager_test.cpp 2015-07-13 21:57:32 +0000 |
3321 | @@ -1,5 +1,5 @@ |
3322 | /* |
3323 | - * Copyright (C) 2013 Canonical, Ltd. |
3324 | + * Copyright (C) 2013-2015 Canonical, Ltd. |
3325 | * |
3326 | * This program is free software: you can redistribute it and/or modify it under |
3327 | * the terms of the GNU Lesser General Public License version 3, as published by |
3328 | @@ -23,8 +23,9 @@ |
3329 | |
3330 | #include <Unity/Application/applicationscreenshotprovider.h> |
3331 | |
3332 | - #include "mock_surface.h" |
3333 | - #include "qtmir_test.h" |
3334 | +#include "fake_mirsurfaceitem.h" |
3335 | +#include "mock_surface.h" |
3336 | +#include "qtmir_test.h" |
3337 | |
3338 | using namespace qtmir; |
3339 | using mir::scene::MockSession; |
3340 | @@ -45,100 +46,41 @@ |
3341 | applicationManager.onSessionStopping(session); |
3342 | sessionManager.onSessionStopping(session); |
3343 | } |
3344 | + inline void onSessionCreatedSurface(const mir::scene::Session *mirSession, |
3345 | + MirSurfaceItemInterface *qmlSurface) { |
3346 | + |
3347 | + SessionInterface* qmlSession = sessionManager.findSession(mirSession); |
3348 | + if (qmlSession) { |
3349 | + qmlSession->setSurface(qmlSurface); |
3350 | + } |
3351 | + |
3352 | + // I assume that applicationManager ignores the mirSurface parameter, so sending |
3353 | + // a null shared pointer must suffice |
3354 | + std::shared_ptr<mir::scene::Surface> mirSurface(nullptr); |
3355 | + applicationManager.onSessionCreatedSurface(mirSession, mirSurface); |
3356 | + } |
3357 | + |
3358 | + inline void suspend(Application *application) { |
3359 | + application->setRequestedState(Application::RequestedSuspended); |
3360 | + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); |
3361 | + static_cast<qtmir::Session*>(application->session())->doSuspend(); |
3362 | + ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState()); |
3363 | + applicationManager.onProcessSuspended(application->appId()); |
3364 | + ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); |
3365 | + } |
3366 | }; |
3367 | |
3368 | -TEST_F(ApplicationManagerTests, SuspendingAndResumingARunningApplicationResultsInOomScoreAdjustment) |
3369 | -{ |
3370 | - using namespace ::testing; |
3371 | - |
3372 | - const QString appId("com.canonical.does.not.exist"); |
3373 | - |
3374 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(_, _)).Times(1); |
3375 | - EXPECT_CALL(appController, findDesktopFileForAppId(appId)).Times(1); |
3376 | - |
3377 | - EXPECT_CALL(desktopFileReaderFactory, createInstance(_, _)).Times(1); |
3378 | - |
3379 | - auto application = applicationManager.startApplication( |
3380 | - appId, |
3381 | - ApplicationManager::NoFlag, |
3382 | - QStringList()); |
3383 | - |
3384 | - // FIXME - this is doesn't really excerise the actualt behaviour since suspend/resume should be |
3385 | - // controlled by state changes. Requires using suspend timer. |
3386 | - QMetaObject::invokeMethod(application, "onSessionSuspended"); |
3387 | - QMetaObject::invokeMethod(application, "onSessionResumed"); |
3388 | -} |
3389 | - |
3390 | -TEST_F(ApplicationManagerTests, SuspendingAndResumingDashResultsInOomScoreAdjustment) |
3391 | -{ |
3392 | - using namespace ::testing; |
3393 | - |
3394 | - quint64 procId = 5921; |
3395 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3396 | - QByteArray cmdLine( "/usr/bin/app1 --desktop_file_hint=unity8-dash"); |
3397 | - |
3398 | - EXPECT_CALL(procInfo,command_line(procId)) |
3399 | - .Times(1) |
3400 | - .WillOnce(Return(cmdLine)); |
3401 | - |
3402 | - ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3403 | - |
3404 | - bool authed = true; |
3405 | - |
3406 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("Oo", procId); |
3407 | - applicationManager.authorizeSession(procId, authed); |
3408 | - onSessionStarting(session); |
3409 | - |
3410 | - auto application = applicationManager.findApplication("unity8-dash"); |
3411 | - applicationManager.onSessionCreatedSurface(session.get(), aSurface); |
3412 | - |
3413 | - // FIXME - this is doesn't really excerise the actualt behaviour since suspend/resume should be |
3414 | - // controlled by state changes. Requires using suspend timer. |
3415 | - QMetaObject::invokeMethod(application, "onSessionSuspended"); |
3416 | - QMetaObject::invokeMethod(application, "onSessionResumed"); |
3417 | -} |
3418 | - |
3419 | -// Currently disabled as we need to make sure that we have a corresponding mir session, too. |
3420 | -TEST_F(ApplicationManagerTests, DISABLED_FocusingRunningApplicationResultsInOomScoreAdjustment) |
3421 | -{ |
3422 | - using namespace ::testing; |
3423 | - |
3424 | - const QString appId("com.canonical.does.not.exist"); |
3425 | - |
3426 | - QSet<QString> appIds; |
3427 | - |
3428 | - for (unsigned int i = 0; i < 50; i++) |
3429 | - { |
3430 | - QString appIdFormat("%1.does.not.exist"); |
3431 | - auto appId = appIdFormat.arg(i); |
3432 | - |
3433 | - auto application = applicationManager.startApplication( |
3434 | - appId, |
3435 | - ApplicationManager::NoFlag, |
3436 | - QStringList()); |
3437 | - |
3438 | - std::shared_ptr<mir::scene::Session> mirSession = std::make_shared<MockSession>(appIdFormat.toStdString(), i); |
3439 | - onSessionStarting( mirSession ); |
3440 | - |
3441 | - EXPECT_NE(nullptr, application); |
3442 | - } |
3443 | - |
3444 | - for (auto appId : appIds) |
3445 | - { |
3446 | - applicationManager.focusApplication(appId); |
3447 | - } |
3448 | -} |
3449 | - |
3450 | TEST_F(ApplicationManagerTests,bug_case_1240400_second_dialer_app_fails_to_authorize_and_gets_mixed_up_with_first_one) |
3451 | { |
3452 | using namespace ::testing; |
3453 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3454 | quint64 firstProcId = 5921; |
3455 | quint64 secondProcId = 5922; |
3456 | const char dialer_app_id[] = "dialer-app"; |
3457 | QByteArray cmdLine( "/usr/bin/dialer-app --desktop_file_hint=dialer-app"); |
3458 | QByteArray secondcmdLine( "/usr/bin/dialer-app"); |
3459 | |
3460 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
3461 | + |
3462 | EXPECT_CALL(procInfo,command_line(firstProcId)) |
3463 | .Times(1) |
3464 | .WillOnce(Return(cmdLine)); |
3465 | @@ -150,18 +92,20 @@ |
3466 | |
3467 | std::shared_ptr<mir::scene::Session> mirSession = std::make_shared<MockSession>(dialer_app_id, firstProcId); |
3468 | applicationManager.authorizeSession(firstProcId, authed); |
3469 | - EXPECT_EQ(true, authed); |
3470 | + ASSERT_EQ(true, authed); |
3471 | onSessionStarting(mirSession); |
3472 | - applicationManager.onSessionCreatedSurface(mirSession.get(),aSurface); |
3473 | - Application * app = applicationManager.findApplication(dialer_app_id); |
3474 | - EXPECT_NE(nullptr,app); |
3475 | + onSessionCreatedSurface(mirSession.get(), surface); |
3476 | + surface->drawFirstFrame(); |
3477 | + Application * application = applicationManager.findApplication(dialer_app_id); |
3478 | + ASSERT_NE(nullptr,application); |
3479 | + ASSERT_EQ(Application::InternalState::Running, application->internalState()); |
3480 | |
3481 | // now a second session without desktop file is launched: |
3482 | applicationManager.authorizeSession(secondProcId, authed); |
3483 | applicationManager.onProcessStarting(dialer_app_id); |
3484 | |
3485 | EXPECT_FALSE(authed); |
3486 | - EXPECT_EQ(app,applicationManager.findApplication(dialer_app_id)); |
3487 | + EXPECT_EQ(application, applicationManager.findApplication(dialer_app_id)); |
3488 | } |
3489 | |
3490 | TEST_F(ApplicationManagerTests,application_dies_while_starting) |
3491 | @@ -182,6 +126,7 @@ |
3492 | onSessionStarting(mirSession); |
3493 | Application * beforeFailure = applicationManager.findApplication(app_id); |
3494 | applicationManager.onProcessStarting(app_id); |
3495 | + onSessionStopping(mirSession); |
3496 | applicationManager.onProcessFailed(app_id, true); |
3497 | Application * afterFailure = applicationManager.findApplication(app_id); |
3498 | |
3499 | @@ -190,34 +135,6 @@ |
3500 | EXPECT_EQ(nullptr, afterFailure); |
3501 | } |
3502 | |
3503 | -TEST_F(ApplicationManagerTests,application_start_failure_after_starting) |
3504 | -{ |
3505 | - using namespace ::testing; |
3506 | - quint64 procId = 5921; |
3507 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3508 | - const char app_id[] = "my-app"; |
3509 | - QByteArray cmdLine( "/usr/bin/my-app --desktop_file_hint=my-app"); |
3510 | - |
3511 | - EXPECT_CALL(procInfo,command_line(procId)) |
3512 | - .Times(1) |
3513 | - .WillOnce(Return(cmdLine)); |
3514 | - |
3515 | - bool authed = true; |
3516 | - |
3517 | - std::shared_ptr<mir::scene::Session> mirSession = std::make_shared<MockSession>(app_id, procId); |
3518 | - applicationManager.authorizeSession(procId, authed); |
3519 | - onSessionStarting(mirSession); |
3520 | - Application * beforeFailure = applicationManager.findApplication(app_id); |
3521 | - applicationManager.onSessionCreatedSurface(mirSession.get(), aSurface); |
3522 | - applicationManager.onProcessStarting(app_id); |
3523 | - applicationManager.onProcessFailed(app_id, false); |
3524 | - Application * afterFailure = applicationManager.findApplication(app_id); |
3525 | - |
3526 | - EXPECT_EQ(true, authed); |
3527 | - EXPECT_NE(nullptr, beforeFailure); |
3528 | - EXPECT_EQ(beforeFailure, afterFailure); |
3529 | -} |
3530 | - |
3531 | TEST_F(ApplicationManagerTests,startApplicationSupportsShortAppId) |
3532 | { |
3533 | using namespace ::testing; |
3534 | @@ -400,7 +317,7 @@ |
3535 | quint64 a_procId = 5921; |
3536 | const char an_app_id[] = "some_app"; |
3537 | QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app"); |
3538 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3539 | + FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem; |
3540 | |
3541 | ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd)); |
3542 | |
3543 | @@ -413,8 +330,8 @@ |
3544 | applicationManager.authorizeSession(a_procId, authed); |
3545 | |
3546 | onSessionStarting(first_session); |
3547 | - applicationManager.focusApplication(an_app_id); |
3548 | - applicationManager.onSessionCreatedSurface(first_session.get(), aSurface); |
3549 | + onSessionCreatedSurface(first_session.get(), aSurface); |
3550 | + aSurface->drawFirstFrame(); |
3551 | onSessionStarting(second_session); |
3552 | |
3553 | Application * the_app = applicationManager.findApplication(an_app_id); |
3554 | @@ -430,211 +347,62 @@ |
3555 | quint64 a_procId = 5921; |
3556 | const char an_app_id[] = "some_app"; |
3557 | QByteArray a_cmd("/usr/bin/app1 --desktop_file_hint=some_app"); |
3558 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3559 | + FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem; |
3560 | |
3561 | ON_CALL(procInfo, command_line(_)).WillByDefault(Return(a_cmd)); |
3562 | ON_CALL(appController, appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3563 | - |
3564 | + |
3565 | bool authed = true; |
3566 | |
3567 | std::shared_ptr<mir::scene::Session> a_session = std::make_shared<MockSession>("Oo", a_procId); |
3568 | - |
3569 | + |
3570 | applicationManager.authorizeSession(a_procId, authed); |
3571 | onSessionStarting(a_session); |
3572 | - applicationManager.onSessionCreatedSurface(a_session.get(), aSurface); |
3573 | - |
3574 | - Application * the_app = applicationManager.findApplication(an_app_id); |
3575 | - applicationManager.focusApplication(an_app_id); |
3576 | - |
3577 | - EXPECT_EQ(Application::Running, the_app->state()); |
3578 | - EXPECT_EQ(true, the_app->focused()); |
3579 | - |
3580 | - applicationManager.focusApplication(an_app_id); |
3581 | - EXPECT_EQ(true, the_app->focused()); |
3582 | -} |
3583 | - |
3584 | -TEST_F(ApplicationManagerTests,suspended_suspends_focused_app_and_marks_it_unfocused_in_the_model) |
3585 | -{ |
3586 | - using namespace ::testing; |
3587 | - quint64 a_procId = 5921; |
3588 | - const char an_app_id[] = "some_app"; |
3589 | - QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app"); |
3590 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3591 | - |
3592 | - ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd)); |
3593 | - |
3594 | - ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3595 | - |
3596 | - bool authed = true; |
3597 | - |
3598 | - std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", a_procId); |
3599 | - std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", a_procId); |
3600 | - applicationManager.authorizeSession(a_procId, authed); |
3601 | - |
3602 | - onSessionStarting(first_session); |
3603 | - applicationManager.onSessionCreatedSurface(first_session.get(), aSurface); |
3604 | - onSessionStarting(second_session); |
3605 | - |
3606 | - Application * the_app = applicationManager.findApplication(an_app_id); |
3607 | - applicationManager.focusApplication(an_app_id); |
3608 | - |
3609 | - EXPECT_EQ(Application::Running, the_app->state()); |
3610 | - |
3611 | - applicationManager.setSuspended(true); |
3612 | - |
3613 | - EXPECT_EQ(Application::Suspended, the_app->state()); |
3614 | - EXPECT_FALSE(the_app->focused()); |
3615 | - |
3616 | - applicationManager.setSuspended(false); |
3617 | - |
3618 | - EXPECT_EQ(Application::Running, the_app->state()); |
3619 | - EXPECT_EQ(true, the_app->focused()); |
3620 | -} |
3621 | - |
3622 | -TEST_F(ApplicationManagerTests,suspended_suspends_starting_app_when_it_gets_ready) |
3623 | -{ |
3624 | - using namespace ::testing; |
3625 | - quint64 a_procId = 5921; |
3626 | - const char an_app_id[] = "some_app"; |
3627 | - QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app"); |
3628 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3629 | - |
3630 | - ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd)); |
3631 | - |
3632 | - ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3633 | - |
3634 | - bool authed = true; |
3635 | - |
3636 | - std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", a_procId); |
3637 | - applicationManager.authorizeSession(a_procId, authed); |
3638 | - |
3639 | - onSessionStarting(first_session); |
3640 | - |
3641 | - Application * the_app = applicationManager.findApplication(an_app_id); |
3642 | - applicationManager.focusApplication(an_app_id); |
3643 | - EXPECT_EQ(Application::Starting, the_app->state()); |
3644 | - |
3645 | - applicationManager.setSuspended(true); |
3646 | - |
3647 | - // Not suspending yet, as it's still starting |
3648 | - EXPECT_EQ(Application::Starting, the_app->state()); |
3649 | - |
3650 | - // This signals the app is ready now |
3651 | - applicationManager.onSessionCreatedSurface(first_session.get(), aSurface); |
3652 | - |
3653 | - // And given that the AppManager is suspended now, this should go to suspended too |
3654 | - EXPECT_EQ(Application::Suspended, the_app->state()); |
3655 | - EXPECT_FALSE(the_app->focused()); |
3656 | - |
3657 | - applicationManager.setSuspended(false); |
3658 | - |
3659 | - EXPECT_EQ(Application::Running, the_app->state()); |
3660 | - EXPECT_EQ(true, the_app->focused()); |
3661 | -} |
3662 | - |
3663 | -TEST_F(ApplicationManagerTests,focus_change_suspends_starting_app_when_it_gets_ready) |
3664 | -{ |
3665 | - using namespace ::testing; |
3666 | - quint64 first_procId = 5921; |
3667 | - quint64 second_procId = 5922; |
3668 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3669 | - QByteArray first_cmdLine( "/usr/bin/app1 --desktop_file_hint=app1"); |
3670 | - QByteArray second_cmdLine( "/usr/bin/app2--desktop_file_hint=app2"); |
3671 | - |
3672 | - EXPECT_CALL(procInfo,command_line(first_procId)) |
3673 | - .Times(1) |
3674 | - .WillOnce(Return(first_cmdLine)); |
3675 | - |
3676 | - ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3677 | - |
3678 | - EXPECT_CALL(procInfo,command_line(second_procId)) |
3679 | - .Times(1) |
3680 | - .WillOnce(Return(second_cmdLine)); |
3681 | - |
3682 | - bool authed = true; |
3683 | - |
3684 | - std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", first_procId); |
3685 | - std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", second_procId); |
3686 | - applicationManager.authorizeSession(first_procId, authed); |
3687 | - applicationManager.authorizeSession(second_procId, authed); |
3688 | - onSessionStarting(first_session); |
3689 | - |
3690 | - Application * app1 = applicationManager.findApplication("app1"); |
3691 | - applicationManager.focusApplication("app1"); |
3692 | + onSessionCreatedSurface(a_session.get(), aSurface); |
3693 | + aSurface->drawFirstFrame(); |
3694 | + |
3695 | + Application * the_app = applicationManager.findApplication(an_app_id); |
3696 | + applicationManager.focusApplication(an_app_id); |
3697 | + |
3698 | + EXPECT_EQ(Application::Running, the_app->state()); |
3699 | + EXPECT_EQ(true, the_app->focused()); |
3700 | + |
3701 | + applicationManager.focusApplication(an_app_id); |
3702 | + EXPECT_EQ(true, the_app->focused()); |
3703 | +} |
3704 | + |
3705 | +TEST_F(ApplicationManagerTests,starting_app_is_suspended_when_it_gets_ready_if_requested) |
3706 | +{ |
3707 | + using namespace ::testing; |
3708 | + quint64 procId = 5921; |
3709 | + FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem; |
3710 | + QByteArray cmdLine( "/usr/bin/app --desktop_file_hint=app"); |
3711 | + |
3712 | + EXPECT_CALL(procInfo,command_line(procId)) |
3713 | + .Times(1) |
3714 | + .WillOnce(Return(cmdLine)); |
3715 | + |
3716 | + ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3717 | + |
3718 | + bool authed = true; |
3719 | + |
3720 | + std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("Oo", procId); |
3721 | + applicationManager.authorizeSession(procId, authed); |
3722 | + onSessionStarting(session); |
3723 | + |
3724 | + Application * app = applicationManager.findApplication("app"); |
3725 | + app->setRequestedState(Application::RequestedSuspended); |
3726 | |
3727 | // First app starting... |
3728 | - EXPECT_EQ(Application::Starting, app1->state()); |
3729 | - |
3730 | - onSessionStarting(second_session); |
3731 | - Application * app2 = applicationManager.findApplication("app2"); |
3732 | - applicationManager.focusApplication("app2"); |
3733 | - |
3734 | - // Second app starting... |
3735 | - EXPECT_EQ(Application::Starting, app2->state()); |
3736 | - |
3737 | - // Make sure first one is still in starting state |
3738 | - EXPECT_EQ(Application::Starting, app1->state()); |
3739 | - |
3740 | - // Signal app1 is ready now |
3741 | - applicationManager.onSessionCreatedSurface(first_session.get(), aSurface); |
3742 | - |
3743 | - // Make sure AppMan suspended it now that its ready |
3744 | - EXPECT_EQ(Application::Suspended, app1->state()); |
3745 | -} |
3746 | - |
3747 | -TEST_F(ApplicationManagerTests,forceDashActive_activates_dash_while_not_focused) |
3748 | -{ |
3749 | - using namespace ::testing; |
3750 | - quint64 first_procId = 5921; |
3751 | - quint64 second_procId = 5922; |
3752 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
3753 | - QByteArray first_cmdLine( "/usr/bin/app1 --desktop_file_hint=unity8-dash"); |
3754 | - QByteArray second_cmdLine( "/usr/bin/app2--desktop_file_hint=app2"); |
3755 | - |
3756 | - EXPECT_CALL(procInfo,command_line(first_procId)) |
3757 | - .Times(1) |
3758 | - .WillOnce(Return(first_cmdLine)); |
3759 | - |
3760 | - ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
3761 | - |
3762 | - EXPECT_CALL(procInfo,command_line(second_procId)) |
3763 | - .Times(1) |
3764 | - .WillOnce(Return(second_cmdLine)); |
3765 | - |
3766 | - bool authed = true; |
3767 | - |
3768 | - std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", first_procId); |
3769 | - std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", second_procId); |
3770 | - applicationManager.authorizeSession(first_procId, authed); |
3771 | - applicationManager.authorizeSession(second_procId, authed); |
3772 | - onSessionStarting(first_session); |
3773 | - |
3774 | - Application * dashApp = applicationManager.findApplication("unity8-dash"); |
3775 | - applicationManager.onSessionCreatedSurface(first_session.get(), aSurface); |
3776 | - applicationManager.focusApplication("unity8-dash"); |
3777 | - |
3778 | - // Dash app should be ready now... |
3779 | - EXPECT_EQ(Application::Running, dashApp->state()); |
3780 | - |
3781 | - // Launch second app |
3782 | - onSessionStarting(second_session); |
3783 | - applicationManager.onSessionCreatedSurface(second_session.get(), aSurface); |
3784 | - applicationManager.focusApplication("app2"); |
3785 | - EXPECT_EQ(applicationManager.focusedApplicationId(), "app2"); |
3786 | - |
3787 | - // Make sure the dash is suspended |
3788 | - EXPECT_EQ(dashApp->state(), Application::Suspended); |
3789 | - |
3790 | - // Now set the dashactive flag |
3791 | - applicationManager.setForceDashActive(true); |
3792 | - |
3793 | - // And make sure the dash is woken up but not focused |
3794 | - EXPECT_EQ(applicationManager.focusedApplicationId(), "app2"); |
3795 | - EXPECT_EQ(dashApp->state(), Application::Running); |
3796 | - |
3797 | - // Unset the dashactive flag |
3798 | - applicationManager.setForceDashActive(false); |
3799 | - EXPECT_EQ(dashApp->state(), Application::Suspended); |
3800 | + EXPECT_EQ(Application::Starting, app->state()); |
3801 | + |
3802 | + // Signal app is ready now |
3803 | + applicationManager.onProcessStarting("app"); |
3804 | + onSessionCreatedSurface(session.get(), aSurface); |
3805 | + aSurface->drawFirstFrame(); |
3806 | + |
3807 | + // now that its ready, suspend process should have begun |
3808 | + EXPECT_EQ(Application::InternalState::SuspendingWaitSession, app->internalState()); |
3809 | } |
3810 | |
3811 | TEST_F(ApplicationManagerTests,requestFocusApplication) |
3812 | @@ -713,20 +481,20 @@ |
3813 | Application *theApp = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
3814 | |
3815 | // check application data |
3816 | - EXPECT_EQ(theApp->state(), Application::Starting); |
3817 | - EXPECT_EQ(theApp->appId(), appId); |
3818 | - EXPECT_EQ(theApp->name(), name); |
3819 | - EXPECT_EQ(theApp->canBeResumed(), true); |
3820 | + EXPECT_EQ(Application::Starting, theApp->state()); |
3821 | + EXPECT_EQ(appId, theApp->appId()); |
3822 | + EXPECT_EQ(name, theApp->name()); |
3823 | + EXPECT_FALSE(theApp->canBeResumed()); |
3824 | |
3825 | // check signals were emitted |
3826 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
3827 | - EXPECT_EQ(applicationManager.count(), 1); |
3828 | - EXPECT_EQ(addedSpy.count(), 1); |
3829 | - EXPECT_EQ(addedSpy.takeFirst().at(0).toString(), appId); |
3830 | + EXPECT_EQ(2, countSpy.count()); //FIXME(greyback) |
3831 | + EXPECT_EQ(1, applicationManager.count()); |
3832 | + EXPECT_EQ(1, addedSpy.count()); |
3833 | + EXPECT_EQ(appId, addedSpy.takeFirst().at(0).toString()); |
3834 | |
3835 | // check application in list of apps |
3836 | Application *theAppAgain = applicationManager.findApplication(appId); |
3837 | - EXPECT_EQ(theAppAgain, theApp); |
3838 | + EXPECT_EQ(theApp, theAppAgain); |
3839 | } |
3840 | |
3841 | /* |
3842 | @@ -757,18 +525,18 @@ |
3843 | Application *theApp = applicationManager.findApplication(appId); |
3844 | |
3845 | // check application data |
3846 | - EXPECT_EQ(theApp->state(), Application::Starting); |
3847 | - EXPECT_EQ(theApp->appId(), appId); |
3848 | - EXPECT_EQ(theApp->name(), name); |
3849 | - EXPECT_EQ(theApp->canBeResumed(), true); |
3850 | + EXPECT_EQ(Application::Starting, theApp->state()); |
3851 | + EXPECT_EQ(appId, theApp->appId()); |
3852 | + EXPECT_EQ(name, theApp->name()); |
3853 | + EXPECT_EQ(true, theApp->canBeResumed()); |
3854 | |
3855 | // check signals were emitted |
3856 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
3857 | - EXPECT_EQ(applicationManager.count(), 1); |
3858 | - EXPECT_EQ(addedSpy.count(), 1); |
3859 | - EXPECT_EQ(addedSpy.takeFirst().at(0).toString(), appId); |
3860 | - EXPECT_EQ(focusSpy.count(), 1); |
3861 | - EXPECT_EQ(focusSpy.takeFirst().at(0).toString(), appId); |
3862 | + EXPECT_EQ(2, countSpy.count()); //FIXME(greyback) |
3863 | + EXPECT_EQ(1, applicationManager.count()); |
3864 | + EXPECT_EQ(1, addedSpy.count()); |
3865 | + EXPECT_EQ(appId, addedSpy.takeFirst().at(0).toString()); |
3866 | + EXPECT_EQ(1, focusSpy.count()); |
3867 | + EXPECT_EQ(appId, focusSpy.takeFirst().at(0).toString()); |
3868 | } |
3869 | |
3870 | /* |
3871 | @@ -1067,7 +835,6 @@ |
3872 | |
3873 | applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
3874 | applicationManager.onProcessStarting(appId); |
3875 | - applicationManager.focusApplication(appId); |
3876 | |
3877 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
3878 | |
3879 | @@ -1075,9 +842,10 @@ |
3880 | applicationManager.authorizeSession(procId, authed); |
3881 | onSessionStarting(session); |
3882 | |
3883 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
3884 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
3885 | |
3886 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
3887 | + onSessionCreatedSurface(session.get(), surface); |
3888 | + surface->drawFirstFrame(); |
3889 | |
3890 | // Check application state is correctly set |
3891 | Application *theApp = applicationManager.findApplication(appId); |
3892 | @@ -1124,7 +892,7 @@ |
3893 | } |
3894 | |
3895 | /* |
3896 | - * Test that the foreground application is stopped correctly (is in Running state, has surface) |
3897 | + * Test that a running application is stopped correctly (is in Running state, has surface) |
3898 | */ |
3899 | TEST_F(ApplicationManagerTests,shellStopsForegroundAppCorrectly) |
3900 | { |
3901 | @@ -1150,100 +918,61 @@ |
3902 | applicationManager.authorizeSession(procId, authed); |
3903 | onSessionStarting(session); |
3904 | |
3905 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
3906 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
3907 | - applicationManager.focusApplication(appId); |
3908 | - EXPECT_EQ(applicationManager.focusedApplicationId(), appId); |
3909 | - |
3910 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
3911 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
3912 | - |
3913 | - // Stop app |
3914 | - applicationManager.stopApplication(appId); |
3915 | - |
3916 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
3917 | - EXPECT_EQ(applicationManager.count(), 0); |
3918 | - EXPECT_EQ(removedSpy.count(), 1); |
3919 | - EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId); |
3920 | -} |
3921 | - |
3922 | -/* |
3923 | - * Test that the background application is stopped correctly |
3924 | - */ |
3925 | -TEST_F(ApplicationManagerTests,shellStopsBackgroundAppCorrectly) |
3926 | -{ |
3927 | - using namespace ::testing; |
3928 | - const QString appId("testAppId"); |
3929 | - quint64 procId = 5551; |
3930 | - |
3931 | - // Set up Mocks & signal watcher |
3932 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
3933 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
3934 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
3935 | - |
3936 | - ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
3937 | - |
3938 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
3939 | - .Times(1) |
3940 | - .WillOnce(Return(true)); |
3941 | - |
3942 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
3943 | - applicationManager.onProcessStarting(appId); |
3944 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
3945 | - bool authed = true; |
3946 | - applicationManager.authorizeSession(procId, authed); |
3947 | - onSessionStarting(session); |
3948 | - |
3949 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
3950 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
3951 | - applicationManager.unfocusCurrentApplication(); |
3952 | - |
3953 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
3954 | - |
3955 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
3956 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
3957 | - |
3958 | - // Stop app |
3959 | - applicationManager.stopApplication(appId); |
3960 | - |
3961 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
3962 | - EXPECT_EQ(applicationManager.count(), 0); |
3963 | - EXPECT_EQ(removedSpy.count(), 1); |
3964 | - EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId); |
3965 | -} |
3966 | - |
3967 | -/* |
3968 | - * Test that if an application is stopped by upstart, before it has created a surface, AppMan cleans up after it ok |
3969 | - */ |
3970 | -TEST_F(ApplicationManagerTests,upstartNotificationOfStartingAppBeingStopped) |
3971 | -{ |
3972 | - using namespace ::testing; |
3973 | - const QString appId("testAppId"); |
3974 | - quint64 procId = 5551; |
3975 | - |
3976 | - // Set up Mocks & signal watcher |
3977 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
3978 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
3979 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
3980 | - |
3981 | - ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
3982 | - |
3983 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
3984 | - .Times(1) |
3985 | - .WillOnce(Return(true)); |
3986 | - |
3987 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
3988 | - applicationManager.onProcessStarting(appId); |
3989 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
3990 | - bool authed = true; |
3991 | - applicationManager.authorizeSession(procId, authed); |
3992 | - onSessionStarting(session); |
3993 | - |
3994 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
3995 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
3996 | - |
3997 | - // Upstart notifies of stopping app |
3998 | - applicationManager.onProcessStopped(appId); |
3999 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4000 | + onSessionCreatedSurface(session.get(), surface); |
4001 | + surface->drawFirstFrame(); |
4002 | + |
4003 | + QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4004 | + QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4005 | + |
4006 | + // Stop app |
4007 | + applicationManager.stopApplication(appId); |
4008 | + |
4009 | + EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
4010 | + EXPECT_EQ(applicationManager.count(), 0); |
4011 | + EXPECT_EQ(removedSpy.count(), 1); |
4012 | + EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId); |
4013 | +} |
4014 | + |
4015 | +/* |
4016 | + * Test that a suspended application is stopped correctly |
4017 | + */ |
4018 | +TEST_F(ApplicationManagerTests,shellStopsSuspendedAppCorrectly) |
4019 | +{ |
4020 | + using namespace ::testing; |
4021 | + const QString appId("testAppId"); |
4022 | + quint64 procId = 5551; |
4023 | + |
4024 | + // Set up Mocks & signal watcher |
4025 | + auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
4026 | + ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4027 | + ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
4028 | + |
4029 | + ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
4030 | + |
4031 | + EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
4032 | + .Times(1) |
4033 | + .WillOnce(Return(true)); |
4034 | + |
4035 | + Application *application = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4036 | + applicationManager.onProcessStarting(appId); |
4037 | + std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4038 | + bool authed = true; |
4039 | + applicationManager.authorizeSession(procId, authed); |
4040 | + onSessionStarting(session); |
4041 | + applicationManager.onProcessStarting(appId); |
4042 | + |
4043 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4044 | + onSessionCreatedSurface(session.get(), surface); |
4045 | + surface->drawFirstFrame(); |
4046 | + |
4047 | + suspend(application); |
4048 | + |
4049 | + QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4050 | + QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4051 | + |
4052 | + // Stop app |
4053 | + applicationManager.stopApplication(appId); |
4054 | |
4055 | EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
4056 | EXPECT_EQ(applicationManager.count(), 0); |
4057 | @@ -1278,28 +1007,28 @@ |
4058 | applicationManager.authorizeSession(procId, authed); |
4059 | onSessionStarting(session); |
4060 | |
4061 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4062 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4063 | - applicationManager.focusApplication(appId); |
4064 | - EXPECT_EQ(applicationManager.focusedApplicationId(), appId); |
4065 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4066 | + onSessionCreatedSurface(session.get(), surface); |
4067 | + surface->drawFirstFrame(); |
4068 | |
4069 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4070 | QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4071 | |
4072 | + onSessionStopping(session); |
4073 | // Upstart notifies of stopping app |
4074 | applicationManager.onProcessStopped(appId); |
4075 | |
4076 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
4077 | - EXPECT_EQ(applicationManager.count(), 0); |
4078 | - EXPECT_EQ(removedSpy.count(), 1); |
4079 | - EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId); |
4080 | + EXPECT_EQ(2, countSpy.count()); //FIXME(greyback) |
4081 | + EXPECT_EQ(0, applicationManager.count()); |
4082 | + EXPECT_EQ(1, removedSpy.count()); |
4083 | + EXPECT_EQ(appId, removedSpy.takeFirst().at(0).toString()); |
4084 | } |
4085 | |
4086 | /* |
4087 | - * Test that if the foreground Running application is reported to unexpectedly stop by upstart, AppMan |
4088 | - * cleans up after it ok (as was not in background, had not lifecycle saved its state, so cannot be resumed) |
4089 | + * Test that if a running application is reported to have stopped unexpectedly by upstart, AppMan |
4090 | + * cleans up after it ok (as was not suspended, had not lifecycle saved its state, so cannot be resumed) |
4091 | */ |
4092 | -TEST_F(ApplicationManagerTests,upstartNotifiesOfUnexpectedStopOfForegroundApp) |
4093 | +TEST_F(ApplicationManagerTests,upstartNotifiesOfUnexpectedStopOfRunningApp) |
4094 | { |
4095 | using namespace ::testing; |
4096 | const QString appId("testAppId"); |
4097 | @@ -1323,14 +1052,15 @@ |
4098 | applicationManager.authorizeSession(procId, authed); |
4099 | onSessionStarting(session); |
4100 | |
4101 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4102 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4103 | - applicationManager.focusApplication(appId); |
4104 | - EXPECT_EQ(applicationManager.focusedApplicationId(), appId); |
4105 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4106 | + onSessionCreatedSurface(session.get(), surface); |
4107 | + surface->drawFirstFrame(); |
4108 | |
4109 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4110 | QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4111 | |
4112 | + onSessionStopping(session); |
4113 | + |
4114 | // Upstart notifies of crashing / OOM killed app |
4115 | applicationManager.onProcessFailed(appId, false); |
4116 | |
4117 | @@ -1344,53 +1074,6 @@ |
4118 | } |
4119 | |
4120 | /* |
4121 | - * Test that if a background application is stopped by upstart, AppMan removes it from the app list |
4122 | - * as the event is a result of direct user interaction |
4123 | - */ |
4124 | -TEST_F(ApplicationManagerTests,upstartNotifiesOfStoppingBackgroundApp) |
4125 | -{ |
4126 | - using namespace ::testing; |
4127 | - const QString appId("testAppId"); |
4128 | - quint64 procId = 5551; |
4129 | - |
4130 | - // Set up Mocks & signal watcher |
4131 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
4132 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4133 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
4134 | - |
4135 | - ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
4136 | - |
4137 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
4138 | - .Times(1) |
4139 | - .WillOnce(Return(true)); |
4140 | - |
4141 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4142 | - applicationManager.onProcessStarting(appId); |
4143 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4144 | - bool authed = true; |
4145 | - applicationManager.authorizeSession(procId, authed); |
4146 | - onSessionStarting(session); |
4147 | - |
4148 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4149 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4150 | - applicationManager.unfocusCurrentApplication(); |
4151 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
4152 | - |
4153 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4154 | - QSignalSpy focusSpy(&applicationManager, SIGNAL(focusedApplicationIdChanged())); |
4155 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4156 | - |
4157 | - // Upstart notifies of stopping app |
4158 | - applicationManager.onProcessStopped(appId); |
4159 | - |
4160 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
4161 | - EXPECT_EQ(applicationManager.count(), 0); |
4162 | - EXPECT_EQ(focusSpy.count(), 0); |
4163 | - EXPECT_EQ(removedSpy.count(), 1); |
4164 | - EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId); |
4165 | -} |
4166 | - |
4167 | -/* |
4168 | * Test that if a background application is reported to unexpectedly stop by upstart, AppMan does not remove |
4169 | * it from the app lists but instead considers it Stopped, ready to be resumed. This is due to the fact the |
4170 | * app should have saved its state, so can be resumed. This situation can occur due to the OOM killer, or |
4171 | @@ -1413,18 +1096,18 @@ |
4172 | .Times(1) |
4173 | .WillOnce(Return(true)); |
4174 | |
4175 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4176 | + Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4177 | applicationManager.onProcessStarting(appId); |
4178 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4179 | bool authed = true; |
4180 | applicationManager.authorizeSession(procId, authed); |
4181 | onSessionStarting(session); |
4182 | |
4183 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4184 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4185 | - applicationManager.focusApplication(appId); |
4186 | - applicationManager.unfocusCurrentApplication(); |
4187 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
4188 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4189 | + onSessionCreatedSurface(session.get(), surface); |
4190 | + surface->drawFirstFrame(); |
4191 | + |
4192 | + suspend(app); |
4193 | |
4194 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4195 | QSignalSpy focusSpy(&applicationManager, SIGNAL(focusedApplicationIdChanged())); |
4196 | @@ -1436,14 +1119,14 @@ |
4197 | // Upstart notifies of crashing / OOM-killed app |
4198 | applicationManager.onProcessFailed(appId, false); |
4199 | |
4200 | - EXPECT_EQ(focusSpy.count(), 0); |
4201 | + EXPECT_EQ(0, focusSpy.count()); |
4202 | |
4203 | // Upstart finally notifies the app stopped |
4204 | applicationManager.onProcessStopped(appId); |
4205 | |
4206 | - EXPECT_EQ(countSpy.count(), 0); |
4207 | - EXPECT_EQ(applicationManager.count(), 1); |
4208 | - EXPECT_EQ(removedSpy.count(), 0); |
4209 | + EXPECT_EQ(0, countSpy.count()); |
4210 | + EXPECT_EQ(1, applicationManager.count()); |
4211 | + EXPECT_EQ(0, removedSpy.count()); |
4212 | } |
4213 | |
4214 | /* |
4215 | @@ -1471,18 +1154,18 @@ |
4216 | .Times(1) |
4217 | .WillOnce(Return(true)); |
4218 | |
4219 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4220 | + Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4221 | applicationManager.onProcessStarting(appId); |
4222 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4223 | bool authed = true; |
4224 | applicationManager.authorizeSession(procId, authed); |
4225 | onSessionStarting(session); |
4226 | |
4227 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4228 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4229 | - applicationManager.focusApplication(appId); |
4230 | - applicationManager.unfocusCurrentApplication(); |
4231 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
4232 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4233 | + onSessionCreatedSurface(session.get(), surface); |
4234 | + surface->drawFirstFrame(); |
4235 | + |
4236 | + suspend(app); |
4237 | |
4238 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4239 | QSignalSpy focusSpy(&applicationManager, SIGNAL(focusedApplicationIdChanged())); |
4240 | @@ -1571,10 +1254,9 @@ |
4241 | onSessionStarting(session); |
4242 | |
4243 | // Associate a surface so AppMan considers app Running, check focused |
4244 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4245 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4246 | - applicationManager.focusApplication(appId); |
4247 | - EXPECT_EQ(applicationManager.focusedApplicationId(), appId); |
4248 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4249 | + onSessionCreatedSurface(session.get(), surface); |
4250 | + surface->drawFirstFrame(); |
4251 | |
4252 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4253 | QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4254 | @@ -1589,10 +1271,10 @@ |
4255 | } |
4256 | |
4257 | /* |
4258 | - * Test that if a foreground application (one launched via desktop_file_hint) is reported to be stopping by |
4259 | + * Test that if an application (one launched via desktop_file_hint) is reported to be stopping by |
4260 | * Mir, AppMan removes it from the model immediately |
4261 | */ |
4262 | -TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingForegroundAppLaunchedWithDesktopFileHint) |
4263 | +TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingAppLaunchedWithDesktopFileHint) |
4264 | { |
4265 | using namespace ::testing; |
4266 | const QString appId("testAppId"); |
4267 | @@ -1621,10 +1303,9 @@ |
4268 | onSessionStarting(session); |
4269 | |
4270 | // Associate a surface so AppMan considers app Running, check focused |
4271 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4272 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4273 | - applicationManager.focusApplication(appId); |
4274 | - EXPECT_EQ(applicationManager.focusedApplicationId(), appId); |
4275 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4276 | + onSessionCreatedSurface(session.get(), surface); |
4277 | + surface->drawFirstFrame(); |
4278 | |
4279 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4280 | QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4281 | @@ -1661,86 +1342,43 @@ |
4282 | .Times(1) |
4283 | .WillOnce(Return(true)); |
4284 | |
4285 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4286 | + Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4287 | applicationManager.onProcessStarting(appId); |
4288 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4289 | bool authed = true; |
4290 | applicationManager.authorizeSession(procId, authed); |
4291 | onSessionStarting(session); |
4292 | - |
4293 | - // Associate a surface so AppMan considers app Running, check in background |
4294 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4295 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4296 | - applicationManager.focusApplication(appId); |
4297 | - applicationManager.unfocusCurrentApplication(); |
4298 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
4299 | - |
4300 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4301 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4302 | - |
4303 | - // Mir notifies of stopping app |
4304 | - onSessionStopping(session); |
4305 | - |
4306 | - EXPECT_EQ(countSpy.count(), 0); |
4307 | - EXPECT_EQ(applicationManager.count(), 1); |
4308 | - EXPECT_EQ(removedSpy.count(), 0); |
4309 | - |
4310 | - Application * app = applicationManager.findApplication(appId); |
4311 | - EXPECT_NE(nullptr,app); |
4312 | - EXPECT_EQ(app->state(), Application::Stopped); |
4313 | -} |
4314 | - |
4315 | -/* |
4316 | - * Test that if a background application (one launched via desktop_file_hint) is reported to be stopping by |
4317 | - * Mir, AppMan removes it from the model immediately |
4318 | - */ |
4319 | -TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingBackgroundAppLaunchedWithDesktopFileHint) |
4320 | -{ |
4321 | - using namespace ::testing; |
4322 | - const QString appId("testAppId"); |
4323 | - const QString name("Test App"); |
4324 | - quint64 procId = 5551; |
4325 | - QByteArray cmdLine("/usr/bin/testApp --desktop_file_hint="); |
4326 | - cmdLine = cmdLine.append(appId); |
4327 | - |
4328 | - // Set up Mocks & signal watcher |
4329 | - EXPECT_CALL(procInfo,command_line(procId)) |
4330 | - .Times(1) |
4331 | - .WillOnce(Return(cmdLine)); |
4332 | - |
4333 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
4334 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4335 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
4336 | - ON_CALL(*mockDesktopFileReader, name()).WillByDefault(Return(name)); |
4337 | - |
4338 | - ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
4339 | - |
4340 | - // Mir requests authentication for an application that was started |
4341 | - bool authed = true; |
4342 | - applicationManager.authorizeSession(procId, authed); |
4343 | - EXPECT_EQ(authed, true); |
4344 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4345 | - onSessionStarting(session); |
4346 | - |
4347 | - // Associate a surface so AppMan considers app Running, check in background |
4348 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4349 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4350 | - applicationManager.focusApplication(appId); |
4351 | - applicationManager.unfocusCurrentApplication(); |
4352 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
4353 | - |
4354 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4355 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4356 | - |
4357 | - // Mir notifies of stopping app |
4358 | - onSessionStopping(session); |
4359 | - |
4360 | - EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback) |
4361 | - EXPECT_EQ(applicationManager.count(), 0); |
4362 | - EXPECT_EQ(removedSpy.count(), 1); |
4363 | - |
4364 | - Application * app = applicationManager.findApplication(appId); |
4365 | - EXPECT_EQ(nullptr,app); |
4366 | + EXPECT_EQ(Application::Starting, app->state()); |
4367 | + |
4368 | + app->setRequestedState(Application::RequestedSuspended); |
4369 | + |
4370 | + // should not suspend an app that`s still starting up |
4371 | + ASSERT_EQ(Application::InternalState::Starting, app->internalState()); |
4372 | + |
4373 | + // Associate a surface so AppMan considers app Running |
4374 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4375 | + onSessionCreatedSurface(session.get(), surface); |
4376 | + surface->drawFirstFrame(); |
4377 | + |
4378 | + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, app->internalState()); |
4379 | + |
4380 | + static_cast<qtmir::Session*>(app->session())->doSuspend(); |
4381 | + ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, app->internalState()); |
4382 | + |
4383 | + applicationManager.onProcessSuspended(app->appId()); |
4384 | + ASSERT_EQ(Application::InternalState::Suspended, app->internalState()); |
4385 | + |
4386 | + QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4387 | + QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4388 | + |
4389 | + // Mir notifies of stopping app |
4390 | + onSessionStopping(session); |
4391 | + |
4392 | + EXPECT_EQ(0, countSpy.count()); |
4393 | + EXPECT_EQ(1, applicationManager.count()); |
4394 | + EXPECT_EQ(0, removedSpy.count()); |
4395 | + |
4396 | + EXPECT_EQ(Application::Stopped, app->state()); |
4397 | } |
4398 | |
4399 | /* |
4400 | @@ -1822,45 +1460,6 @@ |
4401 | } |
4402 | |
4403 | /* |
4404 | - * Test that if an application is stopped by upstart, the Mir stopping event is ignored |
4405 | - */ |
4406 | -TEST_F(ApplicationManagerTests,appStoppedByUpstart_mirSessionStoppingEventIgnored) |
4407 | -{ |
4408 | - using namespace ::testing; |
4409 | - const QString appId("testAppId"); |
4410 | - quint64 procId = 5551; |
4411 | - |
4412 | - // Set up Mocks & signal watcher |
4413 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
4414 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4415 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
4416 | - |
4417 | - ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
4418 | - |
4419 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
4420 | - .Times(1) |
4421 | - .WillOnce(Return(true)); |
4422 | - |
4423 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4424 | - applicationManager.onProcessStarting(appId); |
4425 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4426 | - bool authed = true; |
4427 | - applicationManager.authorizeSession(procId, authed); |
4428 | - onSessionStarting(session); |
4429 | - |
4430 | - applicationManager.onProcessStopped(appId); |
4431 | - |
4432 | - QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4433 | - QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4434 | - |
4435 | - // Mir notifies of stopping app |
4436 | - onSessionStopping(session); |
4437 | - |
4438 | - EXPECT_EQ(countSpy.count(), 0); |
4439 | - EXPECT_EQ(removedSpy.count(), 0); |
4440 | -} |
4441 | - |
4442 | -/* |
4443 | * Webapps have multiple sessions, but only one is linked to the application (other is considered a hidden session). |
4444 | * If webapp in foreground stops unexpectedly, remove it and it alone from app list |
4445 | */ |
4446 | @@ -1903,8 +1502,9 @@ |
4447 | applicationManager.authorizeSession(procId2, authed); |
4448 | onSessionStarting(session2); |
4449 | EXPECT_EQ(authed, true); |
4450 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4451 | - applicationManager.onSessionCreatedSurface(session2.get(), surface); |
4452 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4453 | + onSessionCreatedSurface(session2.get(), surface); |
4454 | + surface->drawFirstFrame(); |
4455 | |
4456 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4457 | QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4458 | @@ -1950,7 +1550,7 @@ |
4459 | .Times(1) |
4460 | .WillOnce(Return(true)); |
4461 | |
4462 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4463 | + Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4464 | applicationManager.onProcessStarting(appId); |
4465 | std::shared_ptr<mir::scene::Session> session1 = std::make_shared<MockSession>("", procId1); |
4466 | std::shared_ptr<mir::scene::Session> session2 = std::make_shared<MockSession>("", procId2); |
4467 | @@ -1958,19 +1558,20 @@ |
4468 | bool authed = false; |
4469 | applicationManager.authorizeSession(procId1, authed); |
4470 | onSessionStarting(session1); |
4471 | - EXPECT_EQ(authed, true); |
4472 | + EXPECT_EQ(true, authed); |
4473 | applicationManager.authorizeSession(procId2, authed); |
4474 | onSessionStarting(session2); |
4475 | - EXPECT_EQ(authed, true); |
4476 | + EXPECT_EQ(true, authed); |
4477 | |
4478 | - // both sessions create surfaces, then unfocus everything. |
4479 | - std::shared_ptr<mir::scene::Surface> surface1(nullptr); |
4480 | - applicationManager.onSessionCreatedSurface(session1.get(), surface1); |
4481 | - std::shared_ptr<mir::scene::Surface> surface2(nullptr); |
4482 | - applicationManager.onSessionCreatedSurface(session2.get(), surface2); |
4483 | - applicationManager.focusApplication(appId); |
4484 | - applicationManager.unfocusCurrentApplication(); |
4485 | - EXPECT_EQ(applicationManager.focusedApplicationId(), QString()); |
4486 | + // both sessions create surfaces, then get them all suspended |
4487 | + FakeMirSurfaceItem *surface1 = new FakeMirSurfaceItem; |
4488 | + onSessionCreatedSurface(session1.get(), surface1); |
4489 | + surface1->drawFirstFrame(); |
4490 | + FakeMirSurfaceItem *surface2 = new FakeMirSurfaceItem; |
4491 | + onSessionCreatedSurface(session2.get(), surface2); |
4492 | + surface2->drawFirstFrame(); |
4493 | + suspend(app); |
4494 | + EXPECT_EQ(Application::Suspended, app->state()); |
4495 | |
4496 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
4497 | QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &))); |
4498 | @@ -1979,8 +1580,104 @@ |
4499 | onSessionStopping(session2); |
4500 | onSessionStopping(session1); |
4501 | |
4502 | - EXPECT_EQ(countSpy.count(), 0); |
4503 | - EXPECT_EQ(removedSpy.count(), 0); |
4504 | + EXPECT_EQ(0, countSpy.count()); |
4505 | + EXPECT_EQ(0, removedSpy.count()); |
4506 | +} |
4507 | + |
4508 | +/* |
4509 | + * Test requested surface size unchanged if no surfaceSizer registered |
4510 | + */ |
4511 | +TEST_F(ApplicationManagerTests, registerSurfaceSizeUnchangedWhenNoSizerCallbackRegistered) |
4512 | +{ |
4513 | + using namespace ::testing; |
4514 | + quint64 procId = 5551; |
4515 | + SurfaceParameters params; |
4516 | + params.geometry = {400, 250}; // can be overridden |
4517 | + |
4518 | + const auto session = std::make_shared<MockSession>("", procId); |
4519 | + applicationManager.onSessionAboutToCreateSurface(session, params); |
4520 | + |
4521 | + EXPECT_EQ(params.geometry, QSize(400, 250)); |
4522 | +} |
4523 | + |
4524 | +/* |
4525 | + * Test registerSurfaceSizerCallback functionality |
4526 | + */ |
4527 | +TEST_F(ApplicationManagerTests, registerSurfaceSizerFunctional) |
4528 | +{ |
4529 | + using namespace ::testing; |
4530 | + quint64 procId = 5551; |
4531 | + SurfaceParameters params; |
4532 | + params.geometry = {400, 250}; // can be overridden |
4533 | + |
4534 | + QJSValue callback = jsEngine->evaluate("(function(surface) { surface.width = 111; return surface; })"); |
4535 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4536 | + |
4537 | + const auto session = std::make_shared<MockSession>("", procId); |
4538 | + applicationManager.onSessionAboutToCreateSurface(session, params); |
4539 | + |
4540 | + EXPECT_EQ(params.geometry, QSize(111, 250)); |
4541 | +} |
4542 | + |
4543 | +/* |
4544 | + * Test deregisterSurfaceSizerCallback correctly removes the callback |
4545 | + */ |
4546 | +TEST_F(ApplicationManagerTests, deregisterSurfaceSizerWorks) |
4547 | +{ |
4548 | + using namespace ::testing; |
4549 | + quint64 procId = 5551; |
4550 | + SurfaceParameters params; |
4551 | + params.geometry = {400, 250}; // can be overridden |
4552 | + |
4553 | + QJSValue callback = jsEngine->evaluate("(function(surface) { surface.width = 111; return surface; })"); |
4554 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4555 | + |
4556 | + const auto session = std::make_shared<MockSession>("", procId); |
4557 | + |
4558 | + applicationManager.setSurfaceAboutToBeCreatedCallback(false); |
4559 | + applicationManager.onSessionAboutToCreateSurface(session, params); |
4560 | + |
4561 | + EXPECT_EQ(params.geometry, QSize(400, 250)); // should be unchanged |
4562 | +} |
4563 | + |
4564 | +/* |
4565 | + * Test registerSurfaceSizerCallback rejects an uncallable QJSValue (i.e. something that's not a function was passed) |
4566 | + */ |
4567 | +TEST_F(ApplicationManagerTests, registerSurfaceSizerRejectsNonCallableJSValues) |
4568 | +{ |
4569 | + using namespace ::testing; |
4570 | + |
4571 | + QJSValue callback = jsEngine->evaluate("21"); |
4572 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4573 | + |
4574 | + callback = jsEngine->evaluate("true"); |
4575 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4576 | + |
4577 | + callback = jsEngine->evaluate("{}"); |
4578 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4579 | + |
4580 | + callback = jsEngine->evaluate("new Array()"); |
4581 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4582 | +} |
4583 | + |
4584 | +/* |
4585 | + * Test in case that registered SurfaceSizerCallback does not return a type with a 'width' (or 'height') property, |
4586 | + * we return the requested surface width/height unchanged |
4587 | + */ |
4588 | +TEST_F(ApplicationManagerTests, registeredSurfaceSizerDealswithBadReturns) |
4589 | +{ |
4590 | + using namespace ::testing; |
4591 | + quint64 procId = 5551; |
4592 | + SurfaceParameters params; |
4593 | + params.geometry = {400, 250}; // can be overridden |
4594 | + |
4595 | + QJSValue callback = jsEngine->evaluate("(function(s) { var out = new Object(); out.height = 333; return out; })"); |
4596 | + applicationManager.setSurfaceAboutToBeCreatedCallback(callback); |
4597 | + |
4598 | + const auto session = std::make_shared<MockSession>("", procId); |
4599 | + applicationManager.onSessionAboutToCreateSurface(session, params); |
4600 | + |
4601 | + EXPECT_EQ(params.geometry, QSize(400, 333)); |
4602 | } |
4603 | |
4604 | /* |
4605 | @@ -2007,34 +1704,33 @@ |
4606 | .Times(1) |
4607 | .WillOnce(Return(true)); |
4608 | |
4609 | - applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4610 | + Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4611 | applicationManager.onProcessStarting(appId); |
4612 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4613 | bool authed = true; |
4614 | applicationManager.authorizeSession(procId, authed); |
4615 | onSessionStarting(session); |
4616 | |
4617 | - // App creates surface, focuses it, puts it in background, then is OOM killed. |
4618 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4619 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4620 | - applicationManager.focusApplication(appId); |
4621 | - applicationManager.unfocusCurrentApplication(); |
4622 | + // App creates surface, puts it in background, then is OOM killed. |
4623 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4624 | + onSessionCreatedSurface(session.get(), surface); |
4625 | + surface->drawFirstFrame(); |
4626 | + suspend(app); |
4627 | |
4628 | onSessionStopping(session); |
4629 | applicationManager.onProcessFailed(appId, false); |
4630 | applicationManager.onProcessStopped(appId); |
4631 | |
4632 | - Application *app = applicationManager.findApplication(appId); |
4633 | - EXPECT_EQ(app->state(), Application::Stopped); |
4634 | + EXPECT_EQ(Application::Stopped, app->state()); |
4635 | |
4636 | QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &))); |
4637 | |
4638 | // Upstart re-launches app |
4639 | applicationManager.onProcessStarting(appId); |
4640 | |
4641 | - EXPECT_EQ(app->state(), Application::Starting); |
4642 | - EXPECT_EQ(focusRequestSpy.count(), 1); |
4643 | - EXPECT_EQ(applicationManager.count(), 1); |
4644 | + EXPECT_EQ(Application::Starting, app->state()); |
4645 | + EXPECT_EQ(1, focusRequestSpy.count()); |
4646 | + EXPECT_EQ(1, applicationManager.count()); |
4647 | } |
4648 | |
4649 | /* |
4650 | @@ -2138,142 +1834,61 @@ |
4651 | } |
4652 | } |
4653 | |
4654 | -/* |
4655 | - 1 - launch and focus a main stage app |
4656 | - * main stage app is running and focused |
4657 | - 2 - launch and focus a side stage app |
4658 | - * main stage app is running but is not focused |
4659 | - * side stage app is running and has focus |
4660 | - 3 - focus the main stage app |
4661 | - * main stage app is running and has focus |
4662 | - * side stage app is running but is not focused |
4663 | - |
4664 | - This is a regression test for the bug where on step 3, the main stage app was momentarily |
4665 | - suspended and then resumed again. |
4666 | - */ |
4667 | -TEST_F(ApplicationManagerTests, focusMainStageAfterSideStage) |
4668 | -{ |
4669 | - using namespace testing; |
4670 | - |
4671 | - QString webbrowserAppId("webbrowser-app"); |
4672 | - quint64 webbrowserPID = 123; |
4673 | - std::shared_ptr<mir::scene::Surface> webbrowserSurface(nullptr); |
4674 | - |
4675 | - QString dialerAppId("dialer-app"); |
4676 | - quint64 dialerPID = 456; |
4677 | - std::shared_ptr<mir::scene::Surface> dialerSurface(nullptr); |
4678 | - |
4679 | - /*** Start webbrowser-app (main stage) ***/ |
4680 | - |
4681 | - ON_CALL(appController,appIdHasProcessId(webbrowserPID, webbrowserAppId)).WillByDefault(Return(true)); |
4682 | - |
4683 | - { |
4684 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(webbrowserAppId, QFileInfo()); |
4685 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4686 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(webbrowserAppId)); |
4687 | - ON_CALL(*mockDesktopFileReader, stageHint()).WillByDefault(Return("MainStage")); |
4688 | - |
4689 | - ON_CALL(desktopFileReaderFactory, createInstance(webbrowserAppId, _)) |
4690 | - .WillByDefault(Return(mockDesktopFileReader)); |
4691 | - } |
4692 | - |
4693 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(webbrowserAppId, _)) |
4694 | - .Times(1) |
4695 | - .WillOnce(Return(true)); |
4696 | - |
4697 | - /*auto application =*/ applicationManager.startApplication(webbrowserAppId, ApplicationManager::NoFlag); |
4698 | - applicationManager.onProcessStarting(webbrowserAppId); |
4699 | - |
4700 | - { |
4701 | - bool authed = false; |
4702 | - applicationManager.authorizeSession(webbrowserPID, authed); |
4703 | - EXPECT_EQ(authed, true); |
4704 | - } |
4705 | - |
4706 | - auto webbrowserSession = std::make_shared<mir::scene::MockSession>(webbrowserAppId.toStdString(), webbrowserPID); |
4707 | - sessionManager.onSessionStarting(webbrowserSession); |
4708 | - applicationManager.focusApplication(webbrowserAppId); |
4709 | - applicationManager.onSessionCreatedSurface(webbrowserSession.get(), webbrowserSurface); |
4710 | - |
4711 | - /*** Start dialer-app (side stage) ***/ |
4712 | - |
4713 | - ON_CALL(appController, appIdHasProcessId(dialerPID, dialerAppId)).WillByDefault(Return(true)); |
4714 | - |
4715 | - { |
4716 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(dialerAppId, QFileInfo()); |
4717 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4718 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(dialerAppId)); |
4719 | - ON_CALL(*mockDesktopFileReader, stageHint()).WillByDefault(Return("SideStage")); |
4720 | - |
4721 | - ON_CALL(desktopFileReaderFactory, createInstance(dialerAppId, _)) |
4722 | - .WillByDefault(Return(mockDesktopFileReader)); |
4723 | - } |
4724 | - |
4725 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(dialerAppId, _)) |
4726 | - .Times(1) |
4727 | - .WillOnce(Return(true)); |
4728 | - |
4729 | - /*auto application =*/ applicationManager.startApplication(dialerAppId, ApplicationManager::NoFlag); |
4730 | - applicationManager.onProcessStarting(dialerAppId); |
4731 | - |
4732 | - { |
4733 | - bool authed = false; |
4734 | - applicationManager.authorizeSession(dialerPID, authed); |
4735 | - EXPECT_EQ(authed, true); |
4736 | - } |
4737 | - |
4738 | - auto dialerSession = std::make_shared<mir::scene::MockSession>(dialerAppId.toStdString(), dialerPID); |
4739 | - sessionManager.onSessionStarting(dialerSession); |
4740 | - applicationManager.focusApplication(dialerAppId); |
4741 | - applicationManager.onSessionCreatedSurface(dialerSession.get(), dialerSurface); |
4742 | - |
4743 | - /*** Focus webbrowser ***/ |
4744 | - |
4745 | - // Nothing should happen as it's already the running main stage app |
4746 | - EXPECT_CALL(*webbrowserSession.get(), set_lifecycle_state(_)) |
4747 | - .Times(0); |
4748 | - applicationManager.focusApplication(webbrowserAppId); |
4749 | -} |
4750 | - |
4751 | TEST_F(ApplicationManagerTests,lifecycle_exempt_appId_is_not_suspended) |
4752 | { |
4753 | using namespace ::testing; |
4754 | quint64 a_procId = 5921; |
4755 | - const char an_app_id[] = "some_app"; |
4756 | - QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app"); |
4757 | - std::shared_ptr<mir::scene::Surface> aSurface(nullptr); |
4758 | + const QString appId("some_app"); |
4759 | + QByteArray a_cmd("/usr/bin/app1"); |
4760 | |
4761 | ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd)); |
4762 | |
4763 | - ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
4764 | - |
4765 | - bool authed = true; |
4766 | + ON_CALL(appController,appIdHasProcessId(a_procId, appId)).WillByDefault(Return(true)); |
4767 | + |
4768 | + // Set up Mocks & signal watcher |
4769 | + auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
4770 | + ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4771 | + ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
4772 | + |
4773 | + ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
4774 | + |
4775 | + |
4776 | + Application *the_app = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4777 | + applicationManager.onProcessStarting(appId); |
4778 | |
4779 | std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", a_procId); |
4780 | std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", a_procId); |
4781 | - applicationManager.authorizeSession(a_procId, authed); |
4782 | + { |
4783 | + bool authed = false; |
4784 | + applicationManager.authorizeSession(a_procId, authed); |
4785 | + ASSERT_EQ(authed, true); |
4786 | + } |
4787 | |
4788 | onSessionStarting(first_session); |
4789 | - applicationManager.onSessionCreatedSurface(first_session.get(), aSurface); |
4790 | + FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem; |
4791 | + onSessionCreatedSurface(first_session.get(), aSurface); |
4792 | + aSurface->drawFirstFrame(); |
4793 | onSessionStarting(second_session); |
4794 | |
4795 | - Application * the_app = applicationManager.findApplication(an_app_id); |
4796 | - applicationManager.focusApplication(an_app_id); |
4797 | - |
4798 | // Add to other apps to the list (Not "some_app") |
4799 | QVariantList lifecycleExemptAppIds; |
4800 | lifecycleExemptAppIds << "one_app" << "another_app"; |
4801 | ON_CALL(settings,get(_)).WillByDefault(Return(lifecycleExemptAppIds)); |
4802 | settings.changed("lifecycleExemptAppids"); |
4803 | |
4804 | - EXPECT_EQ(Application::Running, the_app->state()); |
4805 | - |
4806 | - applicationManager.setSuspended(true); |
4807 | - |
4808 | - // And expect "some_app" to get suspended |
4809 | - EXPECT_EQ(Application::Suspended, the_app->state()); |
4810 | - |
4811 | - applicationManager.setSuspended(false); |
4812 | + ASSERT_EQ(Application::InternalState::Running, the_app->internalState()); |
4813 | + |
4814 | + EXPECT_CALL(*(mir::scene::MockSession*)first_session.get(), set_lifecycle_state(mir_lifecycle_state_will_suspend)); |
4815 | + the_app->setRequestedState(Application::RequestedSuspended); |
4816 | + ASSERT_EQ(Application::InternalState::SuspendingWaitSession, the_app->internalState()); |
4817 | + |
4818 | + static_cast<qtmir::Session*>(the_app->session())->doSuspend(); |
4819 | + ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, the_app->internalState()); |
4820 | + applicationManager.onProcessSuspended(the_app->appId()); |
4821 | + ASSERT_EQ(Application::InternalState::Suspended, the_app->internalState()); |
4822 | + |
4823 | + EXPECT_CALL(*(mir::scene::MockSession*)first_session.get(), set_lifecycle_state(mir_lifecycle_state_resumed)); |
4824 | + the_app->setRequestedState(Application::RequestedRunning); |
4825 | |
4826 | EXPECT_EQ(Application::Running, the_app->state()); |
4827 | |
4828 | @@ -2284,14 +1899,16 @@ |
4829 | |
4830 | EXPECT_EQ(Application::Running, the_app->state()); |
4831 | |
4832 | - applicationManager.setSuspended(true); |
4833 | + EXPECT_CALL(*(mir::scene::MockSession*)first_session.get(), set_lifecycle_state(_)).Times(0); |
4834 | + the_app->setRequestedState(Application::RequestedSuspended); |
4835 | |
4836 | // And expect it to be running still |
4837 | - EXPECT_EQ(Application::Running, the_app->state()); |
4838 | - |
4839 | - applicationManager.setSuspended(false); |
4840 | - |
4841 | - EXPECT_EQ(Application::Running, the_app->state()); |
4842 | + ASSERT_EQ(Application::InternalState::RunningInBackground, the_app->internalState()); |
4843 | + |
4844 | + the_app->setRequestedState(Application::RequestedRunning); |
4845 | + |
4846 | + EXPECT_EQ(Application::Running, the_app->state()); |
4847 | + ASSERT_EQ(Application::InternalState::Running, the_app->internalState()); |
4848 | } |
4849 | |
4850 | /* |
4851 | @@ -2323,51 +1940,13 @@ |
4852 | onSessionStarting(session); |
4853 | |
4854 | // App creates surface, focuses it so state is running |
4855 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4856 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4857 | - applicationManager.focusApplication(appId); |
4858 | - |
4859 | - applicationManager.unfocusCurrentApplication(); |
4860 | - |
4861 | - EXPECT_FALSE(sharedWakelock.enabled()); |
4862 | - EXPECT_EQ(application->state(), Application::Running); |
4863 | -} |
4864 | - |
4865 | -/* |
4866 | - * Test lifecycle exempt applications have their wakelocks released on suspend |
4867 | - */ |
4868 | -TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnUnSuspend) |
4869 | -{ |
4870 | - using namespace ::testing; |
4871 | - |
4872 | - const QString appId("com.ubuntu.music"); // member of lifecycle exemption list |
4873 | - const quint64 procId = 12345; |
4874 | - |
4875 | - // Set up Mocks & signal watcher |
4876 | - auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo()); |
4877 | - ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true)); |
4878 | - ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId)); |
4879 | - |
4880 | - ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader)); |
4881 | - |
4882 | - EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _)) |
4883 | - .Times(1) |
4884 | - .WillOnce(Return(true)); |
4885 | - |
4886 | - auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag); |
4887 | - applicationManager.onProcessStarting(appId); |
4888 | - std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
4889 | - bool authed = true; |
4890 | - applicationManager.authorizeSession(procId, authed); |
4891 | - onSessionStarting(session); |
4892 | - |
4893 | - // App creates surface, focuses it so state is running |
4894 | - std::shared_ptr<mir::scene::Surface> surface(nullptr); |
4895 | - applicationManager.onSessionCreatedSurface(session.get(), surface); |
4896 | - applicationManager.focusApplication(appId); |
4897 | - |
4898 | - applicationManager.setSuspended(true); |
4899 | - |
4900 | - EXPECT_FALSE(sharedWakelock.enabled()); |
4901 | - EXPECT_EQ(application->state(), Application::Running); |
4902 | + FakeMirSurfaceItem *surface = new FakeMirSurfaceItem; |
4903 | + onSessionCreatedSurface(session.get(), surface); |
4904 | + surface->drawFirstFrame(); |
4905 | + |
4906 | + application->setRequestedState(Application::RequestedSuspended); |
4907 | + |
4908 | + EXPECT_FALSE(sharedWakelock.enabled()); |
4909 | + ASSERT_EQ(Application::InternalState::RunningInBackground, application->internalState()); |
4910 | + EXPECT_EQ(Application::Running, application->state()); |
4911 | } |
4912 | |
4913 | === modified file 'tests/modules/MirSurfaceItem/CMakeLists.txt' |
4914 | --- tests/modules/MirSurfaceItem/CMakeLists.txt 2014-12-03 08:56:35 +0000 |
4915 | +++ tests/modules/MirSurfaceItem/CMakeLists.txt 2015-07-13 21:57:32 +0000 |
4916 | @@ -5,7 +5,9 @@ |
4917 | ) |
4918 | |
4919 | include_directories( |
4920 | - ${CMAKE_SOURCE_DIR}/src/modules/Unity/Application |
4921 | + ${CMAKE_SOURCE_DIR}/src/common |
4922 | +# ${CMAKE_SOURCE_DIR}/src/modules/Unity/Application |
4923 | + ${CMAKE_SOURCE_DIR}/src/modules |
4924 | ${CMAKE_SOURCE_DIR}/tests/modules/common |
4925 | ${MIRSERVER_INCLUDE_DIRS} |
4926 | ) |
4927 | |
4928 | === modified file 'tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp' |
4929 | --- tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp 2015-05-01 13:37:03 +0000 |
4930 | +++ tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp 2015-07-13 21:57:32 +0000 |
4931 | @@ -23,7 +23,7 @@ |
4932 | #include <QTest> |
4933 | |
4934 | // the test subject |
4935 | -#include <mirsurfaceitem.h> |
4936 | +#include <Unity/Application/mirsurfaceitem.h> |
4937 | |
4938 | // mocks |
4939 | #include <mock_surface.h> |
4940 | |
4941 | === modified file 'tests/modules/SessionManager/CMakeLists.txt' |
4942 | --- tests/modules/SessionManager/CMakeLists.txt 2015-05-21 18:48:59 +0000 |
4943 | +++ tests/modules/SessionManager/CMakeLists.txt 2015-07-13 21:57:32 +0000 |
4944 | @@ -3,9 +3,13 @@ |
4945 | session_manager_test.cpp |
4946 | session_test.cpp |
4947 | ${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp |
4948 | + ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp |
4949 | + ${CMAKE_SOURCE_DIR}/tests/modules/common/fake_mirsurfaceitem.h |
4950 | ) |
4951 | |
4952 | include_directories( |
4953 | + ${APPLICATION_API_INCLUDE_DIRS} |
4954 | + ${CMAKE_SOURCE_DIR}/src/common |
4955 | ${CMAKE_SOURCE_DIR}/src/platforms/mirserver |
4956 | ${CMAKE_SOURCE_DIR}/src/modules |
4957 | ${CMAKE_SOURCE_DIR}/tests/modules/common |
4958 | |
4959 | === modified file 'tests/modules/SessionManager/session_manager_test.cpp' |
4960 | --- tests/modules/SessionManager/session_manager_test.cpp 2014-12-01 11:05:01 +0000 |
4961 | +++ tests/modules/SessionManager/session_manager_test.cpp 2015-07-13 21:57:32 +0000 |
4962 | @@ -21,7 +21,7 @@ |
4963 | |
4964 | #include <Unity/Application/session.h> |
4965 | |
4966 | - #include "qtmir_test.h" |
4967 | +#include "qtmir_test.h" |
4968 | |
4969 | using namespace qtmir; |
4970 | using mir::scene::MockSession; |
4971 | |
4972 | === modified file 'tests/modules/SessionManager/session_test.cpp' |
4973 | --- tests/modules/SessionManager/session_test.cpp 2015-01-09 15:13:29 +0000 |
4974 | +++ tests/modules/SessionManager/session_test.cpp 2015-07-13 21:57:32 +0000 |
4975 | @@ -1,5 +1,5 @@ |
4976 | /* |
4977 | - * Copyright (C) 2014 Canonical, Ltd. |
4978 | + * Copyright (C) 2014,2015 Canonical, Ltd. |
4979 | * |
4980 | * This program is free software: you can redistribute it and/or modify it under |
4981 | * the terms of the GNU Lesser General Public License version 3, as published by |
4982 | @@ -15,16 +15,17 @@ |
4983 | * |
4984 | */ |
4985 | |
4986 | +#include <qtmir_test.h> |
4987 | +#include <fake_mirsurfaceitem.h> |
4988 | + |
4989 | #include <Unity/Application/application.h> |
4990 | #include <Unity/Application/mirsurfaceitem.h> |
4991 | |
4992 | -#include "qtmir_test.h" |
4993 | #include "stub_scene_surface.h" |
4994 | |
4995 | using namespace qtmir; |
4996 | using mir::scene::MockSession; |
4997 | |
4998 | - |
4999 | namespace ms = mir::scene; |
5000 | namespace mtd = mir::test::doubles; |
See inline.