~gerboland/qtmir/ual-catch-exception

« back to all changes in this revision

Viewing changes to src/modules/Unity/Application/application.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:
32
32
#include <mir/scene/session.h>
33
33
#include <mir/scene/snapshot.h>
34
34
 
 
35
// Unity API
 
36
#include <unity/shell/application/MirSurfaceInterface.h>
 
37
 
 
38
namespace unityapp = unity::shell::application;
35
39
namespace ms = mir::scene;
36
40
 
37
41
#define DEBUG_MSG qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::" << __func__
50
54
    , m_stage((desktopFileReader->stageHint() == "SideStage") ? Application::SideStage : Application::MainStage)
51
55
    , m_supportedStages(Application::MainStage|Application::SideStage)
52
56
    , m_state(InternalState::Starting)
53
 
    , m_focused(false)
54
57
    , m_arguments(arguments)
55
58
    , m_session(nullptr)
56
59
    , m_requestedState(RequestedRunning)
57
60
    , m_processState(ProcessUnknown)
58
 
    , m_closeTimer(nullptr)
 
61
    , m_stopTimer(nullptr)
59
62
    , m_exemptFromLifecycle(false)
60
63
{
61
64
    DEBUG_MSG << "()";
70
73
 
71
74
    m_rotatesWindowContents = m_desktopData->rotatesWindowContents();
72
75
 
73
 
    setCloseTimer(new Timer);
 
76
    setStopTimer(new Timer);
74
77
}
75
78
 
76
79
Application::~Application()
106
109
        delete m_session;
107
110
    }
108
111
    delete m_desktopData;
109
 
    delete m_closeTimer;
 
112
    delete m_stopTimer;
110
113
}
111
114
 
112
115
 
289
292
        return Starting;
290
293
    case InternalState::Running:
291
294
    case InternalState::RunningInBackground:
292
 
    case InternalState::SuspendingWaitSession:
293
 
    case InternalState::SuspendingWaitProcess:
294
295
    case InternalState::Closing:
295
296
        return Running;
 
297
    case InternalState::SuspendingWaitSession:
 
298
    case InternalState::SuspendingWaitProcess:
296
299
    case InternalState::Suspended:
297
300
        return Suspended;
298
301
    case InternalState::StoppedResumable:
319
322
    m_requestedState = value;
320
323
    Q_EMIT requestedStateChanged(m_requestedState);
321
324
 
322
 
    applyRequestedState();
 
325
    updateState();
323
326
}
324
327
 
325
 
void Application::applyRequestedState()
 
328
void Application::updateState()
326
329
{
327
 
    if (m_requestedState == RequestedRunning) {
 
330
    if ((!m_session && m_state != InternalState::Starting && m_state != InternalState::StoppedResumable)
 
331
        ||
 
332
        (m_session && m_session->surfaceList()->isEmpty() && m_session->hasClosingSurfaces())) {
 
333
        // As we might not be able to go to Closing state right now (eg, SuspendingWaitProcess),
 
334
        // store the intent in a separate variable.
 
335
        m_closing = true;
 
336
    }
 
337
 
 
338
    bool lostAllSurfaces = m_session && m_session->surfaceList()->isEmpty() && m_session->hadSurface()
 
339
            && !m_session->hasClosingSurfaces();
 
340
 
 
341
    if (m_closing || (lostAllSurfaces && m_state != InternalState::StoppedResumable)) {
 
342
        applyClosing();
 
343
    } else if (m_requestedState == RequestedRunning || (m_session && m_session->hasClosingSurfaces())) {
328
344
        applyRequestedRunning();
329
345
    } else {
330
346
        applyRequestedSuspended();
331
347
    }
332
348
}
333
349
 
 
350
void Application::applyClosing()
 
351
{
 
352
    switch (m_state) {
 
353
    case InternalState::Starting:
 
354
        // can't be
 
355
        Q_ASSERT(false);
 
356
        break;
 
357
    case InternalState::Running:
 
358
    case InternalState::RunningInBackground:
 
359
        if (!m_stopTimer->isRunning()) {
 
360
            m_stopTimer->start();
 
361
        }
 
362
        if (m_closing) {
 
363
            setInternalState(InternalState::Closing);
 
364
        }
 
365
        break;
 
366
    case InternalState::SuspendingWaitSession:
 
367
    case InternalState::Suspended:
 
368
        resume();
 
369
        break;
 
370
    case InternalState::SuspendingWaitProcess:
 
371
        // should leave the app alone until it reaches Suspended state
 
372
        break;
 
373
    case InternalState::Closing:
 
374
        // leave it alone
 
375
        Q_ASSERT(m_closing);
 
376
        Q_ASSERT(m_stopTimer->isRunning());
 
377
        break;
 
378
    case InternalState::StoppedResumable:
 
379
        setInternalState(InternalState::Stopped);
 
380
        break;
 
381
    case InternalState::Stopped:
 
382
        break;
 
383
    }
 
384
}
 
385
 
334
386
void Application::applyRequestedRunning()
335
387
{
 
388
    // We might be coming back from having lost all surfaces
 
389
    if (m_stopTimer->isRunning()) {
 
390
        m_stopTimer->stop();
 
391
    }
 
392
 
336
393
    switch (m_state) {
337
394
    case InternalState::Starting:
338
395
        // should leave the app alone until it reaches Running state
349
406
        // should leave the app alone until it reaches Suspended state
350
407
        break;
351
408
    case InternalState::Closing:
 
409
        // can't be
 
410
        Q_ASSERT(false);
352
411
        break;
353
412
    case InternalState::StoppedResumable:
354
413
        respawn();
361
420
 
362
421
void Application::applyRequestedSuspended()
363
422
{
 
423
    // We might be coming back from having lost all surfaces
 
424
    if (m_stopTimer->isRunning()) {
 
425
        m_stopTimer->stop();
 
426
    }
 
427
 
364
428
    switch (m_state) {
365
429
    case InternalState::Starting:
366
430
        // should leave the app alone until it reaches Running state
380
444
        // it's already going where we it's wanted
381
445
        break;
382
446
    case InternalState::Closing:
383
 
        // don't suspend while it is closing
 
447
        // can't be
 
448
        Q_ASSERT(false);
384
449
        break;
385
450
    case InternalState::StoppedResumable:
386
451
    case InternalState::Stopped:
391
456
 
392
457
bool Application::focused() const
393
458
{
394
 
    return m_focused;
 
459
    bool someSurfaceHasFocus = false; // to be proven wrong
 
460
    for (int i = 0; i < m_proxySurfaceList.rowCount() && !someSurfaceHasFocus; ++i) {
 
461
        someSurfaceHasFocus |= m_proxySurfaceList.get(i)->focused();
 
462
    }
 
463
    return someSurfaceHasFocus;
395
464
}
396
465
 
397
466
bool Application::fullscreen() const
416
485
    switch (m_state) {
417
486
    case InternalState::Starting:
418
487
        stop();
 
488
        // Don't wait for a confirmation.
 
489
        setInternalState(InternalState::Stopped);
419
490
        break;
420
491
    case InternalState::Running:
421
 
        doClose();
422
 
        break;
423
492
    case InternalState::RunningInBackground:
424
493
    case InternalState::SuspendingWaitSession:
425
494
    case InternalState::SuspendingWaitProcess:
426
495
    case InternalState::Suspended:
427
 
        setRequestedState(RequestedRunning);
428
 
        doClose();
 
496
        m_session->close();
429
497
        break;
430
498
    case InternalState::Closing:
431
499
        // already on the way
440
508
    }
441
509
}
442
510
 
443
 
void Application::doClose()
444
 
{
445
 
    Q_ASSERT(!m_closeTimer->isRunning());;
446
 
    Q_ASSERT(m_session != nullptr);
447
 
 
448
 
    m_session->close();
449
 
    m_closeTimer->start();
450
 
    setInternalState(InternalState::Closing);
451
 
}
452
 
 
453
511
void Application::setPid(pid_t pid)
454
512
{
455
513
    m_pid = pid;
468
526
        return;
469
527
 
470
528
    if (m_session) {
 
529
        m_proxySurfaceList.setSourceList(nullptr);
471
530
        m_session->disconnect(this);
 
531
        m_session->surfaceList()->disconnect(this);
472
532
        m_session->setApplication(nullptr);
473
533
        m_session->setParent(nullptr);
474
534
    }
500
560
 
501
561
        connect(m_session, &SessionInterface::stateChanged, this, &Application::onSessionStateChanged);
502
562
        connect(m_session, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged);
 
563
        connect(m_session, &SessionInterface::hasClosingSurfacesChanged, this, &Application::updateState);
 
564
        connect(m_session, &SessionInterface::focusRequested, this, &Application::focusRequested);
 
565
        connect(m_session->surfaceList(), &MirSurfaceListModel::emptyChanged, this, &Application::updateState);
503
566
 
504
567
        if (oldFullscreen != fullscreen())
505
568
            Q_EMIT fullscreenChanged(fullscreen());
 
569
 
 
570
        m_proxySurfaceList.setSourceList(m_session->surfaceList());
506
571
    } else {
507
 
        // this can only happen after the session has stopped and QML code called Session::release()
508
 
        Q_ASSERT(m_state == InternalState::Stopped || m_state == InternalState::StoppedResumable);
 
572
        // this can only happen after the session has stopped
 
573
        Q_ASSERT(m_state == InternalState::Stopped || m_state == InternalState::StoppedResumable
 
574
                || m_state == InternalState::Closing);
509
575
    }
510
576
 
511
577
    Q_EMIT sessionChanged(m_session);
545
611
            releaseWakelock();
546
612
            break;
547
613
        case InternalState::Closing:
 
614
            Q_EMIT closing();
548
615
            acquireWakelock();
549
616
            break;
550
617
        case InternalState::StoppedResumable:
565
632
        Q_EMIT stateChanged(this->state());
566
633
    }
567
634
 
568
 
    applyRequestedState();
569
 
}
570
 
 
571
 
void Application::setFocused(bool focused)
572
 
{
573
 
    DEBUG_MSG << "(focused=" << focused << ")";
574
 
 
575
 
    if (m_focused != focused) {
576
 
        m_focused = focused;
577
 
        Q_EMIT focusedChanged(focused);
578
 
    }
 
635
    updateState();
579
636
}
580
637
 
581
638
void Application::setProcessState(ProcessState newProcessState)
597
654
        }
598
655
        break;
599
656
    case ProcessSuspended:
600
 
        if (m_state == InternalState::Closing) {
601
 
            // If we get a process suspension event while we're closing, resume the process.
602
 
            Q_EMIT resumeProcessRequested();
603
 
        } else {
604
 
            setInternalState(InternalState::Suspended);
605
 
        }
 
657
        Q_ASSERT(m_state == InternalState::SuspendingWaitProcess);
 
658
        setInternalState(InternalState::Suspended);
606
659
        break;
607
660
    case ProcessFailed:
608
661
        // we assume the session always stop before the process
633
686
        break;
634
687
    }
635
688
 
636
 
    applyRequestedState();
 
689
    updateState();
637
690
}
638
691
 
639
692
void Application::suspend()
659
712
    DEBUG_MSG << "()";
660
713
 
661
714
    if (m_state == InternalState::Suspended || m_state == InternalState::SuspendingWaitProcess) {
662
 
        setInternalState(InternalState::Running);
663
715
        Q_EMIT resumeProcessRequested();
 
716
        setInternalState(InternalState::Running);
664
717
        if (m_processState == ProcessSuspended) {
665
718
            setProcessState(ProcessRunning); // should we wait for a resumed() signal?
666
719
        }
667
 
        m_session->resume();
 
720
        if (m_session) {
 
721
            m_session->resume();
 
722
        }
668
723
    } else if (m_state == InternalState::SuspendingWaitSession) {
669
724
        setInternalState(InternalState::Running);
670
725
        m_session->resume();
703
758
{
704
759
    if (m_exemptFromLifecycle != exemptFromLifecycle)
705
760
    {
 
761
        DEBUG_MSG << "(" << exemptFromLifecycle << ")";
706
762
        // We don't adjust current suspension state, we only care about exempt
707
763
        // status going into a suspend.
708
764
        m_exemptFromLifecycle = exemptFromLifecycle;
764
820
        Q_EMIT suspendProcessRequested();
765
821
        break;
766
822
    case Session::Stopped:
767
 
        if ((m_state == InternalState::SuspendingWaitProcess || m_state == InternalState::SuspendingWaitProcess) &&
768
 
             m_processState != Application::ProcessFailed) {
769
 
            // Session stopped normally while we're waiting for suspension.
770
 
            doClose();
771
 
            Q_EMIT resumeProcessRequested();
 
823
        if ((m_state == InternalState::SuspendingWaitSession || m_state == InternalState::SuspendingWaitProcess)
 
824
                && m_processState != Application::ProcessFailed) {
 
825
            // Session stopped normally while we're waiting for suspension
 
826
            stop();
 
827
            setInternalState(InternalState::Stopped);
772
828
        } else if (!canBeResumed()
773
829
                || m_state == InternalState::Starting
774
830
                || m_state == InternalState::Running
789
845
    }
790
846
}
791
847
 
792
 
void Application::setCloseTimer(AbstractTimer *timer)
 
848
void Application::setStopTimer(AbstractTimer *timer)
793
849
{
794
 
    delete m_closeTimer;
 
850
    delete m_stopTimer;
795
851
 
796
 
    m_closeTimer = timer;
797
 
    m_closeTimer->setInterval(3000);
798
 
    m_closeTimer->setSingleShot(true);
799
 
    connect(m_closeTimer, &Timer::timeout, this, &Application::stop);
 
852
    m_stopTimer = timer;
 
853
    m_stopTimer->setInterval(1000);
 
854
    m_stopTimer->setSingleShot(true);
 
855
    connect(m_stopTimer, &Timer::timeout, this, &Application::stop);
800
856
}
801
857
 
802
858
QSize Application::initialSurfaceSize() const
814
870
    }
815
871
}
816
872
 
 
873
unityapp::MirSurfaceListInterface* Application::surfaceList()
 
874
{
 
875
    return &m_proxySurfaceList;
 
876
}
 
877
 
 
878
void Application::requestFocus()
 
879
{
 
880
    if (m_proxySurfaceList.rowCount() > 0) {
 
881
        DEBUG_MSG << "() - Requesting focus for most recent app surface";
 
882
        m_proxySurfaceList.get(0)->requestFocus();
 
883
    } else {
 
884
        DEBUG_MSG << "() - emitting focusRequested()";
 
885
        Q_EMIT focusRequested();
 
886
    }
 
887
}
 
888
 
817
889
} // namespace qtmir