32
32
#include <mir/scene/session.h>
33
33
#include <mir/scene/snapshot.h>
36
#include <unity/shell/application/MirSurfaceInterface.h>
38
namespace unityapp = unity::shell::application;
35
39
namespace ms = mir::scene;
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)
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)
290
293
case InternalState::Running:
291
294
case InternalState::RunningInBackground:
292
case InternalState::SuspendingWaitSession:
293
case InternalState::SuspendingWaitProcess:
294
295
case InternalState::Closing:
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);
322
applyRequestedState();
325
void Application::applyRequestedState()
328
void Application::updateState()
327
if (m_requestedState == RequestedRunning) {
330
if ((!m_session && m_state != InternalState::Starting && m_state != InternalState::StoppedResumable)
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.
338
bool lostAllSurfaces = m_session && m_session->surfaceList()->isEmpty() && m_session->hadSurface()
339
&& !m_session->hasClosingSurfaces();
341
if (m_closing || (lostAllSurfaces && m_state != InternalState::StoppedResumable)) {
343
} else if (m_requestedState == RequestedRunning || (m_session && m_session->hasClosingSurfaces())) {
328
344
applyRequestedRunning();
330
346
applyRequestedSuspended();
350
void Application::applyClosing()
353
case InternalState::Starting:
357
case InternalState::Running:
358
case InternalState::RunningInBackground:
359
if (!m_stopTimer->isRunning()) {
360
m_stopTimer->start();
363
setInternalState(InternalState::Closing);
366
case InternalState::SuspendingWaitSession:
367
case InternalState::Suspended:
370
case InternalState::SuspendingWaitProcess:
371
// should leave the app alone until it reaches Suspended state
373
case InternalState::Closing:
376
Q_ASSERT(m_stopTimer->isRunning());
378
case InternalState::StoppedResumable:
379
setInternalState(InternalState::Stopped);
381
case InternalState::Stopped:
334
386
void Application::applyRequestedRunning()
388
// We might be coming back from having lost all surfaces
389
if (m_stopTimer->isRunning()) {
336
393
switch (m_state) {
337
394
case InternalState::Starting:
338
395
// should leave the app alone until it reaches Running state
362
421
void Application::applyRequestedSuspended()
423
// We might be coming back from having lost all surfaces
424
if (m_stopTimer->isRunning()) {
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
382
446
case InternalState::Closing:
383
// don't suspend while it is closing
385
450
case InternalState::StoppedResumable:
386
451
case InternalState::Stopped:
392
457
bool Application::focused() const
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();
463
return someSurfaceHasFocus;
397
466
bool Application::fullscreen() const
416
485
switch (m_state) {
417
486
case InternalState::Starting:
488
// Don't wait for a confirmation.
489
setInternalState(InternalState::Stopped);
420
491
case InternalState::Running:
423
492
case InternalState::RunningInBackground:
424
493
case InternalState::SuspendingWaitSession:
425
494
case InternalState::SuspendingWaitProcess:
426
495
case InternalState::Suspended:
427
setRequestedState(RequestedRunning);
430
498
case InternalState::Closing:
431
499
// already on the way
443
void Application::doClose()
445
Q_ASSERT(!m_closeTimer->isRunning());;
446
Q_ASSERT(m_session != nullptr);
449
m_closeTimer->start();
450
setInternalState(InternalState::Closing);
453
511
void Application::setPid(pid_t pid)
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);
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);
504
567
if (oldFullscreen != fullscreen())
505
568
Q_EMIT fullscreenChanged(fullscreen());
570
m_proxySurfaceList.setSourceList(m_session->surfaceList());
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);
511
577
Q_EMIT sessionChanged(m_session);
565
632
Q_EMIT stateChanged(this->state());
568
applyRequestedState();
571
void Application::setFocused(bool focused)
573
DEBUG_MSG << "(focused=" << focused << ")";
575
if (m_focused != focused) {
577
Q_EMIT focusedChanged(focused);
581
638
void Application::setProcessState(ProcessState newProcessState)
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();
604
setInternalState(InternalState::Suspended);
657
Q_ASSERT(m_state == InternalState::SuspendingWaitProcess);
658
setInternalState(InternalState::Suspended);
607
660
case ProcessFailed:
608
661
// we assume the session always stop before the process
659
712
DEBUG_MSG << "()";
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?
668
723
} else if (m_state == InternalState::SuspendingWaitSession) {
669
724
setInternalState(InternalState::Running);
670
725
m_session->resume();
704
759
if (m_exemptFromLifecycle != exemptFromLifecycle)
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();
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.
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
827
setInternalState(InternalState::Stopped);
772
828
} else if (!canBeResumed()
773
829
|| m_state == InternalState::Starting
774
830
|| m_state == InternalState::Running
792
void Application::setCloseTimer(AbstractTimer *timer)
848
void Application::setStopTimer(AbstractTimer *timer)
796
m_closeTimer = timer;
797
m_closeTimer->setInterval(3000);
798
m_closeTimer->setSingleShot(true);
799
connect(m_closeTimer, &Timer::timeout, this, &Application::stop);
853
m_stopTimer->setInterval(1000);
854
m_stopTimer->setSingleShot(true);
855
connect(m_stopTimer, &Timer::timeout, this, &Application::stop);
802
858
QSize Application::initialSurfaceSize() const
873
unityapp::MirSurfaceListInterface* Application::surfaceList()
875
return &m_proxySurfaceList;
878
void Application::requestFocus()
880
if (m_proxySurfaceList.rowCount() > 0) {
881
DEBUG_MSG << "() - Requesting focus for most recent app surface";
882
m_proxySurfaceList.get(0)->requestFocus();
884
DEBUG_MSG << "() - emitting focusRequested()";
885
Q_EMIT focusRequested();
817
889
} // namespace qtmir