~lukas-kde/miral/shellchrome-windowinfo

« back to all changes in this revision

Viewing changes to miral-qt/src/modules/Unity/Application/session.cpp

  • Committer: Larry Price
  • Date: 2016-09-13 16:19:29 UTC
  • mto: (330.4.1 miral)
  • mto: This revision was merged to the branch mainline in revision 352.
  • Revision ID: larry.price@canonical.com-20160913161929-vs9ka1capmljq1es
Removing miral-qt from release branch, updating copyright file, and adding GPL3 license to root dir

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2014-2016 Canonical, Ltd.
3
 
 *
4
 
 * This program is free software: you can redistribute it and/or modify it under
5
 
 * the terms of the GNU Lesser General Public License version 3, as published by
6
 
 * the Free Software Foundation.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 
 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10
 
 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 
 * Lesser General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU Lesser General Public License
14
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 */
16
 
 
17
 
// local
18
 
#include "application.h"
19
 
#include "debughelpers.h"
20
 
#include "session.h"
21
 
#include "mirsurfaceinterface.h"
22
 
#include "mirsurfaceitem.h"
23
 
 
24
 
// mirserver
25
 
#include "logging.h"
26
 
 
27
 
// mir
28
 
#include <mir/scene/session.h>
29
 
#include <mir/scene/prompt_session.h>
30
 
#include <mir/scene/prompt_session_manager.h>
31
 
 
32
 
// Qt
33
 
#include <QPainter>
34
 
#include <QQmlEngine>
35
 
 
36
 
namespace ms = mir::scene;
37
 
 
38
 
using unity::shell::application::ApplicationInfoInterface;
39
 
 
40
 
#define DEBUG_MSG qCDebug(QTMIR_SURFACES).nospace() << "Session[" << (void*)this << ",name=" << name() << "]::" << __func__
41
 
 
42
 
namespace qtmir
43
 
{
44
 
 
45
 
namespace {
46
 
 
47
 
const char *sessionStateToString(SessionInterface::State state)
48
 
{
49
 
    switch (state) {
50
 
    case SessionInterface::Starting:
51
 
        return "starting";
52
 
    case SessionInterface::Running:
53
 
        return "running";
54
 
    case SessionInterface::Suspending:
55
 
        return "suspending";
56
 
    case SessionInterface::Suspended:
57
 
        return "suspended";
58
 
    case SessionInterface::Stopped:
59
 
        return "stopped";
60
 
    default:
61
 
        return "???";
62
 
    }
63
 
}
64
 
 
65
 
}
66
 
 
67
 
Session::Session(const std::shared_ptr<ms::Session>& session,
68
 
                 const std::shared_ptr<ms::PromptSessionManager>& promptSessionManager,
69
 
                 QObject *parent)
70
 
    : SessionInterface(parent)
71
 
    , m_session(session)
72
 
    , m_application(nullptr)
73
 
    , m_children(new SessionModel(this))
74
 
    , m_fullscreen(false)
75
 
    , m_state(State::Starting)
76
 
    , m_live(true)
77
 
    , m_promptSessionManager(promptSessionManager)
78
 
{
79
 
    DEBUG_MSG << "()";
80
 
 
81
 
    setSuspendTimer(new Timer);
82
 
 
83
 
    connect(&m_surfaceList, &MirSurfaceListModel::emptyChanged, this, &Session::deleteIfZombieAndEmpty);
84
 
}
85
 
 
86
 
Session::~Session()
87
 
{
88
 
    DEBUG_MSG << "()";
89
 
    stopPromptSessions();
90
 
 
91
 
    const QList<SessionInterface*> children(m_children->list());
92
 
    for (SessionInterface* child : children) {
93
 
        delete child;
94
 
    }
95
 
    if (m_application) {
96
 
        m_application->setSession(nullptr);
97
 
    }
98
 
 
99
 
    delete m_children; m_children = nullptr;
100
 
 
101
 
    delete m_suspendTimer;
102
 
 
103
 
    Q_EMIT destroyed(this); // Early warning, while Session methods can still be accessed.
104
 
}
105
 
 
106
 
void Session::doSuspend()
107
 
{
108
 
    Q_ASSERT(m_state == Session::Suspending);
109
 
 
110
 
    if (m_surfaceList.count() == 0) {
111
 
        DEBUG_MSG << " no surface to call stopFrameDropper() on!";
112
 
    } else {
113
 
        for (int i = 0; i < m_surfaceList.count(); ++i) {
114
 
            auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
115
 
            surface->stopFrameDropper();
116
 
        }
117
 
    }
118
 
    setState(Suspended);
119
 
}
120
 
 
121
 
QString Session::name() const
122
 
{
123
 
    return QString::fromStdString(m_session->name());
124
 
}
125
 
 
126
 
std::shared_ptr<ms::Session> Session::session() const
127
 
{
128
 
    return m_session;
129
 
}
130
 
 
131
 
ApplicationInfoInterface* Session::application() const
132
 
{
133
 
    return m_application;
134
 
}
135
 
 
136
 
MirSurfaceListModel* Session::surfaceList()
137
 
{
138
 
    return &m_surfaceList;
139
 
}
140
 
 
141
 
MirSurfaceListModel* Session::promptSurfaceList()
142
 
{
143
 
    return &m_promptSurfaceList;
144
 
}
145
 
 
146
 
Session::State Session::state() const
147
 
{
148
 
    return m_state;
149
 
}
150
 
 
151
 
void Session::setState(State state)
152
 
{
153
 
    if (m_state == state) {
154
 
        return;
155
 
    }
156
 
 
157
 
    DEBUG_MSG << "(state=" << sessionStateToString(state) << ")";
158
 
 
159
 
    if (m_state == Suspending) {
160
 
        m_suspendTimer->stop();
161
 
    }
162
 
 
163
 
    m_state = state;
164
 
 
165
 
    switch (m_state) {
166
 
        case Starting:
167
 
        case Running:
168
 
            break;
169
 
        case Suspending:
170
 
            m_suspendTimer->start();
171
 
            break;
172
 
        case Suspended:
173
 
        case Stopped:
174
 
            break;
175
 
    }
176
 
 
177
 
    Q_EMIT stateChanged(m_state);
178
 
}
179
 
 
180
 
bool Session::fullscreen() const
181
 
{
182
 
    return m_fullscreen;
183
 
}
184
 
 
185
 
bool Session::live() const
186
 
{
187
 
    return m_live;
188
 
}
189
 
 
190
 
void Session::setApplication(ApplicationInfoInterface* application)
191
 
{
192
 
    if (m_application == application)
193
 
        return;
194
 
 
195
 
    m_application = static_cast<Application*>(application);
196
 
    Q_EMIT applicationChanged(application);
197
 
}
198
 
 
199
 
void Session::registerSurface(MirSurfaceInterface *newSurface)
200
 
{
201
 
    DEBUG_MSG << "(surface=" << newSurface << ")";
202
 
 
203
 
    // Only notify QML of surface creation once it has drawn its first frame.
204
 
    if (newSurface->isFirstFrameDrawn()) {
205
 
        prependSurface(newSurface);
206
 
    } else {
207
 
        connect(newSurface, &MirSurfaceInterface::firstFrameDrawn, this, [this, newSurface]()
208
 
            {
209
 
                newSurface->disconnect(this);
210
 
                this->prependSurface(newSurface);
211
 
            });
212
 
    }
213
 
}
214
 
 
215
 
void Session::prependSurface(MirSurfaceInterface *newSurface)
216
 
{
217
 
    DEBUG_MSG << "(surface=" << newSurface << ")";
218
 
 
219
 
    connect(newSurface, &MirSurfaceInterface::stateChanged,
220
 
        this, &Session::updateFullscreenProperty);
221
 
 
222
 
    connect(newSurface, &MirSurfaceInterface::closeRequested, this, [this, newSurface]()
223
 
        {
224
 
            m_closingSurfaces.append(newSurface);
225
 
            if (m_closingSurfaces.count() == 1) {
226
 
                Q_EMIT hasClosingSurfacesChanged();
227
 
            }
228
 
 
229
 
            m_surfaceList.removeSurface(newSurface);
230
 
        });
231
 
    connect(newSurface, &QObject::destroyed, this, [this, newSurface]()
232
 
        {
233
 
            this->removeSurface(newSurface);
234
 
        });
235
 
    connect(newSurface, &MirSurfaceInterface::focusRequested, this, &SessionInterface::focusRequested);
236
 
 
237
 
    m_surfaceList.prependSurface(newSurface);
238
 
    m_hadSurface = true;
239
 
 
240
 
    if (m_state == Starting) {
241
 
        setState(Running);
242
 
    }
243
 
 
244
 
    updateFullscreenProperty();
245
 
}
246
 
 
247
 
void Session::removeSurface(MirSurfaceInterface* surface)
248
 
{
249
 
    DEBUG_MSG << "(surface=" << surface << ")";
250
 
 
251
 
    surface->disconnect(this);
252
 
 
253
 
    if (m_surfaceList.contains(surface)) {
254
 
        m_surfaceList.removeSurface(surface);
255
 
    }
256
 
 
257
 
    if (m_closingSurfaces.contains(surface)) {
258
 
        m_closingSurfaces.removeAll(surface);
259
 
        if (m_closingSurfaces.isEmpty()) {
260
 
            Q_EMIT hasClosingSurfacesChanged();
261
 
        }
262
 
    }
263
 
 
264
 
    updateFullscreenProperty();
265
 
}
266
 
 
267
 
void Session::updateFullscreenProperty()
268
 
{
269
 
    if (m_surfaceList.count() > 0) {
270
 
        // TODO: Figure out something better
271
 
        setFullscreen(m_surfaceList.get(0)->state() == Mir::FullscreenState);
272
 
    } else {
273
 
        // Keep the current value of the fullscreen property until we get a new
274
 
        // surface
275
 
    }
276
 
}
277
 
 
278
 
void Session::setFullscreen(bool fullscreen)
279
 
{
280
 
    if (m_fullscreen != fullscreen) {
281
 
        DEBUG_MSG << "(" << fullscreen << ")";
282
 
        m_fullscreen = fullscreen;
283
 
        Q_EMIT fullscreenChanged(m_fullscreen);
284
 
    }
285
 
}
286
 
 
287
 
void Session::suspend()
288
 
{
289
 
    DEBUG_MSG << " state=" << sessionStateToString(m_state);
290
 
    if (m_state == Running) {
291
 
        session()->set_lifecycle_state(mir_lifecycle_state_will_suspend);
292
 
        m_suspendTimer->start();
293
 
 
294
 
        foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) {
295
 
            m_promptSessionManager->suspend_prompt_session(promptSession);
296
 
        });
297
 
 
298
 
        foreachChildSession([](SessionInterface* session) {
299
 
            session->suspend();
300
 
        });
301
 
 
302
 
        setState(Suspending);
303
 
    }
304
 
}
305
 
 
306
 
void Session::resume()
307
 
{
308
 
    DEBUG_MSG << " state=" << sessionStateToString(m_state);
309
 
 
310
 
    if (m_state == Suspending || m_state == Suspended) {
311
 
        doResume();
312
 
    }
313
 
}
314
 
 
315
 
void Session::doResume()
316
 
{
317
 
    if (m_state == Suspended) {
318
 
        for (int i = 0; i < m_surfaceList.count(); ++i) {
319
 
            auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
320
 
            surface->startFrameDropper();
321
 
        }
322
 
    }
323
 
 
324
 
    session()->set_lifecycle_state(mir_lifecycle_state_resumed);
325
 
 
326
 
    foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) {
327
 
        m_promptSessionManager->resume_prompt_session(promptSession);
328
 
    });
329
 
 
330
 
    foreachChildSession([](SessionInterface* session) {
331
 
        session->resume();
332
 
    });
333
 
 
334
 
    setState(Running);
335
 
}
336
 
 
337
 
void Session::close()
338
 
{
339
 
    DEBUG_MSG << "()";
340
 
 
341
 
    if (m_state == Stopped) return;
342
 
 
343
 
    for (int i = 0; i < m_surfaceList.count(); ++i) {
344
 
        auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
345
 
        surface->close();
346
 
    }
347
 
}
348
 
 
349
 
void Session::stop()
350
 
{
351
 
    DEBUG_MSG << "()";
352
 
 
353
 
    if (m_state != Stopped) {
354
 
 
355
 
        stopPromptSessions();
356
 
 
357
 
        {
358
 
            for (int i = 0; i < m_surfaceList.count(); ++i) {
359
 
                auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
360
 
                surface->stopFrameDropper();
361
 
            }
362
 
        }
363
 
 
364
 
        foreachChildSession([](SessionInterface* session) {
365
 
            session->stop();
366
 
        });
367
 
 
368
 
        setState(Stopped);
369
 
    }
370
 
}
371
 
 
372
 
void Session::setLive(const bool live)
373
 
{
374
 
    if (m_live != live) {
375
 
        DEBUG_MSG << "(" << live << ")";
376
 
 
377
 
        m_live = live;
378
 
        Q_EMIT liveChanged(m_live);
379
 
        if (!live) {
380
 
            setState(Stopped);
381
 
 
382
 
            for (int i = 0; i < m_surfaceList.count(); ++i) {
383
 
                auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
384
 
                surface->setLive(false);
385
 
            }
386
 
 
387
 
            deleteIfZombieAndEmpty();
388
 
        }
389
 
    }
390
 
}
391
 
 
392
 
void Session::addChildSession(SessionInterface* session)
393
 
{
394
 
    insertChildSession(m_children->rowCount(), session);
395
 
}
396
 
 
397
 
void Session::insertChildSession(uint index, SessionInterface* session)
398
 
{
399
 
    DEBUG_MSG << "(index=" << index << ", Session[" << (void*)session << ",name=" << session->name() << "])";
400
 
    Q_ASSERT(!m_children->contains(session));
401
 
 
402
 
    m_children->insert(index, session);
403
 
 
404
 
    // Flatten the list of prompt surfaces
405
 
    m_promptSurfaceList.addSurfaceList(session->surfaceList());
406
 
    m_promptSurfaceList.addSurfaceList(session->promptSurfaceList());
407
 
 
408
 
    connect(session, &QObject::destroyed, this, [this, session]() { this->removeChildSession(session); });
409
 
 
410
 
    switch (m_state) {
411
 
        case Starting:
412
 
        case Running:
413
 
            session->resume();
414
 
            break;
415
 
        case Suspending:
416
 
        case Suspended:
417
 
            session->suspend();
418
 
            break;
419
 
        case Stopped:
420
 
            session->stop();
421
 
            break;
422
 
    }
423
 
}
424
 
 
425
 
void Session::removeChildSession(SessionInterface* session)
426
 
{
427
 
    DEBUG_MSG << "(Session[" << (void*)session << ",name=" << session->name() << "])";
428
 
 
429
 
    disconnect(session, 0, this, 0);
430
 
 
431
 
    if (m_children->contains(session)) {
432
 
        m_children->remove(session);
433
 
        m_promptSurfaceList.removeSurfaceList(session->surfaceList());
434
 
        m_promptSurfaceList.removeSurfaceList(session->promptSurfaceList());
435
 
    }
436
 
 
437
 
    deleteIfZombieAndEmpty();
438
 
}
439
 
 
440
 
void Session::foreachChildSession(const std::function<void(SessionInterface* session)>& f) const
441
 
{
442
 
    const QList<SessionInterface*> children(m_children->list());
443
 
    for (SessionInterface* child : children) {
444
 
        f(child);
445
 
    }
446
 
}
447
 
 
448
 
SessionModel* Session::childSessions() const
449
 
{
450
 
    return m_children;
451
 
}
452
 
 
453
 
void Session::appendPromptSession(const std::shared_ptr<ms::PromptSession>& promptSession)
454
 
{
455
 
    DEBUG_MSG << "(promptSession=" << (promptSession ? promptSession.get() : nullptr) << ")";
456
 
 
457
 
    m_promptSessions.append(promptSession);
458
 
}
459
 
 
460
 
void Session::removePromptSession(const std::shared_ptr<ms::PromptSession>& promptSession)
461
 
{
462
 
    DEBUG_MSG << "(promptSession=" << (promptSession ? promptSession.get() : nullptr) << ")";
463
 
 
464
 
    m_promptSessions.removeAll(promptSession);
465
 
}
466
 
 
467
 
void Session::stopPromptSessions()
468
 
{
469
 
    const QList<SessionInterface*> children(m_children->list());
470
 
    for (SessionInterface* child : children) {
471
 
        static_cast<Session*>(child)->stopPromptSessions();
472
 
    }
473
 
 
474
 
    QVector<std::shared_ptr<ms::PromptSession>> copy(m_promptSessions);
475
 
    QVectorIterator<std::shared_ptr<ms::PromptSession>> it(copy);
476
 
    for ( it.toBack(); it.hasPrevious(); ) {
477
 
        std::shared_ptr<ms::PromptSession> promptSession = it.previous();
478
 
        DEBUG_MSG << " - promptSession=" << promptSession.get();
479
 
 
480
 
        m_promptSessionManager->stop_prompt_session(promptSession);
481
 
    }
482
 
}
483
 
 
484
 
std::shared_ptr<ms::PromptSession> Session::activePromptSession() const
485
 
{
486
 
    if (m_promptSessions.count() > 0)
487
 
        return m_promptSessions.back();
488
 
    return nullptr;
489
 
}
490
 
 
491
 
void Session::foreachPromptSession(const std::function<void(const std::shared_ptr<ms::PromptSession>&)>& f) const
492
 
{
493
 
    Q_FOREACH (std::shared_ptr<ms::PromptSession> promptSession, m_promptSessions) {
494
 
        f(promptSession);
495
 
    }
496
 
}
497
 
 
498
 
void Session::deleteIfZombieAndEmpty()
499
 
{
500
 
    if (!m_live && m_children->rowCount() == 0 && m_surfaceList.isEmpty()) {
501
 
        DEBUG_MSG << " - deleteLater()";
502
 
        deleteLater();
503
 
    }
504
 
}
505
 
 
506
 
bool Session::hasClosingSurfaces() const
507
 
{
508
 
    return m_closingSurfaces.count() > 0;
509
 
}
510
 
 
511
 
bool Session::hadSurface() const
512
 
{
513
 
    return m_hadSurface;
514
 
}
515
 
 
516
 
bool Session::activeFocus() const
517
 
{
518
 
    for (int i = 0; i < m_surfaceList.count(); ++i) {
519
 
        auto surface = static_cast<const MirSurfaceInterface*>(m_surfaceList.get(i));
520
 
        if (surface->activeFocus()) {
521
 
            return true;
522
 
        }
523
 
    }
524
 
 
525
 
    return false;
526
 
}
527
 
 
528
 
pid_t Session::pid() const
529
 
{
530
 
    return m_session->process_id();
531
 
}
532
 
 
533
 
void Session::setSuspendTimer(AbstractTimer *timer)
534
 
{
535
 
    bool timerWasRunning = false;
536
 
 
537
 
    if (m_suspendTimer) {
538
 
        timerWasRunning = m_suspendTimer->isRunning();
539
 
        delete m_suspendTimer;
540
 
    }
541
 
 
542
 
    m_suspendTimer = timer;
543
 
    m_suspendTimer->setInterval(1500);
544
 
    m_suspendTimer->setSingleShot(true);
545
 
    connect(m_suspendTimer, &AbstractTimer::timeout, this, &Session::doSuspend);
546
 
 
547
 
    if (timerWasRunning) {
548
 
        m_suspendTimer->start();
549
 
    }
550
 
}
551
 
 
552
 
} // namespace qtmir