~gerboland/qtmir/ual-catch-exception

« back to all changes in this revision

Viewing changes to src/modules/Unity/Application/session.cpp

  • Committer: CI Train Bot
  • Author(s): Daniel d'Andrada
  • Date: 2016-04-13 18:38:49 UTC
  • mfrom: (466.2.16 surfaceListModel)
  • Revision ID: ci-train-bot@canonical.com-20160413183849-qdqd0akyoa4rdl9i
Surface-based window management

- Session is no longer exported to QML. It's now an internal qtmir concept.
Approved by: Gerry Boland

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2014-2015 Canonical, Ltd.
 
2
 * Copyright (C) 2014-2016 Canonical, Ltd.
3
3
 *
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
18
18
#include "application.h"
19
19
#include "debughelpers.h"
20
20
#include "session.h"
 
21
#include "mirsurfaceinterface.h"
21
22
#include "mirsurfacemanager.h"
22
23
#include "mirsurfaceitem.h"
23
24
 
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)
75
75
    , m_live(true)
76
 
    , m_released(false)
77
 
    , m_suspendTimer(new QTimer(this))
78
76
    , m_promptSessionManager(promptSessionManager)
79
77
{
80
78
    qCDebug(QTMIR_SESSIONS) << "Session::Session() " << this->name();
81
79
 
82
 
    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
 
80
    setSuspendTimer(new Timer);
83
81
 
84
 
    m_suspendTimer->setSingleShot(true);
85
 
    connect(m_suspendTimer, &QTimer::timeout, this, &Session::doSuspend);
 
82
    connect(&m_surfaceList, &MirSurfaceListModel::emptyChanged, this, &Session::deleteIfZombieAndEmpty);
86
83
}
87
84
 
88
85
Session::~Session()
94
91
    for (SessionInterface* child : children) {
95
92
        delete child;
96
93
    }
97
 
    if (m_parentSession) {
98
 
        m_parentSession->removeChildSession(this);
99
 
    }
100
94
    if (m_application) {
101
95
        m_application->setSession(nullptr);
102
96
    }
103
97
 
104
98
    delete m_children; m_children = nullptr;
 
99
 
 
100
    delete m_suspendTimer;
 
101
 
 
102
    Q_EMIT destroyed(this); // Early warning, while Session methods can still be accessed.
105
103
}
106
104
 
107
105
void Session::doSuspend()
108
106
{
109
107
    Q_ASSERT(m_state == Session::Suspending);
110
108
 
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!";
114
111
    } else {
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();
117
115
        }
118
116
    }
119
117
    setState(Suspended);
120
118
}
121
119
 
122
 
void Session::release()
123
 
{
124
 
    qCDebug(QTMIR_SESSIONS) << "Session::release " << name();
125
 
 
126
 
    m_released = true;
127
 
 
128
 
    if (m_state == Stopped) {
129
 
        deleteLater();
130
 
    }
131
 
}
132
 
 
133
120
QString Session::name() const
134
121
{
135
122
    return QString::fromStdString(m_session->name());
145
132
    return m_application;
146
133
}
147
134
 
148
 
const ObjectListModel<MirSurfaceInterface>* Session::surfaces() const
149
 
{
150
 
    return &m_surfaces;
151
 
}
152
 
 
153
 
SessionInterface* Session::parentSession() const
154
 
{
155
 
    return m_parentSession;
 
135
MirSurfaceListModel* Session::surfaceList()
 
136
{
 
137
    return &m_surfaceList;
156
138
}
157
139
 
158
140
Session::State Session::state() const
180
162
        case Running:
181
163
            break;
182
164
        case Suspending:
183
 
            m_suspendTimer->start(1500);
 
165
            m_suspendTimer->start();
184
166
            break;
185
167
        case Suspended:
186
168
        case Stopped:
215
197
 
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);
219
201
    } else {
220
202
        connect(newSurface, &MirSurfaceInterface::firstFrameDrawn,
221
 
                this, [this, newSurface]() { this->appendSurface(newSurface); });
 
203
                this, [this, newSurface]() { this->prependSurface(newSurface); });
222
204
    }
223
205
}
224
206
 
225
 
void Session::appendSurface(MirSurfaceInterface *newSurface)
 
207
void Session::prependSurface(MirSurfaceInterface *newSurface)
226
208
{
227
 
    qCDebug(QTMIR_SESSIONS) << "Session::appendSurface - session=" << name() << "surface=" << newSurface;
 
209
    qCDebug(QTMIR_SESSIONS) << "Session::prependSurface - session=" << name() << "surface=" << newSurface;
228
210
 
229
211
    connect(newSurface, &MirSurfaceInterface::stateChanged,
230
212
        this, &Session::updateFullscreenProperty);
231
213
 
232
 
    m_surfaces.insert(m_surfaces.rowCount(), newSurface);
233
 
 
234
 
    Q_EMIT lastSurfaceChanged(newSurface);
 
214
    connect(newSurface, &MirSurfaceInterface::closeRequested, this, [this, newSurface]()
 
215
        {
 
216
            m_closingSurfaces.append(newSurface);
 
217
            if (m_closingSurfaces.count() == 1) {
 
218
                Q_EMIT hasClosingSurfacesChanged();
 
219
            }
 
220
 
 
221
            m_surfaceList.removeSurface(newSurface);
 
222
        });
 
223
    connect(newSurface, &QObject::destroyed, this, [this, newSurface]()
 
224
        {
 
225
            this->removeSurface(newSurface);
 
226
        });
 
227
    connect(newSurface, &MirSurfaceInterface::focusRequested, this, &SessionInterface::focusRequested);
 
228
 
 
229
    m_surfaceList.prependSurface(newSurface);
 
230
    m_hadSurface = true;
235
231
 
236
232
    if (m_state == Starting) {
237
233
        setState(Running);
246
242
 
247
243
    surface->disconnect(this);
248
244
 
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);
 
247
    }
 
248
 
 
249
    if (m_closingSurfaces.contains(surface)) {
 
250
        m_closingSurfaces.removeAll(surface);
 
251
        if (m_closingSurfaces.isEmpty()) {
 
252
            Q_EMIT hasClosingSurfacesChanged();
254
253
        }
255
254
    }
256
255
 
259
258
 
260
259
void Session::updateFullscreenProperty()
261
260
{
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);
265
264
    } else {
266
265
        // Keep the current value of the fullscreen property until we get a new
267
266
        // surface
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();
286
285
 
287
286
        foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) {
288
287
            m_promptSessionManager->suspend_prompt_session(promptSession);
308
307
void Session::doResume()
309
308
{
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();
315
313
        }
316
314
    }
317
315
 
334
332
 
335
333
    if (m_state == Stopped) return;
336
334
 
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));
 
337
        surface->close();
340
338
    }
341
339
}
342
340
 
349
347
        stopPromptSessions();
350
348
 
351
349
        {
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();
355
353
            }
356
354
        }
357
355
 
360
358
        });
361
359
 
362
360
        setState(Stopped);
363
 
        if (m_released) {
364
 
            deleteLater();
365
 
        }
366
361
    }
367
362
}
368
363
 
375
370
        Q_EMIT liveChanged(m_live);
376
371
        if (!live) {
377
372
            setState(Stopped);
378
 
            if (m_released) {
379
 
                deleteLater();
 
373
 
 
374
            for (int i = 0; i < m_surfaceList.count(); ++i) {
 
375
                auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
 
376
                surface->setLive(false);
380
377
            }
 
378
 
 
379
            deleteIfZombieAndEmpty();
381
380
        }
382
381
    }
383
382
}
384
383
 
385
 
void Session::setParentSession(Session* session)
386
 
{
387
 
    if (m_parentSession == session || session == this)
388
 
        return;
389
 
 
390
 
    m_parentSession = session;
391
 
 
392
 
    Q_EMIT parentSessionChanged(session);
393
 
}
394
 
 
395
384
void Session::addChildSession(SessionInterface* session)
396
385
{
397
386
    insertChildSession(m_children->rowCount(), session);
 
387
 
 
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());
 
392
    }
398
393
}
399
394
 
400
395
void Session::insertChildSession(uint index, SessionInterface* session)
401
396
{
402
397
    qCDebug(QTMIR_SESSIONS) << "Session::insertChildSession - " << session->name() << " to " << name() << " @  " << index;
403
398
 
404
 
    static_cast<Session*>(session)->setParentSession(this);
405
399
    m_children->insert(index, session);
406
400
 
 
401
    connect(session, &QObject::destroyed, this, [this, session]() { this->removeChildSession(session); });
 
402
 
407
403
    switch (m_state) {
408
404
        case Starting:
409
405
        case Running:
423
419
{
424
420
    qCDebug(QTMIR_SESSIONS) << "Session::removeChildSession - " << session->name() << " from " << name();
425
421
 
 
422
    disconnect(session, 0, this, 0);
 
423
 
426
424
    if (m_children->contains(session)) {
427
425
        m_children->remove(session);
428
 
        static_cast<Session*>(session)->setParentSession(nullptr);
429
426
    }
 
427
 
 
428
    deleteIfZombieAndEmpty();
430
429
}
431
430
 
432
431
void Session::foreachChildSession(std::function<void(SessionInterface* session)> f) const
489
488
    }
490
489
}
491
490
 
492
 
MirSurfaceInterface* Session::lastSurface() const
493
 
{
494
 
    if (m_surfaces.rowCount() > 0) {
495
 
        return m_surfaces.list().last();
496
 
    } else {
497
 
        return nullptr;
 
491
void Session::deleteIfZombieAndEmpty()
 
492
{
 
493
    if (!m_live && m_children->rowCount() == 0 && m_surfaceList.isEmpty()) {
 
494
        qCDebug(QTMIR_SESSIONS).nospace() << "Session::deleteIfZombieAndEmpty[" << name() << "] - deleteLater()";
 
495
        deleteLater();
 
496
    }
 
497
}
 
498
 
 
499
bool Session::hasClosingSurfaces() const
 
500
{
 
501
    return m_closingSurfaces.count() > 0;
 
502
}
 
503
 
 
504
bool Session::hadSurface() const
 
505
{
 
506
    return m_hadSurface;
 
507
}
 
508
 
 
509
void Session::setSuspendTimer(AbstractTimer *timer)
 
510
{
 
511
    bool timerWasRunning = false;
 
512
 
 
513
    if (m_suspendTimer) {
 
514
        timerWasRunning = m_suspendTimer->isRunning();
 
515
        delete m_suspendTimer;
 
516
    }
 
517
 
 
518
    m_suspendTimer = timer;
 
519
    m_suspendTimer->setInterval(1500);
 
520
    m_suspendTimer->setSingleShot(true);
 
521
    connect(m_suspendTimer, &AbstractTimer::timeout, this, &Session::doSuspend);
 
522
 
 
523
    if (timerWasRunning) {
 
524
        m_suspendTimer->start();
498
525
    }
499
526
}
500
527