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 | continuous-integration | 2014-08-21 | Needs Fixing on 2015-01-19 |
| Albert Astals Cid (community) | Needs Fixing on 2015-01-19 | ||
| Michał Sawicz | 2014-08-21 | Approve on 2014-08-21 | |
| Daniel d'Andrada | 2014-08-21 | Pending | |
|
Review via email:
|
|||
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
| 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 on 2015-01-19
-
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 on 2015-01-22
-
Move Surface Types & States into Globals enum class. Expand surfaceSizer parameter to include state
- 264. By Gerry Boland on 2015-02-09
-
Merge trunk
- 265. By Gerry Boland on 2015-03-30
-
Merge trunk, required many changes
- 266. By Gerry Boland on 2015-03-30
-
Remove accidental commits
- 267. By Gerry Boland on 2015-03-30
-
Remove local build tweak
- 268. By Gerry Boland on 2015-07-13
-
Merge trunk
- 269. By Gerry Boland on 2015-07-13
-
Merge detach-
state-from- focus and resolve conflicts
Unmerged revisions
- 269. By Gerry Boland on 2015-07-13
-
Merge detach-
state-from- focus and resolve conflicts - 268. By Gerry Boland on 2015-07-13
-
Merge trunk
- 267. By Gerry Boland on 2015-03-30
-
Remove local build tweak
- 266. By Gerry Boland on 2015-03-30
-
Remove accidental commits
- 265. By Gerry Boland on 2015-03-30
-
Merge trunk, required many changes
- 264. By Gerry Boland on 2015-02-09
-
Merge trunk
- 263. By Gerry Boland on 2015-01-22
-
Move Surface Types & States into Globals enum class. Expand surfaceSizer parameter to include state
- 262. By Gerry Boland on 2015-01-19
-
Merge trunk & fix conflicts
- 261. By Gerry Boland on 2015-01-13
-
Merge trunk
- 260. By Gerry Boland on 2015-01-05
-
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.