2
* Copyright (C) 2014-2015 Canonical, Ltd.
2
* Copyright (C) 2014-2016 Canonical, Ltd.
4
4
* This program is free software: you can redistribute it and/or modify it under
5
5
* the terms of the GNU Lesser General Public License version 3, as published by
68
69
: SessionInterface(parent)
69
70
, m_session(session)
70
71
, m_application(nullptr)
71
, m_parentSession(nullptr)
72
72
, m_children(new SessionModel(this))
73
73
, m_fullscreen(false)
74
74
, m_state(State::Starting)
77
, m_suspendTimer(new QTimer(this))
78
76
, m_promptSessionManager(promptSessionManager)
80
78
qCDebug(QTMIR_SESSIONS) << "Session::Session() " << this->name();
82
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
80
setSuspendTimer(new Timer);
84
m_suspendTimer->setSingleShot(true);
85
connect(m_suspendTimer, &QTimer::timeout, this, &Session::doSuspend);
82
connect(&m_surfaceList, &MirSurfaceListModel::emptyChanged, this, &Session::deleteIfZombieAndEmpty);
88
85
Session::~Session()
94
91
for (SessionInterface* child : children) {
97
if (m_parentSession) {
98
m_parentSession->removeChildSession(this);
100
94
if (m_application) {
101
95
m_application->setSession(nullptr);
104
98
delete m_children; m_children = nullptr;
100
delete m_suspendTimer;
102
Q_EMIT destroyed(this); // Early warning, while Session methods can still be accessed.
107
105
void Session::doSuspend()
109
107
Q_ASSERT(m_state == Session::Suspending);
111
auto surfaceList = m_surfaces.list();
112
if (surfaceList.empty()) {
109
if (m_surfaceList.count() == 0) {
113
110
qCDebug(QTMIR_SESSIONS) << "Application::suspend - no surface to call stopFrameDropper() on!";
115
for (int i = 0; i < surfaceList.count(); ++i) {
116
surfaceList[i]->stopFrameDropper();
112
for (int i = 0; i < m_surfaceList.count(); ++i) {
113
auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
114
surface->stopFrameDropper();
119
117
setState(Suspended);
122
void Session::release()
124
qCDebug(QTMIR_SESSIONS) << "Session::release " << name();
128
if (m_state == Stopped) {
133
120
QString Session::name() const
135
122
return QString::fromStdString(m_session->name());
216
198
// Only notify QML of surface creation once it has drawn its first frame.
217
199
if (newSurface->isFirstFrameDrawn()) {
218
appendSurface(newSurface);
200
prependSurface(newSurface);
220
202
connect(newSurface, &MirSurfaceInterface::firstFrameDrawn,
221
this, [this, newSurface]() { this->appendSurface(newSurface); });
203
this, [this, newSurface]() { this->prependSurface(newSurface); });
225
void Session::appendSurface(MirSurfaceInterface *newSurface)
207
void Session::prependSurface(MirSurfaceInterface *newSurface)
227
qCDebug(QTMIR_SESSIONS) << "Session::appendSurface - session=" << name() << "surface=" << newSurface;
209
qCDebug(QTMIR_SESSIONS) << "Session::prependSurface - session=" << name() << "surface=" << newSurface;
229
211
connect(newSurface, &MirSurfaceInterface::stateChanged,
230
212
this, &Session::updateFullscreenProperty);
232
m_surfaces.insert(m_surfaces.rowCount(), newSurface);
234
Q_EMIT lastSurfaceChanged(newSurface);
214
connect(newSurface, &MirSurfaceInterface::closeRequested, this, [this, newSurface]()
216
m_closingSurfaces.append(newSurface);
217
if (m_closingSurfaces.count() == 1) {
218
Q_EMIT hasClosingSurfacesChanged();
221
m_surfaceList.removeSurface(newSurface);
223
connect(newSurface, &QObject::destroyed, this, [this, newSurface]()
225
this->removeSurface(newSurface);
227
connect(newSurface, &MirSurfaceInterface::focusRequested, this, &SessionInterface::focusRequested);
229
m_surfaceList.prependSurface(newSurface);
236
232
if (m_state == Starting) {
237
233
setState(Running);
247
243
surface->disconnect(this);
249
if (m_surfaces.contains(surface)) {
250
bool lastSurfaceWasRemoved = lastSurface() == surface;
251
m_surfaces.remove(surface);
252
if (lastSurfaceWasRemoved) {
253
Q_EMIT lastSurfaceChanged(lastSurface());
245
if (m_surfaceList.contains(surface)) {
246
m_surfaceList.removeSurface(surface);
249
if (m_closingSurfaces.contains(surface)) {
250
m_closingSurfaces.removeAll(surface);
251
if (m_closingSurfaces.isEmpty()) {
252
Q_EMIT hasClosingSurfacesChanged();
260
259
void Session::updateFullscreenProperty()
262
if (m_surfaces.rowCount() > 0) {
261
if (m_surfaceList.count() > 0) {
263
262
// TODO: Figure out something better
264
setFullscreen(lastSurface()->state() == Mir::FullscreenState);
263
setFullscreen(m_surfaceList.get(0)->state() == Mir::FullscreenState);
266
265
// Keep the current value of the fullscreen property until we get a new
282
281
qCDebug(QTMIR_SESSIONS) << "Session::suspend - session=" << this << "state=" << sessionStateToString(m_state);
283
282
if (m_state == Running) {
284
283
session()->set_lifecycle_state(mir_lifecycle_state_will_suspend);
285
m_suspendTimer->start(1500);
284
m_suspendTimer->start();
287
286
foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) {
288
287
m_promptSessionManager->suspend_prompt_session(promptSession);
308
307
void Session::doResume()
310
309
if (m_state == Suspended) {
311
Q_ASSERT(m_surfaces.rowCount() > 0);
312
auto surfaceList = m_surfaces.list();
313
for (int i = 0; i < surfaceList.count(); ++i) {
314
surfaceList[i]->startFrameDropper();
310
for (int i = 0; i < m_surfaceList.count(); ++i) {
311
auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
312
surface->startFrameDropper();
335
333
if (m_state == Stopped) return;
337
auto surfaceList = m_surfaces.list();
338
for (int i = 0; i < surfaceList.count(); ++i) {
339
surfaceList[i]->close();
335
for (int i = 0; i < m_surfaceList.count(); ++i) {
336
auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
349
347
stopPromptSessions();
352
auto surfaceList = m_surfaces.list();
353
for (int i = 0; i < surfaceList.count(); ++i) {
354
surfaceList[i]->stopFrameDropper();
350
for (int i = 0; i < m_surfaceList.count(); ++i) {
351
auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
352
surface->stopFrameDropper();
375
370
Q_EMIT liveChanged(m_live);
377
372
setState(Stopped);
374
for (int i = 0; i < m_surfaceList.count(); ++i) {
375
auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
376
surface->setLive(false);
379
deleteIfZombieAndEmpty();
385
void Session::setParentSession(Session* session)
387
if (m_parentSession == session || session == this)
390
m_parentSession = session;
392
Q_EMIT parentSessionChanged(session);
395
384
void Session::addChildSession(SessionInterface* session)
397
386
insertChildSession(m_children->rowCount(), session);
388
if (m_surfaceList.count() > 0) {
389
// we assume that the top-most surface is the one that caused the prompt session to show up.
390
auto promptSurfaceList = static_cast<MirSurfaceListModel*>(m_surfaceList.get(0)->promptSurfaceList());
391
promptSurfaceList->addSurfaceList(session->surfaceList());
400
395
void Session::insertChildSession(uint index, SessionInterface* session)
402
397
qCDebug(QTMIR_SESSIONS) << "Session::insertChildSession - " << session->name() << " to " << name() << " @ " << index;
404
static_cast<Session*>(session)->setParentSession(this);
405
399
m_children->insert(index, session);
401
connect(session, &QObject::destroyed, this, [this, session]() { this->removeChildSession(session); });
407
403
switch (m_state) {
424
420
qCDebug(QTMIR_SESSIONS) << "Session::removeChildSession - " << session->name() << " from " << name();
422
disconnect(session, 0, this, 0);
426
424
if (m_children->contains(session)) {
427
425
m_children->remove(session);
428
static_cast<Session*>(session)->setParentSession(nullptr);
428
deleteIfZombieAndEmpty();
432
431
void Session::foreachChildSession(std::function<void(SessionInterface* session)> f) const
492
MirSurfaceInterface* Session::lastSurface() const
494
if (m_surfaces.rowCount() > 0) {
495
return m_surfaces.list().last();
491
void Session::deleteIfZombieAndEmpty()
493
if (!m_live && m_children->rowCount() == 0 && m_surfaceList.isEmpty()) {
494
qCDebug(QTMIR_SESSIONS).nospace() << "Session::deleteIfZombieAndEmpty[" << name() << "] - deleteLater()";
499
bool Session::hasClosingSurfaces() const
501
return m_closingSurfaces.count() > 0;
504
bool Session::hadSurface() const
509
void Session::setSuspendTimer(AbstractTimer *timer)
511
bool timerWasRunning = false;
513
if (m_suspendTimer) {
514
timerWasRunning = m_suspendTimer->isRunning();
515
delete m_suspendTimer;
518
m_suspendTimer = timer;
519
m_suspendTimer->setInterval(1500);
520
m_suspendTimer->setSingleShot(true);
521
connect(m_suspendTimer, &AbstractTimer::timeout, this, &Session::doSuspend);
523
if (timerWasRunning) {
524
m_suspendTimer->start();