Merge lp:~dandrader/qtmir/multiSessionApp into lp:qtmir
- multiSessionApp
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Gerry Boland |
Approved revision: | 639 |
Merged at revision: | 638 |
Proposed branch: | lp:~dandrader/qtmir/multiSessionApp |
Merge into: | lp:qtmir |
Diff against target: |
1193 lines (+292/-239) 9 files modified
src/modules/Unity/Application/application.cpp (+146/-90) src/modules/Unity/Application/application.h (+12/-13) src/modules/Unity/Application/application_manager.cpp (+29/-58) src/modules/Unity/Application/application_manager.h (+3/-7) src/modules/Unity/Application/dbusfocusinfo.cpp (+28/-25) src/modules/Unity/Application/session.cpp (+1/-1) src/modules/Unity/Application/session_interface.h (+6/-5) tests/modules/Application/application_test.cpp (+15/-15) tests/modules/ApplicationManager/application_manager_test.cpp (+52/-25) |
To merge this branch: | bzr merge lp:~dandrader/qtmir/multiSessionApp |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | Approve | ||
Gerry Boland (community) | Approve | ||
Unity8 CI Bot (community) | continuous-integration | Approve | |
Review via email: mp+321581@code.launchpad.net |
Commit message
Support multiple sessions per Application
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
No
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
Gerry Boland (gerboland) wrote : | # |
+ if (session->state() > combinedState) {
+ combinedState = session->state();
+ }
I guess this is as good a "combined" state as any.
The code, you're using the convenience to the order of the states in its enum? Strikes me as something easily broken in future - but I'm glad to see you've added a comment to make that less likely.
+void Application::die()
terminate() would match the "kill" term
Going from memory, the setApplicationPid stuff was a workaround for supporting apps that are not launched via UAL - we had to save the pid we got from Mir. Are apps launched with desktop_file_hint still working?
How are you testing this? I made this simple client which might be handy: git clone -b multiple-
Is moving the InitialSurfaceSize calls into the Application required for this MP?
Daniel d'Andrada (dandrader) wrote : | # |
On 31/03/2017 13:26, Gerry Boland wrote:
> +void Application::die()
> terminate() would match the "kill" term
Ok. Renamed.
> Going from memory, the setApplicationPid stuff was a workaround for supporting apps that are not launched via UAL - we had to save the pid we got from Mir. Are apps launched with desktop_file_hint still working?
Ooops! You're right. Being able to remove this bookkeeping of pids from
ApplicationManager was too good to be true.
Fixed.
> How are you testing this? I made this simple client which might be handy: git clone -b multiple-
That's not handy. Launching some random app from the application drawer
is handy. I tried with nautilus and mahjongg.
As a general rule: try to launch some apps from the app drawer without
this patch. You should get endless splash screens for them. Then install
this patch and try the same ones again. They should now work.
You can also add debug-level logging to surface and application
categories and check in unity8.log that such applications are indeed
getting *3* separate mir sessions each (at least the gtk ones I checked).
> Is moving the InitialSurfaceSize calls into the Application required for this MP?
That was how things were being done before the latest landing (had the
patch ready) and that sure is simpler as well as the application has
many sessions and thus entries in that InitialSurfaceSize singleton.
Application knows his own pids and his own initialSurfaceSize. So it can
update InitialSurfaceSize on his own. No need to involve
ApplicationManager in that. Don't know what you gain from it.
Furthermore, ApplicationManager no longer keeps tracks of all pids going
around. It just momentarily holds them between the moment a session is
authorized and the moment it shows up to be assigned to an Application
object.
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:638
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:639
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Gerry Boland (gerboland) wrote : | # |
Ok, this does improve the situation a lot.
Gerry Boland (gerboland) wrote : | # |
<bregma> Saviq, the first way to test the multiple-connection situation would probably be to create a custom .desktop file that removes GDK_BACKEND from the app's environment, which will force it to autoprobe and use Mir instead
Saviq tried this and got http://
Gerry Boland (gerboland) wrote : | # |
Still fixes the main thing, will keep
Michał Sawicz (saviq) wrote : | # |
Sorry, apparently GTK_BACKEND="" is incorrect, ="*" or unsetting it altogether showed GTK apps launch fine.
Preview Diff
1 | === modified file 'src/modules/Unity/Application/application.cpp' |
2 | --- src/modules/Unity/Application/application.cpp 2017-03-28 17:12:03 +0000 |
3 | +++ src/modules/Unity/Application/application.cpp 2017-03-31 21:11:21 +0000 |
4 | @@ -28,10 +28,14 @@ |
5 | |
6 | // QPA mirserver |
7 | #include "logging.h" |
8 | +#include "initialsurfacesizes.h" |
9 | |
10 | // Unity API |
11 | #include <unity/shell/application/MirSurfaceInterface.h> |
12 | |
13 | +// std |
14 | +#include <csignal> |
15 | + |
16 | namespace unityapp = unity::shell::application; |
17 | |
18 | #define DEBUG_MSG qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::" << __func__ |
19 | @@ -50,12 +54,10 @@ |
20 | , m_supportedStages(Application::MainStage|Application::SideStage) |
21 | , m_state(InternalState::Starting) |
22 | , m_arguments(arguments) |
23 | - , m_session(nullptr) |
24 | , m_requestedState(RequestedRunning) |
25 | , m_processState(ProcessUnknown) |
26 | , m_stopTimer(nullptr) |
27 | , m_exemptFromLifecycle(false) |
28 | - , m_proxySurfaceList(new ProxySurfaceListModel(this)) |
29 | , m_proxyPromptSurfaceList(new ProxySurfaceListModel(this)) |
30 | { |
31 | INFO_MSG << "()"; |
32 | @@ -69,7 +71,7 @@ |
33 | |
34 | setStopTimer(new Timer); |
35 | |
36 | - connect(m_proxySurfaceList, &unityapp::MirSurfaceListInterface::countChanged, this, &unityapp::ApplicationInfoInterface::surfaceCountChanged); |
37 | + connect(&m_surfaceList, &unityapp::MirSurfaceListInterface::countChanged, this, &unityapp::ApplicationInfoInterface::surfaceCountChanged); |
38 | } |
39 | |
40 | Application::~Application() |
41 | @@ -100,10 +102,11 @@ |
42 | break; |
43 | } |
44 | |
45 | - if (m_session) { |
46 | - m_session->setApplication(nullptr); |
47 | - delete m_session; |
48 | + for (SessionInterface *session : m_sessions) { |
49 | + session->setApplication(nullptr); |
50 | + delete session; |
51 | } |
52 | + m_sessions.clear(); |
53 | |
54 | delete m_stopTimer; |
55 | } |
56 | @@ -281,20 +284,22 @@ |
57 | |
58 | void Application::updateState() |
59 | { |
60 | - if ((!m_session && m_state != InternalState::Starting && m_state != InternalState::StoppedResumable) |
61 | + SessionInterface *singleSession = m_sessions.count() == 1 ? m_sessions[0] : nullptr; |
62 | + |
63 | + if ((m_sessions.isEmpty() && m_state != InternalState::Starting && m_state != InternalState::StoppedResumable) |
64 | || |
65 | - (m_session && m_session->surfaceList()->isEmpty() && m_session->hasClosingSurfaces())) { |
66 | + (singleSession && singleSession->surfaceList()->isEmpty() && singleSession->hasClosingSurfaces())) { |
67 | // As we might not be able to go to Closing state right now (eg, SuspendingWaitProcess), |
68 | // store the intent in a separate variable. |
69 | m_closing = true; |
70 | } |
71 | |
72 | - bool lostAllSurfaces = m_session && m_session->surfaceList()->isEmpty() && m_session->hadSurface() |
73 | - && !m_session->hasClosingSurfaces(); |
74 | + bool lostAllSurfaces = singleSession && singleSession->surfaceList()->isEmpty() && singleSession->hadSurface() |
75 | + && !singleSession->hasClosingSurfaces(); |
76 | |
77 | if (m_closing || (lostAllSurfaces && m_state != InternalState::StoppedResumable)) { |
78 | applyClosing(); |
79 | - } else if (m_requestedState == RequestedRunning || (m_session && m_session->hasClosingSurfaces())) { |
80 | + } else if (m_requestedState == RequestedRunning || (singleSession && singleSession->hasClosingSurfaces())) { |
81 | applyRequestedRunning(); |
82 | } else { |
83 | applyRequestedSuspended(); |
84 | @@ -410,12 +415,22 @@ |
85 | |
86 | bool Application::focused() const |
87 | { |
88 | - return m_session && m_session->focused(); |
89 | + for (auto session : m_sessions) { |
90 | + if (session->focused()) { |
91 | + return true; |
92 | + } |
93 | + } |
94 | + return false; |
95 | } |
96 | |
97 | bool Application::fullscreen() const |
98 | { |
99 | - return m_session ? m_session->fullscreen() : false; |
100 | + for (auto session : m_sessions) { |
101 | + if (session->fullscreen()) { |
102 | + return true; |
103 | + } |
104 | + } |
105 | + return false; |
106 | } |
107 | |
108 | void Application::close() |
109 | @@ -433,7 +448,9 @@ |
110 | case InternalState::SuspendingWaitSession: |
111 | case InternalState::SuspendingWaitProcess: |
112 | case InternalState::Suspended: |
113 | - m_session->close(); |
114 | + for (auto session : m_sessions) { |
115 | + session->close(); |
116 | + } |
117 | break; |
118 | case InternalState::Closing: |
119 | // already on the way |
120 | @@ -453,69 +470,73 @@ |
121 | m_arguments = arguments; |
122 | } |
123 | |
124 | -void Application::setSession(SessionInterface *newSession) |
125 | +void Application::removeSession(SessionInterface *session) |
126 | +{ |
127 | + if (!m_sessions.contains(session)) |
128 | + return; |
129 | + |
130 | + m_surfaceList.removeSurfaceList(session->surfaceList()); |
131 | + m_proxyPromptSurfaceList->setSourceList(nullptr); |
132 | + session->disconnect(this); |
133 | + session->surfaceList()->disconnect(this); |
134 | + session->setApplication(nullptr); |
135 | + session->setParent(nullptr); |
136 | + |
137 | + m_sessions.removeAll(session); |
138 | + |
139 | + InitialSurfaceSizes::remove(session->pid()); |
140 | +} |
141 | + |
142 | +void Application::addSession(SessionInterface *newSession) |
143 | { |
144 | INFO_MSG << "(session=" << newSession << ")"; |
145 | |
146 | - if (newSession == m_session) |
147 | + if (!newSession || m_sessions.contains(newSession)) |
148 | return; |
149 | |
150 | - if (m_session) { |
151 | - m_proxySurfaceList->setSourceList(nullptr); |
152 | - m_proxyPromptSurfaceList->setSourceList(nullptr); |
153 | - m_session->disconnect(this); |
154 | - m_session->surfaceList()->disconnect(this); |
155 | - m_session->setApplication(nullptr); |
156 | - m_session->setParent(nullptr); |
157 | - } |
158 | - |
159 | bool oldFullscreen = fullscreen(); |
160 | - m_session = newSession; |
161 | - |
162 | - if (m_session) { |
163 | - m_session->setParent(this); |
164 | - m_session->setApplication(this); |
165 | - |
166 | - switch (m_state) { |
167 | - case InternalState::Starting: |
168 | - case InternalState::Running: |
169 | - case InternalState::RunningInBackground: |
170 | - case InternalState::Closing: |
171 | - m_session->resume(); |
172 | - break; |
173 | - case InternalState::SuspendingWaitSession: |
174 | - case InternalState::SuspendingWaitProcess: |
175 | - case InternalState::Suspended: |
176 | - m_session->suspend(); |
177 | - break; |
178 | - case InternalState::Stopped: |
179 | - default: |
180 | - m_session->stop(); |
181 | - break; |
182 | - } |
183 | - |
184 | - connect(m_session, &SessionInterface::stateChanged, this, &Application::onSessionStateChanged); |
185 | - connect(m_session, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged); |
186 | - connect(m_session, &SessionInterface::hasClosingSurfacesChanged, this, &Application::updateState); |
187 | - connect(m_session, &SessionInterface::focusRequested, this, &Application::focusRequested); |
188 | - connect(m_session->surfaceList(), &MirSurfaceListModel::emptyChanged, this, &Application::updateState); |
189 | - connect(m_session, &SessionInterface::focusedChanged, this, [&](bool focused) { |
190 | - qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::focusedChanged(" << focused << ")"; |
191 | - Q_EMIT focusedChanged(focused); |
192 | - }); |
193 | - |
194 | - if (oldFullscreen != fullscreen()) |
195 | - Q_EMIT fullscreenChanged(fullscreen()); |
196 | - |
197 | - m_proxySurfaceList->setSourceList(m_session->surfaceList()); |
198 | - m_proxyPromptSurfaceList->setSourceList(m_session->promptSurfaceList()); |
199 | - } else { |
200 | - // this can only happen after the session has stopped |
201 | - Q_ASSERT(m_state == InternalState::Stopped || m_state == InternalState::StoppedResumable |
202 | - || m_state == InternalState::Closing); |
203 | - } |
204 | - |
205 | - Q_EMIT sessionChanged(m_session); |
206 | + m_sessions << newSession; |
207 | + |
208 | + newSession->setParent(this); |
209 | + newSession->setApplication(this); |
210 | + |
211 | + switch (m_state) { |
212 | + case InternalState::Starting: |
213 | + case InternalState::Running: |
214 | + case InternalState::RunningInBackground: |
215 | + case InternalState::Closing: |
216 | + newSession->resume(); |
217 | + break; |
218 | + case InternalState::SuspendingWaitSession: |
219 | + case InternalState::SuspendingWaitProcess: |
220 | + case InternalState::Suspended: |
221 | + newSession->suspend(); |
222 | + break; |
223 | + case InternalState::Stopped: |
224 | + default: |
225 | + newSession->stop(); |
226 | + break; |
227 | + } |
228 | + |
229 | + connect(newSession, &SessionInterface::stateChanged, this, &Application::onSessionStateChanged); |
230 | + connect(newSession, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged); |
231 | + connect(newSession, &SessionInterface::hasClosingSurfacesChanged, this, &Application::updateState); |
232 | + connect(newSession, &SessionInterface::focusRequested, this, &Application::focusRequested); |
233 | + connect(newSession->surfaceList(), &MirSurfaceListModel::emptyChanged, this, &Application::updateState); |
234 | + connect(newSession, &SessionInterface::focusedChanged, this, [&](bool focused) { |
235 | + qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::focusedChanged(" << focused << ")"; |
236 | + Q_EMIT focusedChanged(focused); |
237 | + }); |
238 | + |
239 | + if (m_initialSurfaceSize.isValid() && newSession->pid() != 0) { |
240 | + InitialSurfaceSizes::set(newSession->pid(), m_initialSurfaceSize); |
241 | + } |
242 | + |
243 | + if (oldFullscreen != fullscreen()) |
244 | + Q_EMIT fullscreenChanged(fullscreen()); |
245 | + |
246 | + m_surfaceList.addSurfaceList(newSession->surfaceList()); |
247 | + m_proxyPromptSurfaceList->setSourceList(newSession->promptSurfaceList()); |
248 | } |
249 | |
250 | void Application::setInternalState(Application::InternalState state) |
251 | @@ -587,7 +608,7 @@ |
252 | break; |
253 | case ProcessFailed: |
254 | // we assume the session always stop before the process |
255 | - Q_ASSERT(!m_session || m_session->state() == Session::Stopped); |
256 | + Q_ASSERT(m_sessions.isEmpty() || combinedSessionState() == Session::Stopped); |
257 | |
258 | if (m_state == InternalState::Starting) { |
259 | // that was way too soon. let it go away |
260 | @@ -599,7 +620,7 @@ |
261 | break; |
262 | case ProcessStopped: |
263 | // we assume the session always stop before the process |
264 | - Q_ASSERT(!m_session || m_session->state() == Session::Stopped); |
265 | + Q_ASSERT(m_sessions.isEmpty() || combinedSessionState() == Session::Stopped); |
266 | |
267 | if (m_state == InternalState::Starting) { |
268 | // that was way too soon. let it go away |
269 | @@ -622,7 +643,7 @@ |
270 | INFO_MSG << "()"; |
271 | |
272 | Q_ASSERT(m_state == InternalState::Running); |
273 | - Q_ASSERT(m_session != nullptr); |
274 | + Q_ASSERT(!m_sessions.isEmpty()); |
275 | |
276 | if (exemptFromLifecycle()) { |
277 | // There's no need to keep the wakelock as the process is never suspended |
278 | @@ -631,7 +652,9 @@ |
279 | setInternalState(InternalState::RunningInBackground); |
280 | } else { |
281 | setInternalState(InternalState::SuspendingWaitSession); |
282 | - m_session->suspend(); |
283 | + for (auto session : m_sessions) { |
284 | + session->suspend(); |
285 | + } |
286 | } |
287 | } |
288 | |
289 | @@ -645,12 +668,14 @@ |
290 | if (m_processState == ProcessSuspended) { |
291 | setProcessState(ProcessRunning); // should we wait for a resumed() signal? |
292 | } |
293 | - if (m_session) { |
294 | - m_session->resume(); |
295 | + for (auto session : m_sessions) { |
296 | + session->resume(); |
297 | } |
298 | } else if (m_state == InternalState::SuspendingWaitSession) { |
299 | setInternalState(InternalState::Running); |
300 | - m_session->resume(); |
301 | + for (auto session : m_sessions) { |
302 | + session->resume(); |
303 | + } |
304 | } else if (m_state == InternalState::RunningInBackground) { |
305 | setInternalState(InternalState::Running); |
306 | } |
307 | @@ -704,11 +729,6 @@ |
308 | return m_rotatesWindowContents; |
309 | } |
310 | |
311 | -SessionInterface* Application::session() const |
312 | -{ |
313 | - return m_session; |
314 | -} |
315 | - |
316 | void Application::acquireWakelock() const |
317 | { |
318 | if (appId() == QLatin1String("unity8-dash")) |
319 | @@ -725,9 +745,28 @@ |
320 | m_sharedWakelock->release(this); |
321 | } |
322 | |
323 | -void Application::onSessionStateChanged(Session::State sessionState) |
324 | -{ |
325 | - switch (sessionState) { |
326 | +SessionInterface::State Application::combinedSessionState() |
327 | +{ |
328 | + // This doesn't make sense when there are no sessions |
329 | + Q_ASSERT(m_sessions.count() > 0); |
330 | + |
331 | + if (m_sessions.count() == 1) { |
332 | + // easy case |
333 | + return m_sessions[0]->state(); |
334 | + } |
335 | + |
336 | + SessionInterface::State combinedState = SessionInterface::Stopped; |
337 | + for (auto session : m_sessions) { |
338 | + if (session->state() > combinedState) { |
339 | + combinedState = session->state(); |
340 | + } |
341 | + } |
342 | + return combinedState; |
343 | +} |
344 | + |
345 | +void Application::onSessionStateChanged() |
346 | +{ |
347 | + switch (combinedSessionState()) { |
348 | case Session::Starting: |
349 | break; |
350 | case Session::Running: |
351 | @@ -825,13 +864,18 @@ |
352 | |
353 | if (size != m_initialSurfaceSize) { |
354 | m_initialSurfaceSize = size; |
355 | + if (m_initialSurfaceSize.isValid()) { |
356 | + for (auto session : m_sessions) { |
357 | + InitialSurfaceSizes::set(session->pid(), size); |
358 | + } |
359 | + } |
360 | Q_EMIT initialSurfaceSizeChanged(m_initialSurfaceSize); |
361 | } |
362 | } |
363 | |
364 | unityapp::MirSurfaceListInterface* Application::surfaceList() const |
365 | { |
366 | - return m_proxySurfaceList; |
367 | + return &m_surfaceList; |
368 | } |
369 | |
370 | unityapp::MirSurfaceListInterface* Application::promptSurfaceList() const |
371 | @@ -841,11 +885,11 @@ |
372 | |
373 | void Application::requestFocus() |
374 | { |
375 | - if (m_proxySurfaceList->rowCount() > 0) { |
376 | + if (m_surfaceList.rowCount() > 0) { |
377 | INFO_MSG << "() - Requesting focus for most recent toplevel app surface"; |
378 | |
379 | - for (int i = 0; i < m_proxySurfaceList->count(); ++i) { |
380 | - auto surface = static_cast<MirSurfaceInterface*>(m_proxySurfaceList->get(i)); |
381 | + for (int i = 0; i < m_surfaceList.count(); ++i) { |
382 | + auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i)); |
383 | if (!surface->parentSurface()) { |
384 | surface->requestFocus(); |
385 | break; |
386 | @@ -857,4 +901,16 @@ |
387 | } |
388 | } |
389 | |
390 | +void Application::terminate() |
391 | +{ |
392 | + for (auto session : m_sessions) { |
393 | + kill(session->pid(), SIGTERM); |
394 | + } |
395 | +} |
396 | + |
397 | +QVector<SessionInterface*> Application::sessions() const |
398 | +{ |
399 | + return m_sessions; |
400 | +} |
401 | + |
402 | } // namespace qtmir |
403 | |
404 | === modified file 'src/modules/Unity/Application/application.h' |
405 | --- src/modules/Unity/Application/application.h 2017-03-22 14:57:19 +0000 |
406 | +++ src/modules/Unity/Application/application.h 2017-03-31 21:11:21 +0000 |
407 | @@ -1,5 +1,5 @@ |
408 | /* |
409 | - * Copyright (C) 2013-2016 Canonical, Ltd. |
410 | + * Copyright (C) 2013-2017 Canonical, Ltd. |
411 | * |
412 | * This program is free software: you can redistribute it and/or modify it under |
413 | * the terms of the GNU Lesser General Public License version 3, as published by |
414 | @@ -24,6 +24,7 @@ |
415 | #include <QtCore/QtCore> |
416 | #include <QImage> |
417 | #include <QSharedPointer> |
418 | +#include <QVector> |
419 | |
420 | // Unity API |
421 | #include <unity/shell/application/ApplicationInfoInterface.h> |
422 | @@ -109,9 +110,11 @@ |
423 | void setProcessState(ProcessState value); |
424 | |
425 | QStringList arguments() const { return m_arguments; } |
426 | + void setArguments(const QStringList &arguments); |
427 | |
428 | - SessionInterface* session() const; |
429 | - void setSession(SessionInterface *session); |
430 | + void addSession(SessionInterface *session); |
431 | + void removeSession(SessionInterface *session); |
432 | + QVector<SessionInterface*> sessions() const; |
433 | |
434 | bool isValid() const; |
435 | bool fullscreen() const; |
436 | @@ -123,13 +126,13 @@ |
437 | |
438 | void requestFocus(); |
439 | |
440 | + void terminate(); |
441 | + |
442 | // for tests |
443 | void setStopTimer(AbstractTimer *timer); |
444 | AbstractTimer *stopTimer() const { return m_stopTimer; } |
445 | - |
446 | Q_SIGNALS: |
447 | void fullscreenChanged(bool fullscreen); |
448 | - void sessionChanged(SessionInterface *session); |
449 | |
450 | void startProcessRequested(); |
451 | void stopProcessRequested(); |
452 | @@ -139,7 +142,7 @@ |
453 | void closing(); |
454 | |
455 | private Q_SLOTS: |
456 | - void onSessionStateChanged(SessionInterface::State sessionState); |
457 | + void onSessionStateChanged(); |
458 | |
459 | void respawn(); |
460 | |
461 | @@ -147,7 +150,6 @@ |
462 | |
463 | void acquireWakelock() const; |
464 | void releaseWakelock() const; |
465 | - void setArguments(const QStringList &arguments); |
466 | void setInternalState(InternalState state); |
467 | void wipeQMLCache(); |
468 | void suspend(); |
469 | @@ -160,6 +162,7 @@ |
470 | void applyRequestedSuspended(); |
471 | void applyClosing(); |
472 | void onSessionStopped(); |
473 | + SessionInterface::State combinedSessionState(); |
474 | |
475 | QSharedPointer<SharedWakelock> m_sharedWakelock; |
476 | QSharedPointer<ApplicationInfo> m_appInfo; |
477 | @@ -168,7 +171,7 @@ |
478 | QStringList m_arguments; |
479 | Qt::ScreenOrientations m_supportedOrientations; |
480 | bool m_rotatesWindowContents; |
481 | - SessionInterface *m_session; |
482 | + QVector<SessionInterface*> m_sessions; |
483 | RequestedState m_requestedState; |
484 | ProcessState m_processState; |
485 | AbstractTimer *m_stopTimer; |
486 | @@ -176,12 +179,8 @@ |
487 | QSize m_initialSurfaceSize; |
488 | bool m_closing{false}; |
489 | |
490 | - ProxySurfaceListModel *m_proxySurfaceList; |
491 | + mutable MirSurfaceListModel m_surfaceList; |
492 | ProxySurfaceListModel *m_proxyPromptSurfaceList; |
493 | - |
494 | - friend class ApplicationManager; |
495 | - friend class SessionManager; |
496 | - friend class Session; |
497 | }; |
498 | |
499 | } // namespace qtmir |
500 | |
501 | === modified file 'src/modules/Unity/Application/application_manager.cpp' |
502 | --- src/modules/Unity/Application/application_manager.cpp 2017-03-28 17:12:54 +0000 |
503 | +++ src/modules/Unity/Application/application_manager.cpp 2017-03-31 21:11:21 +0000 |
504 | @@ -28,7 +28,6 @@ |
505 | #include "settings.h" |
506 | |
507 | // mirserver |
508 | -#include "initialsurfacesizes.h" |
509 | #include "nativeinterface.h" |
510 | #include "logging.h" |
511 | |
512 | @@ -425,7 +424,6 @@ |
513 | |
514 | Q_UNUSED(error); // FIXME(greyback) upstart reports app that fully started up & crashes as failing during startup?? |
515 | application->setProcessState(Application::ProcessFailed); |
516 | - setApplicationPid(application, 0); |
517 | } |
518 | |
519 | void ApplicationManager::onProcessStopped(const QString &appId) |
520 | @@ -450,7 +448,6 @@ |
521 | // we don't want to override what onProcessFailed already set. |
522 | if (application->processState() != Application::ProcessFailed) { |
523 | application->setProcessState(Application::ProcessStopped); |
524 | - setApplicationPid(application, 0); |
525 | } |
526 | } |
527 | |
528 | @@ -527,8 +524,8 @@ |
529 | if (app->state() == Application::Starting) { |
530 | tracepoint(qtmir, appIdHasProcessId_start); |
531 | if (m_taskController->appIdHasProcessId(app->appId(), pid)) { |
532 | - setApplicationPid(app, pid); |
533 | authorized = true; |
534 | + m_authorizedPids.insertMulti(pid, app->appId()); |
535 | tracepoint(qtmir, appIdHasProcessId_end, 1); //found |
536 | return; |
537 | } |
538 | @@ -581,17 +578,18 @@ |
539 | // some naughty applications use a script to launch the actual application. Check for the |
540 | // case where shell actually launched the script. |
541 | Application *application = findApplicationMutexHeld(appInfo->appId()); |
542 | - if (application && application->state() == Application::Starting) { |
543 | + if (application) { |
544 | qCDebug(QTMIR_APPLICATIONS) << "Process with pid" << pid << "appeared, attaching to existing entry" |
545 | << "in application list with appId:" << application->appId(); |
546 | - setApplicationPid(application, pid); |
547 | authorized = true; |
548 | + m_authorizedPids.insertMulti(pid, appInfo->appId()); |
549 | return; |
550 | } |
551 | |
552 | const QStringList arguments(info->asStringList()); |
553 | queuedAddApp(appInfo, arguments, pid); |
554 | authorized = true; |
555 | + m_authorizedPids.insertMulti(pid, appInfo->appId()); |
556 | } |
557 | |
558 | |
559 | @@ -603,26 +601,22 @@ |
560 | auto qtmirSurface = static_cast<qtmir::MirSurfaceInterface*>(surface); |
561 | |
562 | QMutexLocker locker(&m_mutex); |
563 | - return findApplicationWithPid(miral::pid_of(qtmirSurface->session()->session())); |
564 | + return findApplicationWithSession(qtmirSurface->session()->session()); |
565 | } |
566 | |
567 | -Application* ApplicationManager::findApplicationWithSession(const std::shared_ptr<ms::Session> &session) |
568 | +Application* ApplicationManager::findApplicationWithSession(const std::shared_ptr<ms::Session> &session) const |
569 | { |
570 | if (!session) |
571 | return nullptr; |
572 | - return findApplicationWithPid(miral::pid_of(session)); |
573 | -} |
574 | - |
575 | -Application* ApplicationManager::findApplicationWithPid(const pid_t pid) const |
576 | -{ |
577 | - if (pid <= 0) |
578 | - return nullptr; |
579 | - |
580 | - for (Application *app : m_applications) { |
581 | - if (m_applicationsPid.value(app) == pid) { |
582 | - return app; |
583 | + |
584 | + for (auto *application : m_applications) { |
585 | + for (auto *qmlSession : application->sessions()) { |
586 | + if (qmlSession->session() == session) { |
587 | + return application; |
588 | + } |
589 | } |
590 | } |
591 | + |
592 | return nullptr; |
593 | } |
594 | |
595 | @@ -638,7 +632,6 @@ |
596 | appInfo, |
597 | arguments, |
598 | this); |
599 | - setApplicationPid(application, pid); |
600 | add(application); |
601 | } |
602 | |
603 | @@ -653,22 +646,8 @@ |
604 | DEBUG_MSG << "(appId=" << application->appId() << ")"; |
605 | |
606 | connect(application, &QObject::destroyed, this, [this, application] { |
607 | - const pid_t pid = m_applicationsPid.value(application); |
608 | - if (pid != 0) { |
609 | - InitialSurfaceSizes::remove(pid); |
610 | - m_applicationsPid.remove(application); |
611 | - } |
612 | m_closingApplications.removeAll(application); |
613 | }); |
614 | - connect(application, &Application::initialSurfaceSizeChanged, this, [this, application] { |
615 | - const pid_t pid = m_applicationsPid.value(application); |
616 | - if (pid != 0) { |
617 | - const QSize size = application->initialSurfaceSize(); |
618 | - if (size.isValid()) { |
619 | - InitialSurfaceSizes::set(pid, size); |
620 | - } |
621 | - } |
622 | - }); |
623 | |
624 | Q_ASSERT(!m_modelUnderChange); |
625 | m_modelUnderChange = true; |
626 | @@ -707,13 +686,10 @@ |
627 | |
628 | connect(application, &Application::stopProcessRequested, this, [=]() { |
629 | if (!m_taskController->stop(appId)) { |
630 | - const pid_t pid = m_applicationsPid.value(application); |
631 | - if (pid > 0) { |
632 | - qWarning() << "FAILED to ask Upstart to stop application with appId" << appId |
633 | - << "Sending SIGTERM to process:" << appId; |
634 | - kill(pid, SIGTERM); |
635 | - application->setProcessState(Application::ProcessStopped); |
636 | - } |
637 | + qWarning() << "FAILED to ask Upstart to stop application with appId" << appId |
638 | + << "Sending SIGTERM to process:" << appId; |
639 | + application->terminate(); |
640 | + application->setProcessState(Application::ProcessStopped); |
641 | } |
642 | }); |
643 | |
644 | @@ -805,27 +781,22 @@ |
645 | return nullptr; |
646 | } |
647 | |
648 | -void ApplicationManager::setApplicationPid(Application *app, pid_t pid) |
649 | -{ |
650 | - const pid_t oldPid = m_applicationsPid.value(app); |
651 | - if (oldPid != 0) { |
652 | - InitialSurfaceSizes::remove(oldPid); |
653 | - } |
654 | - |
655 | - m_applicationsPid.insert(app, pid); |
656 | - |
657 | - if (app->initialSurfaceSize().isValid() && pid != 0) { |
658 | - InitialSurfaceSizes::set(pid, app->initialSurfaceSize()); |
659 | - } |
660 | -} |
661 | - |
662 | void ApplicationManager::onSessionStarting(SessionInterface *qmlSession) |
663 | { |
664 | QMutexLocker locker(&m_mutex); |
665 | |
666 | - Application* application = findApplicationWithSession(qmlSession->session()); |
667 | - if (application && application->state() != Application::Running) { |
668 | - application->setSession(qmlSession); |
669 | + Application* application = nullptr; |
670 | + { |
671 | + auto iter = m_authorizedPids.find(miral::pid_of(qmlSession->session())); |
672 | + if (iter != m_authorizedPids.end()) { |
673 | + QString appId = iter.value(); |
674 | + application = findApplication(appId); |
675 | + m_authorizedPids.erase(iter); |
676 | + } |
677 | + } |
678 | + |
679 | + if (application) { |
680 | + application->addSession(qmlSession); |
681 | } |
682 | } |
683 | |
684 | |
685 | === modified file 'src/modules/Unity/Application/application_manager.h' |
686 | --- src/modules/Unity/Application/application_manager.h 2017-03-24 08:44:32 +0000 |
687 | +++ src/modules/Unity/Application/application_manager.h 2017-03-31 21:11:21 +0000 |
688 | @@ -110,10 +110,9 @@ |
689 | |
690 | private: |
691 | // All calls to private functions happen with the mutex held |
692 | - qtmir::Application* findApplicationWithPid(const pid_t pid) const; |
693 | Application* findApplicationMutexHeld(const QString &inputAppId) const; |
694 | |
695 | - Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session); |
696 | + Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session) const; |
697 | void setFocused(Application *application); |
698 | void add(Application *application); |
699 | void remove(Application* application); |
700 | @@ -125,10 +124,7 @@ |
701 | Application* findApplicationWithPromptSession(const mir::scene::PromptSession* promptSession); |
702 | Application *findClosingApplication(const QString &inputAppId) const; |
703 | |
704 | - void setApplicationPid(Application *application, pid_t pid); |
705 | - |
706 | QList<Application*> m_applications; |
707 | - QHash<Application*, pid_t> m_applicationsPid; |
708 | DBusFocusInfo *m_dbusFocusInfo; |
709 | QSharedPointer<TaskController> m_taskController; |
710 | QSharedPointer<ProcInfo> m_procInfo; |
711 | @@ -139,8 +135,8 @@ |
712 | bool m_modelUnderChange{false}; |
713 | static ApplicationManager* the_application_manager; |
714 | |
715 | - friend class Application; |
716 | - friend class DBusWindowStack; |
717 | + QHash<pid_t, QString> m_authorizedPids; |
718 | + |
719 | mutable QMutex m_mutex; |
720 | }; |
721 | |
722 | |
723 | === modified file 'src/modules/Unity/Application/dbusfocusinfo.cpp' |
724 | --- src/modules/Unity/Application/dbusfocusinfo.cpp 2017-03-07 20:20:21 +0000 |
725 | +++ src/modules/Unity/Application/dbusfocusinfo.cpp 2017-03-31 21:11:21 +0000 |
726 | @@ -75,18 +75,20 @@ |
727 | SessionInterface* DBusFocusInfo::findSessionWithPid(const QSet<pid_t> &pidSet) |
728 | { |
729 | Q_FOREACH (Application* application, m_applications) { |
730 | - auto session = application->session(); |
731 | - if (pidSet.contains(session->pid())) { |
732 | - return session; |
733 | - } |
734 | - SessionInterface *chosenChildSession = nullptr; |
735 | - session->foreachChildSession([&](SessionInterface* childSession) { |
736 | - if (pidSet.contains(childSession->pid())) { |
737 | - chosenChildSession = childSession; |
738 | - } |
739 | - }); |
740 | - if (chosenChildSession) { |
741 | - return chosenChildSession; |
742 | + QVector<SessionInterface*> sessions = application->sessions(); |
743 | + for (auto session : sessions) { |
744 | + if (pidSet.contains(session->pid())) { |
745 | + return session; |
746 | + } |
747 | + SessionInterface *chosenChildSession = nullptr; |
748 | + session->foreachChildSession([&](SessionInterface* childSession) { |
749 | + if (pidSet.contains(childSession->pid())) { |
750 | + chosenChildSession = childSession; |
751 | + } |
752 | + }); |
753 | + if (chosenChildSession) { |
754 | + return chosenChildSession; |
755 | + } |
756 | } |
757 | } |
758 | return nullptr; |
759 | @@ -111,21 +113,22 @@ |
760 | MirSurfaceInterface *DBusFocusInfo::findQmlSurface(const QString &serializedId) |
761 | { |
762 | for (Application* application : m_applications) { |
763 | - auto session = application->session(); |
764 | - if (session) { |
765 | - auto surfaceList = static_cast<MirSurfaceListModel*>(session->surfaceList()); |
766 | - for (int i = 0; i < surfaceList->count(); ++i) { |
767 | - auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i)); |
768 | - if (qmlSurface->persistentId() == serializedId) { |
769 | - return qmlSurface; |
770 | + for (SessionInterface *session : application->sessions()) { |
771 | + if (session) { |
772 | + auto surfaceList = static_cast<MirSurfaceListModel*>(session->surfaceList()); |
773 | + for (int i = 0; i < surfaceList->count(); ++i) { |
774 | + auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i)); |
775 | + if (qmlSurface->persistentId() == serializedId) { |
776 | + return qmlSurface; |
777 | + } |
778 | } |
779 | - } |
780 | |
781 | - surfaceList = static_cast<MirSurfaceListModel*>(session->promptSurfaceList()); |
782 | - for (int i = 0; i < surfaceList->count(); ++i) { |
783 | - auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i)); |
784 | - if (qmlSurface->persistentId() == serializedId) { |
785 | - return qmlSurface; |
786 | + surfaceList = static_cast<MirSurfaceListModel*>(session->promptSurfaceList()); |
787 | + for (int i = 0; i < surfaceList->count(); ++i) { |
788 | + auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i)); |
789 | + if (qmlSurface->persistentId() == serializedId) { |
790 | + return qmlSurface; |
791 | + } |
792 | } |
793 | } |
794 | } |
795 | |
796 | === modified file 'src/modules/Unity/Application/session.cpp' |
797 | --- src/modules/Unity/Application/session.cpp 2017-02-21 18:39:45 +0000 |
798 | +++ src/modules/Unity/Application/session.cpp 2017-03-31 21:11:21 +0000 |
799 | @@ -92,7 +92,7 @@ |
800 | delete child; |
801 | } |
802 | if (m_application) { |
803 | - m_application->setSession(nullptr); |
804 | + m_application->removeSession(this); |
805 | } |
806 | |
807 | delete m_children; m_children = nullptr; |
808 | |
809 | === modified file 'src/modules/Unity/Application/session_interface.h' |
810 | --- src/modules/Unity/Application/session_interface.h 2017-02-21 18:46:30 +0000 |
811 | +++ src/modules/Unity/Application/session_interface.h 2017-03-31 21:11:21 +0000 |
812 | @@ -53,12 +53,13 @@ |
813 | SessionInterface(QObject *parent = 0) : QObject(parent) {} |
814 | virtual ~SessionInterface() {} |
815 | |
816 | + // Ordered by importance/activity. Used for calculating the combined state of multiple sessions |
817 | enum State { |
818 | - Starting, |
819 | - Running, |
820 | - Suspending, |
821 | - Suspended, |
822 | - Stopped |
823 | + Running = 4, |
824 | + Starting = 3, |
825 | + Suspending = 2, |
826 | + Suspended = 1, |
827 | + Stopped = 0 |
828 | }; |
829 | |
830 | //getters |
831 | |
832 | === modified file 'tests/modules/Application/application_test.cpp' |
833 | --- tests/modules/Application/application_test.cpp 2017-02-21 18:46:30 +0000 |
834 | +++ tests/modules/Application/application_test.cpp 2017-03-31 21:11:21 +0000 |
835 | @@ -49,7 +49,7 @@ |
836 | inline void suspend(Application *application) |
837 | { |
838 | application->setRequestedState(Application::RequestedSuspended); |
839 | - auto session = dynamic_cast<Session*>(application->session()); |
840 | + auto session = dynamic_cast<Session*>(application->sessions()[0]); |
841 | |
842 | ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); |
843 | ASSERT_EQ(Session::Suspending, session->state()); |
844 | @@ -115,7 +115,7 @@ |
845 | |
846 | FakeSession *session = new FakeSession; |
847 | |
848 | - application->setSession(session); |
849 | + application->addSession(session); |
850 | |
851 | ASSERT_EQ(Application::InternalState::Starting, application->internalState()); |
852 | |
853 | @@ -150,7 +150,7 @@ |
854 | |
855 | // Get it running and then suspend it |
856 | application->setProcessState(Application::ProcessRunning); |
857 | - application->setSession(session); |
858 | + application->addSession(session); |
859 | session->setState(SessionInterface::Running); |
860 | application->setRequestedState(Application::RequestedSuspended); |
861 | session->setState(SessionInterface::Suspended); |
862 | @@ -175,7 +175,7 @@ |
863 | |
864 | // Get it running, suspend it, and finally stop it |
865 | application->setProcessState(Application::ProcessRunning); |
866 | - application->setSession(session); |
867 | + application->addSession(session); |
868 | session->setState(SessionInterface::Running); |
869 | application->setRequestedState(Application::RequestedSuspended); |
870 | session->setState(SessionInterface::Suspended); |
871 | @@ -215,7 +215,7 @@ |
872 | |
873 | FakeSession *session = new FakeSession; |
874 | |
875 | - application->setSession(session); |
876 | + application->addSession(session); |
877 | |
878 | ASSERT_EQ(Application::InternalState::Starting, application->internalState()); |
879 | |
880 | @@ -250,7 +250,7 @@ |
881 | application->setProcessState(Application::ProcessRunning); |
882 | |
883 | FakeSession *session = new FakeSession; |
884 | - application->setSession(session); |
885 | + application->addSession(session); |
886 | |
887 | QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped())); |
888 | |
889 | @@ -283,7 +283,7 @@ |
890 | application->setProcessState(Application::ProcessRunning); |
891 | |
892 | Session *session = createSessionWithFakes(); |
893 | - application->setSession(session); |
894 | + application->addSession(session); |
895 | |
896 | QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped())); |
897 | |
898 | @@ -318,7 +318,7 @@ |
899 | application->setProcessState(Application::ProcessRunning); |
900 | |
901 | FakeSession *session = new FakeSession; |
902 | - application->setSession(session); |
903 | + application->addSession(session); |
904 | |
905 | QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped())); |
906 | |
907 | @@ -380,7 +380,7 @@ |
908 | |
909 | Session *session = createSessionWithFakes(); |
910 | |
911 | - application->setSession(session); |
912 | + application->addSession(session); |
913 | |
914 | FakeMirSurface *surface = new FakeMirSurface; |
915 | session->registerSurface(surface); |
916 | @@ -437,7 +437,7 @@ |
917 | |
918 | Session *session = createSessionWithFakes(); |
919 | |
920 | - application->setSession(session); |
921 | + application->addSession(session); |
922 | |
923 | FakeMirSurface *surface = new FakeMirSurface; |
924 | session->registerSurface(surface); |
925 | @@ -488,7 +488,7 @@ |
926 | |
927 | QPointer<Session> session(createSessionWithFakes()); |
928 | |
929 | - application->setSession(session); |
930 | + application->addSession(session); |
931 | |
932 | FakeMirSurface *surface = new FakeMirSurface; |
933 | session->registerSurface(surface); |
934 | @@ -532,7 +532,7 @@ |
935 | application->setProcessState(Application::ProcessRunning); |
936 | |
937 | QPointer<Session> session(createSessionWithFakes()); |
938 | - application->setSession(session); |
939 | + application->addSession(session); |
940 | |
941 | FakeMirSurface *surface = new FakeMirSurface; |
942 | session->registerSurface(surface); |
943 | @@ -570,7 +570,7 @@ |
944 | |
945 | Session *session = createSessionWithFakes(); |
946 | |
947 | - application->setSession(session); |
948 | + application->addSession(session); |
949 | |
950 | FakeMirSurface *surface = new FakeMirSurface; |
951 | session->registerSurface(surface); |
952 | @@ -602,7 +602,7 @@ |
953 | application->setProcessState(Application::ProcessRunning); |
954 | Session *session = createSessionWithFakes(); |
955 | |
956 | - application->setSession(session); |
957 | + application->addSession(session); |
958 | |
959 | QSignalSpy surfaceCountChangedSpy(application.data(), &Application::surfaceCountChanged); |
960 | |
961 | @@ -641,7 +641,7 @@ |
962 | |
963 | FakeSession *session = new FakeSession; |
964 | |
965 | - application->setSession(session); |
966 | + application->addSession(session); |
967 | |
968 | QSignalSpy spyStartProcess(application.data(), SIGNAL(startProcessRequested())); |
969 | |
970 | |
971 | === modified file 'tests/modules/ApplicationManager/application_manager_test.cpp' |
972 | --- tests/modules/ApplicationManager/application_manager_test.cpp 2017-02-21 18:46:30 +0000 |
973 | +++ tests/modules/ApplicationManager/application_manager_test.cpp 2017-03-31 21:11:21 +0000 |
974 | @@ -59,7 +59,7 @@ |
975 | inline void suspend(Application *application) { |
976 | application->setRequestedState(Application::RequestedSuspended); |
977 | ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState()); |
978 | - static_cast<qtmir::Session*>(application->session())->doSuspend(); |
979 | + static_cast<qtmir::Session*>(application->sessions()[0])->doSuspend(); |
980 | ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState()); |
981 | applicationManager.onProcessSuspended(application->appId()); |
982 | ASSERT_EQ(Application::InternalState::Suspended, application->internalState()); |
983 | @@ -85,6 +85,11 @@ |
984 | |
985 | FakeMirSurface surface; |
986 | |
987 | + EXPECT_CALL(*taskController,appIdHasProcessId(QString(dialer_app_id), firstProcId)) |
988 | + .WillRepeatedly(Return(true)); |
989 | + EXPECT_CALL(*taskController,appIdHasProcessId(QString(dialer_app_id), secondProcId)) |
990 | + .WillRepeatedly(Return(true)); |
991 | + |
992 | EXPECT_CALL(procInfo,command_line(firstProcId)) |
993 | .Times(1) |
994 | .WillOnce(Return(cmdLine)); |
995 | @@ -226,12 +231,22 @@ |
996 | const char third_app_id[] = "app3"; |
997 | QByteArray third_cmdLine( "/usr/bin/app3 --desktop_file_hint=app3"); |
998 | |
999 | + ON_CALL(*taskController,appIdHasProcessId(QString(first_app_id), first_procId)).WillByDefault(Return(true)); |
1000 | + ON_CALL(*taskController,appIdHasProcessId(QString(first_app_id), second_procId)).WillByDefault(Return(false)); |
1001 | + ON_CALL(*taskController,appIdHasProcessId(QString(first_app_id), third_procId)).WillByDefault(Return(false)); |
1002 | + |
1003 | + ON_CALL(*taskController,appIdHasProcessId(QString(second_app_id), second_procId)).WillByDefault(Return(true)); |
1004 | + ON_CALL(*taskController,appIdHasProcessId(QString(second_app_id), first_procId)).WillByDefault(Return(false)); |
1005 | + ON_CALL(*taskController,appIdHasProcessId(QString(second_app_id), third_procId)).WillByDefault(Return(false)); |
1006 | + |
1007 | + ON_CALL(*taskController,appIdHasProcessId(QString(third_app_id), third_procId)).WillByDefault(Return(true)); |
1008 | + ON_CALL(*taskController,appIdHasProcessId(QString(third_app_id), first_procId)).WillByDefault(Return(false)); |
1009 | + ON_CALL(*taskController,appIdHasProcessId(QString(third_app_id), second_procId)).WillByDefault(Return(false)); |
1010 | + |
1011 | EXPECT_CALL(procInfo,command_line(first_procId)) |
1012 | .Times(1) |
1013 | .WillOnce(Return(first_cmdLine)); |
1014 | |
1015 | - ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
1016 | - |
1017 | EXPECT_CALL(procInfo,command_line(second_procId)) |
1018 | .Times(1) |
1019 | .WillOnce(Return(second_cmdLine)); |
1020 | @@ -257,12 +272,12 @@ |
1021 | Application * secondApp = applicationManager.findApplication(second_app_id); |
1022 | Application * thirdApp = applicationManager.findApplication(third_app_id); |
1023 | |
1024 | - EXPECT_EQ(firstAppInfo.application(), firstApp->session()->session()); |
1025 | - EXPECT_EQ(secondAppInfo.application(), secondApp->session()->session()); |
1026 | - EXPECT_EQ(thirdAppInfo.application(), thirdApp->session()->session()); |
1027 | + EXPECT_EQ(firstAppInfo.application(), firstApp->sessions()[0]->session()); |
1028 | + EXPECT_EQ(secondAppInfo.application(), secondApp->sessions()[0]->session()); |
1029 | + EXPECT_EQ(thirdAppInfo.application(), thirdApp->sessions()[0]->session()); |
1030 | } |
1031 | |
1032 | -TEST_F(ApplicationManagerTests,two_session_on_one_application) |
1033 | +TEST_F(ApplicationManagerTests,two_sessions_on_one_application) |
1034 | { |
1035 | int argc = 0; |
1036 | char* argv[0]; |
1037 | @@ -275,28 +290,30 @@ |
1038 | |
1039 | ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd)); |
1040 | |
1041 | - ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
1042 | + ON_CALL(*taskController,appIdHasProcessId(QString(an_app_id), a_procId)).WillByDefault(Return(true)); |
1043 | |
1044 | bool authed = true; |
1045 | |
1046 | auto firstAppInfo = createApplicationInfoFor("Oo", a_procId); |
1047 | auto secondAppInfo = createApplicationInfoFor("oO", a_procId); |
1048 | + |
1049 | applicationManager.authorizeSession(a_procId, authed); |
1050 | - |
1051 | taskController->onSessionStarting(firstAppInfo); |
1052 | + |
1053 | + applicationManager.authorizeSession(a_procId, authed); |
1054 | taskController->onSessionStarting(secondAppInfo); |
1055 | |
1056 | Application * the_app = applicationManager.findApplication(an_app_id); |
1057 | |
1058 | EXPECT_EQ(true, authed); |
1059 | - EXPECT_EQ(secondAppInfo.application(), the_app->session()->session()); |
1060 | + EXPECT_EQ(2, the_app->sessions().count()); |
1061 | |
1062 | taskController->onSessionStopping(firstAppInfo); |
1063 | taskController->onSessionStopping(secondAppInfo); |
1064 | qtApp.sendPostedEvents(nullptr, QEvent::DeferredDelete); |
1065 | } |
1066 | |
1067 | -TEST_F(ApplicationManagerTests,two_session_on_one_application_after_starting) |
1068 | +TEST_F(ApplicationManagerTests,two_sessions_on_one_application_after_starting) |
1069 | { |
1070 | int argc = 0; |
1071 | char* argv[0]; |
1072 | @@ -310,24 +327,30 @@ |
1073 | |
1074 | ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd)); |
1075 | |
1076 | - ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
1077 | + ON_CALL(*taskController,appIdHasProcessId(QString(an_app_id), a_procId)).WillByDefault(Return(true)); |
1078 | |
1079 | bool authed = true; |
1080 | |
1081 | auto firstAppInfo = createApplicationInfoFor("Oo", a_procId); |
1082 | auto secondAppInfo = createApplicationInfoFor("oO", a_procId); |
1083 | + |
1084 | applicationManager.authorizeSession(a_procId, authed); |
1085 | - |
1086 | taskController->onSessionStarting(firstAppInfo); |
1087 | + |
1088 | + EXPECT_EQ(true, authed); |
1089 | + |
1090 | onSessionCreatedSurface(firstAppInfo, &aSurface); |
1091 | aSurface.setReady(); |
1092 | + |
1093 | + Application * the_app = applicationManager.findApplication(an_app_id); |
1094 | + EXPECT_EQ(1, the_app->sessions().count()); |
1095 | + |
1096 | + applicationManager.authorizeSession(a_procId, authed); |
1097 | taskController->onSessionStarting(secondAppInfo); |
1098 | |
1099 | - Application * the_app = applicationManager.findApplication(an_app_id); |
1100 | - |
1101 | EXPECT_EQ(true, authed); |
1102 | EXPECT_EQ(Application::Running, the_app->state()); |
1103 | - EXPECT_EQ(firstAppInfo.application(), the_app->session()->session()); |
1104 | + EXPECT_EQ(2, the_app->sessions().count()); |
1105 | |
1106 | taskController->onSessionStopping(firstAppInfo); |
1107 | taskController->onSessionStopping(secondAppInfo); |
1108 | @@ -345,7 +368,7 @@ |
1109 | .Times(1) |
1110 | .WillOnce(Return(cmdLine)); |
1111 | |
1112 | - ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
1113 | + ON_CALL(*taskController,appIdHasProcessId(QString("app"), procId)).WillByDefault(Return(true)); |
1114 | |
1115 | bool authed = true; |
1116 | |
1117 | @@ -383,7 +406,9 @@ |
1118 | .Times(1) |
1119 | .WillOnce(Return(first_cmdLine)); |
1120 | |
1121 | - ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false)); |
1122 | + ON_CALL(*taskController,appIdHasProcessId(QString("app1"), first_procId)).WillByDefault(Return(true)); |
1123 | + ON_CALL(*taskController,appIdHasProcessId(QString("app2"), second_procId)).WillByDefault(Return(true)); |
1124 | + ON_CALL(*taskController,appIdHasProcessId(QString("app3"), third_procId)).WillByDefault(Return(true)); |
1125 | |
1126 | EXPECT_CALL(procInfo,command_line(second_procId)) |
1127 | .Times(1) |
1128 | @@ -718,7 +743,7 @@ |
1129 | |
1130 | // Check application state and session are correctly set |
1131 | Application *theApp = applicationManager.findApplication(appId); |
1132 | - EXPECT_EQ(theApp->session()->session(), appInfo.application()); |
1133 | + EXPECT_EQ(theApp->sessions()[0]->session(), appInfo.application()); |
1134 | EXPECT_EQ(theApp->focused(), false); |
1135 | } |
1136 | |
1137 | @@ -1115,6 +1140,8 @@ |
1138 | QByteArray cmdLine("/usr/bin/testApp --desktop_file_hint="); |
1139 | cmdLine = cmdLine.append(appId); |
1140 | |
1141 | + ON_CALL(*taskController,appIdHasProcessId(appId, procId)).WillByDefault(Return(true)); |
1142 | + |
1143 | // Set up Mocks & signal watcher |
1144 | EXPECT_CALL(procInfo,command_line(procId)) |
1145 | .Times(1) |
1146 | @@ -1181,7 +1208,7 @@ |
1147 | |
1148 | ASSERT_EQ(Application::InternalState::SuspendingWaitSession, app->internalState()); |
1149 | |
1150 | - static_cast<qtmir::Session*>(app->session())->doSuspend(); |
1151 | + static_cast<qtmir::Session*>(app->sessions()[0])->doSuspend(); |
1152 | ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, app->internalState()); |
1153 | |
1154 | applicationManager.onProcessSuspended(app->appId()); |
1155 | @@ -1412,10 +1439,10 @@ |
1156 | |
1157 | // Session should have called deleteLater() on itself, as it's zombie and doesn't hold any surface |
1158 | // But DeferredDelete is special: likes to be called out specifically or it won't come out |
1159 | - qtApp.sendPostedEvents(app->session(), QEvent::DeferredDelete); |
1160 | + qtApp.sendPostedEvents(app->sessions()[0], QEvent::DeferredDelete); |
1161 | qtApp.sendPostedEvents(); |
1162 | |
1163 | - ASSERT_EQ(app->session(), nullptr); |
1164 | + ASSERT_EQ(app->sessions().count(), 0); |
1165 | |
1166 | QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &))); |
1167 | |
1168 | @@ -1461,7 +1488,7 @@ |
1169 | the_app->setRequestedState(Application::RequestedSuspended); |
1170 | ASSERT_EQ(Application::InternalState::SuspendingWaitSession, the_app->internalState()); |
1171 | |
1172 | - static_cast<qtmir::Session*>(the_app->session())->doSuspend(); |
1173 | + static_cast<qtmir::Session*>(the_app->sessions()[0])->doSuspend(); |
1174 | ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, the_app->internalState()); |
1175 | applicationManager.onProcessSuspended(the_app->appId()); |
1176 | ASSERT_EQ(Application::InternalState::Suspended, the_app->internalState()); |
1177 | @@ -1838,7 +1865,7 @@ |
1178 | taskController->onSessionStarting(appInfo1); |
1179 | |
1180 | FakeMirSurface surface1; |
1181 | - surface1.setSession(app1->session()); |
1182 | + surface1.setSession(app1->sessions()[0]); |
1183 | onSessionCreatedSurface(appInfo1, &surface1); |
1184 | surface1.setReady(); |
1185 | |
1186 | @@ -1864,7 +1891,7 @@ |
1187 | taskController->onSessionStarting(appInfo2); |
1188 | |
1189 | FakeMirSurface surface2; |
1190 | - surface2.setSession(app2->session()); |
1191 | + surface2.setSession(app2->sessions()[0]); |
1192 | onSessionCreatedSurface(appInfo2, &surface2); |
1193 | surface2.setReady(); |
1194 |
PASSED: Continuous integration, rev:636 /unity8- jenkins. ubuntu. com/job/ lp-qtmir- ci/652/ /unity8- jenkins. ubuntu. com/job/ build/4810 /unity8- jenkins. ubuntu. com/job/ build-0- fetch/4838 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 4650 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 4650/artifact/ output/ *zip*/output. zip /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= zesty/4650 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=amd64, release= zesty/4650/ artifact/ output/ *zip*/output. zip /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 4650 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 4650/artifact/ output/ *zip*/output. zip /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= zesty/4650 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=armhf, release= zesty/4650/ artifact/ output/ *zip*/output. zip /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 4650 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 4650/artifact/ output/ *zip*/output. zip /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= zesty/4650 /unity8- jenkins. ubuntu. com/job/ build-2- binpkg/ arch=i386, release= zesty/4650/ artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /unity8- jenkins. ubuntu. com/job/ lp-qtmir- ci/652/ rebuild
https:/