summaryrefslogtreecommitdiffstats
path: root/src/modules
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/Unity/Application/CMakeLists.txt1
-rw-r--r--src/modules/Unity/Application/application.cpp390
-rw-r--r--src/modules/Unity/Application/application.h78
-rw-r--r--src/modules/Unity/Application/application_manager.cpp302
-rw-r--r--src/modules/Unity/Application/application_manager.h15
-rw-r--r--src/modules/Unity/Application/applicationcontroller.h3
-rw-r--r--src/modules/Unity/Application/applicationscreenshotprovider.cpp2
-rw-r--r--src/modules/Unity/Application/mirsurfaceitem.cpp10
-rw-r--r--src/modules/Unity/Application/mirsurfaceitem.h92
-rw-r--r--src/modules/Unity/Application/mirsurfaceiteminterface.h116
-rw-r--r--src/modules/Unity/Application/mirsurfaceitemmodel.h4
-rw-r--r--src/modules/Unity/Application/mirsurfacemanager.cpp9
-rw-r--r--src/modules/Unity/Application/mirsurfacemanager.h7
-rw-r--r--src/modules/Unity/Application/plugin.cpp4
-rw-r--r--src/modules/Unity/Application/session.cpp186
-rw-r--r--src/modules/Unity/Application/session.h23
-rw-r--r--src/modules/Unity/Application/session_interface.h54
-rw-r--r--src/modules/Unity/Application/sessionmanager.cpp1
-rw-r--r--src/modules/Unity/Application/taskcontroller.cpp21
-rw-r--r--src/modules/Unity/Application/taskcontroller.h10
-rw-r--r--src/modules/Unity/Application/upstart/applicationcontroller.cpp12
21 files changed, 787 insertions, 553 deletions
diff --git a/src/modules/Unity/Application/CMakeLists.txt b/src/modules/Unity/Application/CMakeLists.txt
index 8c437e6..eaf5478 100644
--- a/src/modules/Unity/Application/CMakeLists.txt
+++ b/src/modules/Unity/Application/CMakeLists.txt
@@ -46,6 +46,7 @@ set(QMLMIRPLUGIN_SRC
${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
# Feed the automoc monster
+ mirsurfaceiteminterface.h
session_interface.h
applicationcontroller.h
settings_interface.h
diff --git a/src/modules/Unity/Application/application.cpp b/src/modules/Unity/Application/application.cpp
index cf37c92..06471f7 100644
--- a/src/modules/Unity/Application/application.cpp
+++ b/src/modules/Unity/Application/application.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 Canonical, Ltd.
+ * Copyright (C) 2013-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -37,25 +37,28 @@ namespace ms = mir::scene;
namespace qtmir
{
-Application::Application(const QSharedPointer<TaskController>& taskController,
- const QSharedPointer<SharedWakelock>& sharedWakelock,
+QStringList Application::lifecycleExceptions;
+
+Application::Application(const QSharedPointer<SharedWakelock>& sharedWakelock,
DesktopFileReader *desktopFileReader,
- State state,
const QStringList &arguments,
ApplicationManager *parent)
: ApplicationInfoInterface(desktopFileReader->appId(), parent)
- , m_taskController(taskController)
, m_sharedWakelock(sharedWakelock)
, m_desktopData(desktopFileReader)
, m_pid(0)
, m_stage((m_desktopData->stageHint() == "SideStage") ? Application::SideStage : Application::MainStage)
- , m_state(state)
+ , m_state(InternalState::Starting)
, m_focused(false)
- , m_canBeResumed(true)
, m_arguments(arguments)
, m_session(nullptr)
+ , m_requestedState(RequestedRunning)
+ , m_processState(ProcessUnknown)
{
- qCDebug(QTMIR_APPLICATIONS) << "Application::Application - appId=" << desktopFileReader->appId() << "state=" << state;
+ qCDebug(QTMIR_APPLICATIONS) << "Application::Application - appId=" << desktopFileReader->appId();
+
+ // Because m_state is InternalState::Starting
+ acquireWakelock();
// FIXME(greyback) need to save long appId internally until ubuntu-app-launch can hide it from us
m_longAppId = desktopFileReader->file().remove(QRegExp(".desktop$")).split('/').last();
@@ -69,10 +72,33 @@ Application::~Application()
{
qCDebug(QTMIR_APPLICATIONS) << "Application::~Application";
+ // (ricmm) -- To be on the safe side, better wipe the application QML compile cache if it crashes on startup
+ if (m_processState == Application::ProcessUnknown
+ || state() == Application::Starting
+ || state() == Application::Running) {
+ wipeQMLCache();
+ }
+
delete m_session;
delete m_desktopData;
}
+
+void Application::wipeQMLCache()
+{
+ QString path(QDir::homePath() + QStringLiteral("/.cache/QML/Apps/"));
+ QDir dir(path);
+ QStringList apps = dir.entryList();
+ for (int i = 0; i < apps.size(); i++) {
+ if (apps.at(i).contains(appId())) {
+ qCDebug(QTMIR_APPLICATIONS) << "Application appId=" << apps.at(i) << " Wiping QML Cache";
+ dir.cd(apps.at(i));
+ dir.removeRecursively();
+ break;
+ }
+ }
+}
+
bool Application::isValid() const
{
return m_desktopData->loaded();
@@ -159,6 +185,30 @@ QColor Application::colorFromString(const QString &colorString, const char *colo
return color;
}
+const char* Application::internalStateToStr(InternalState state)
+{
+ switch (state) {
+ case InternalState::Starting:
+ return "Starting";
+ case InternalState::Running:
+ return "Running";
+ case InternalState::RunningInBackground:
+ return "RunningInBackground";
+ case InternalState::SuspendingWaitSession:
+ return "SuspendingWaitSession";
+ case InternalState::SuspendingWaitProcess:
+ return "SuspendingWaitProcess";
+ case InternalState::Suspended:
+ return "Suspended";
+ case InternalState::StoppedUnexpectedly:
+ return "StoppedUnexpectedly";
+ case InternalState::Stopped:
+ return "Stopped";
+ default:
+ return "???";
+ }
+}
+
bool Application::splashShowHeader() const
{
QString showHeader = m_desktopData->splashShowHeader();
@@ -204,7 +254,104 @@ Application::Stages Application::supportedStages() const
Application::State Application::state() const
{
- return m_state;
+ // The public state is a simplified version of the internal one as our consumers
+ // don't have to know or care about all the nasty details.
+ switch (m_state) {
+ case InternalState::Starting:
+ return Starting;
+ case InternalState::Running:
+ case InternalState::RunningInBackground:
+ case InternalState::SuspendingWaitSession:
+ case InternalState::SuspendingWaitProcess:
+ return Running;
+ case InternalState::Suspended:
+ return Suspended;
+ case InternalState::Stopped:
+ default:
+ return Stopped;
+ }
+}
+
+Application::RequestedState Application::requestedState() const
+{
+ return m_requestedState;
+}
+
+void Application::setRequestedState(RequestedState value)
+{
+ if (m_requestedState == value) {
+ // nothing to do
+ return;
+ }
+
+ qCDebug(QTMIR_APPLICATIONS) << "Application::setRequestedState - appId=" << appId()
+ << "requestedState=" << applicationStateToStr(value);
+ m_requestedState = value;
+ Q_EMIT requestedStateChanged(m_requestedState);
+
+ applyRequestedState();
+}
+
+void Application::applyRequestedState()
+{
+ if (m_requestedState == RequestedRunning) {
+ applyRequestedRunning();
+ } else {
+ applyRequestedSuspended();
+ }
+}
+
+void Application::applyRequestedRunning()
+{
+ switch (m_state) {
+ case InternalState::Starting:
+ // should leave the app alone until it reaches Running state
+ break;
+ case InternalState::Running:
+ // already where it's wanted to be
+ break;
+ case InternalState::RunningInBackground:
+ case InternalState::SuspendingWaitSession:
+ case InternalState::Suspended:
+ resume();
+ break;
+ case InternalState::SuspendingWaitProcess:
+ // should leave the app alone until it reaches Suspended state
+ break;
+ case InternalState::StoppedUnexpectedly:
+ respawn();
+ break;
+ case InternalState::Stopped:
+ // dead end.
+ break;
+ }
+}
+
+void Application::applyRequestedSuspended()
+{
+ switch (m_state) {
+ case InternalState::Starting:
+ // should leave the app alone until it reaches Running state
+ break;
+ case InternalState::Running:
+ if (m_processState == ProcessRunning) {
+ suspend();
+ } else {
+ // we can't suspend it since we have no information on the app process
+ Q_ASSERT(m_processState == ProcessUnknown);
+ }
+ break;
+ case InternalState::RunningInBackground:
+ case InternalState::SuspendingWaitSession:
+ case InternalState::SuspendingWaitProcess:
+ case InternalState::Suspended:
+ // it's already going where we it's wanted
+ break;
+ case InternalState::StoppedUnexpectedly:
+ case InternalState::Stopped:
+ // the app doesn't have a process in the first place, so there's nothing to suspend
+ break;
+ }
}
bool Application::focused() const
@@ -219,12 +366,7 @@ bool Application::fullscreen() const
bool Application::canBeResumed() const
{
- return m_canBeResumed;
-}
-
-void Application::setCanBeResumed(const bool resume)
-{
- m_canBeResumed = resume;
+ return m_processState != ProcessUnknown;
}
pid_t Application::pid() const
@@ -242,7 +384,7 @@ void Application::setArguments(const QStringList arguments)
m_arguments = arguments;
}
-void Application::setSession(Session *newSession)
+void Application::setSession(SessionInterface *newSession)
{
qCDebug(QTMIR_APPLICATIONS) << "Application::setSession - appId=" << appId() << "session=" << newSession;
@@ -261,10 +403,25 @@ void Application::setSession(Session *newSession)
if (m_session) {
m_session->setParent(this);
m_session->setApplication(this);
- m_session->setState(state());
- connect(m_session, &SessionInterface::suspended, this, &Application::onSessionSuspended);
- connect(m_session, &SessionInterface::resumed, this, &Application::onSessionResumed);
+ switch (m_state) {
+ case InternalState::Starting:
+ case InternalState::Running:
+ case InternalState::RunningInBackground:
+ m_session->resume();
+ break;
+ case InternalState::SuspendingWaitSession:
+ case InternalState::SuspendingWaitProcess:
+ case InternalState::Suspended:
+ m_session->suspend();
+ break;
+ case InternalState::Stopped:
+ default:
+ m_session->stop();
+ break;
+ }
+
+ connect(m_session, &SessionInterface::stateChanged, this, &Application::onSessionStateChanged);
connect(m_session, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged);
if (oldFullscreen != fullscreen())
@@ -288,37 +445,53 @@ void Application::setStage(Application::Stage stage)
}
}
-void Application::setState(Application::State state)
+void Application::setInternalState(Application::InternalState state)
{
- qCDebug(QTMIR_APPLICATIONS) << "Application::setState - appId=" << appId() << "state=" << applicationStateToStr(state);
- if (m_state != state) {
- if (session()) {
- session()->setState((Session::State)state);
- } else {
- // If we have have no session, we may have to respawn it.
- switch (state)
- {
- case Session::State::Running:
- if (m_state == Session::State::Stopped) {
- respawn();
- state = Session::State::Starting;
- }
- break;
- default:
- break;
- }
- }
- m_state = state;
- Q_EMIT stateChanged(state);
+ if (m_state == state) {
+ return;
}
+
+ qCDebug(QTMIR_APPLICATIONS) << "Application::setInternalState - appId=" << appId()
+ << "state=" << internalStateToStr(state);
+
+ auto oldPublicState = this->state();
+ m_state = state;
+
+ switch (m_state) {
+ case InternalState::Starting:
+ case InternalState::Running:
+ acquireWakelock();
+ break;
+ case InternalState::RunningInBackground:
+ releaseWakelock();
+ break;
+ case InternalState::Suspended:
+ releaseWakelock();
+ break;
+ case InternalState::StoppedUnexpectedly:
+ releaseWakelock();
+ break;
+ case InternalState::Stopped:
+ Q_EMIT stopped();
+ releaseWakelock();
+ break;
+ case InternalState::SuspendingWaitSession:
+ case InternalState::SuspendingWaitProcess:
+ // transitory states. leave as it is
+ default:
+ break;
+ };
+
+ if (this->state() != oldPublicState) {
+ Q_EMIT stateChanged(this->state());
+ }
+
+ applyRequestedState();
}
void Application::setFocused(bool focused)
{
qCDebug(QTMIR_APPLICATIONS) << "Application::setFocused - appId=" << appId() << "focused=" << focused;
- if (focused) {
- holdWakelock(true);
- }
if (m_focused != focused) {
m_focused = focused;
@@ -326,25 +499,84 @@ void Application::setFocused(bool focused)
}
}
-void Application::onSessionSuspended()
+void Application::setProcessState(ProcessState newProcessState)
{
- qCDebug(QTMIR_APPLICATIONS) << "Application::onSessionSuspended - appId=" << appId();
- m_taskController->suspend(longAppId());
- holdWakelock(false);
+ if (m_processState == newProcessState) {
+ return;
+ }
+
+ m_processState = newProcessState;
+
+ switch (m_processState) {
+ case ProcessUnknown:
+ // it would be a coding error
+ Q_ASSERT(false);
+ break;
+ case ProcessRunning:
+ if (m_state == InternalState::StoppedUnexpectedly) {
+ setInternalState(InternalState::Starting);
+ }
+ break;
+ case ProcessSuspended:
+ Q_ASSERT(m_state == InternalState::SuspendingWaitProcess);
+ setInternalState(InternalState::Suspended);
+ break;
+ case ProcessStopped:
+ // we assume the session always stop before the process
+ Q_ASSERT(!m_session || m_session->state() == Session::Stopped);
+ if (m_state == InternalState::Starting) {
+ setInternalState(InternalState::Stopped);
+ } else {
+ Q_ASSERT(m_state == InternalState::Stopped
+ || m_state == InternalState::StoppedUnexpectedly);
+ }
+ break;
+ }
+
+ applyRequestedState();
}
-void Application::onSessionResumed()
+void Application::suspend()
{
- qCDebug(QTMIR_APPLICATIONS) << "Application::onSessionResumed - appId=" << appId();
- holdWakelock(true);
- m_taskController->resume(longAppId());
+ Q_ASSERT(m_state == InternalState::Running);
+ Q_ASSERT(m_session != nullptr);
+
+ if (!lifecycleExceptions.filter(appId().section('_',0,0)).empty()) {
+ // Present in exceptions list.
+ // There's no need to keep the wakelock as the process is never suspended
+ // and thus has no cleanup to perform when (for example) the display is
+ // blanked.
+ setInternalState(InternalState::RunningInBackground);
+ } else {
+ setInternalState(InternalState::SuspendingWaitSession);
+ m_session->suspend();
+ }
+}
+
+void Application::resume()
+{
+ if (m_state == InternalState::Suspended) {
+ setInternalState(InternalState::Running);
+ Q_EMIT resumeProcessRequested();
+ if (m_processState == ProcessSuspended) {
+ setProcessState(ProcessRunning); // should we wait for a resumed() signal?
+ }
+ m_session->resume();
+ } else if (m_state == InternalState::SuspendingWaitSession) {
+ setInternalState(InternalState::Running);
+ m_session->resume();
+ } else if (m_state == InternalState::RunningInBackground) {
+ setInternalState(InternalState::Running);
+ }
}
void Application::respawn()
{
qCDebug(QTMIR_APPLICATIONS) << "Application::respawn - appId=" << appId();
- holdWakelock(true);
- m_taskController->start(appId(), m_arguments);
+
+ setInternalState(InternalState::Starting);
+
+ Q_EMIT startProcessRequested();
}
QString Application::longAppId() const
@@ -362,20 +594,60 @@ bool Application::rotatesWindowContents() const
return m_rotatesWindowContents;
}
-Session* Application::session() const
+SessionInterface* Application::session() const
{
return m_session;
}
-void Application::holdWakelock(bool enable) const
+void Application::acquireWakelock() const
{
if (appId() == "unity8-dash")
return;
- if (enable) {
- m_sharedWakelock->acquire(this);
- } else {
- m_sharedWakelock->release(this);
+ m_sharedWakelock->acquire(this);
+}
+
+void Application::releaseWakelock() const
+{
+ if (appId() == "unity8-dash")
+ return;
+
+ m_sharedWakelock->release(this);
+}
+
+void Application::onSessionStateChanged(Session::State sessionState)
+{
+ switch (sessionState) {
+ case Session::Starting:
+ break;
+ case Session::Running:
+ if (m_state == InternalState::Starting) {
+ setInternalState(InternalState::Running);
+ }
+ break;
+ case Session::Suspending:
+ break;
+ case Session::Suspended:
+ Q_ASSERT(m_state == InternalState::SuspendingWaitSession);
+ setInternalState(InternalState::SuspendingWaitProcess);
+ Q_EMIT suspendProcessRequested();
+ break;
+ case Session::Stopped:
+ if (!canBeResumed()
+ || m_state == InternalState::Starting
+ || m_state == InternalState::Running) {
+ /* 1. application is not managed by upstart
+ * 2. application is managed by upstart, but has stopped before it managed
+ * to create a surface, we can assume it crashed on startup, and thus
+ * cannot be resumed
+ * 3. application is managed by upstart and is in foreground (i.e. has
+ * Running state), if Mir reports the application disconnects, it
+ * either crashed or stopped itself.
+ */
+ setInternalState(InternalState::Stopped);
+ } else {
+ setInternalState(InternalState::StoppedUnexpectedly);
+ }
}
}
diff --git a/src/modules/Unity/Application/application.h b/src/modules/Unity/Application/application.h
index dff36cd..9344621 100644
--- a/src/modules/Unity/Application/application.h
+++ b/src/modules/Unity/Application/application.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 Canonical, Ltd.
+ * Copyright (C) 2013-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -28,6 +28,8 @@
// Unity API
#include <unity/shell/application/ApplicationInfoInterface.h>
+#include "session_interface.h"
+
namespace mir {
namespace scene {
class Session;
@@ -39,7 +41,6 @@ namespace qtmir
class ApplicationManager;
class DesktopFileReader;
-class TaskController;
class Session;
class SharedWakelock;
@@ -51,15 +52,32 @@ class Application : public unity::shell::application::ApplicationInfoInterface
Q_PROPERTY(QString exec READ exec CONSTANT)
Q_PROPERTY(bool fullscreen READ fullscreen NOTIFY fullscreenChanged)
Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
- Q_PROPERTY(Session* session READ session NOTIFY sessionChanged DESIGNABLE false)
+ Q_PROPERTY(SessionInterface* session READ session NOTIFY sessionChanged DESIGNABLE false)
public:
Q_DECLARE_FLAGS(Stages, Stage)
- Application(const QSharedPointer<TaskController>& taskController,
- const QSharedPointer<SharedWakelock>& sharedWakelock,
+ enum ProcessState {
+ ProcessUnknown,
+ ProcessRunning,
+ ProcessSuspended,
+ ProcessStopped
+ };
+
+ enum class InternalState {
+ Starting,
+ Running,
+ RunningInBackground,
+ SuspendingWaitSession,
+ SuspendingWaitProcess,
+ Suspended,
+ StoppedUnexpectedly,
+ Stopped // It closed itself, crashed or it stopped and we can't respawn it
+ // In any case, this is a dead end.
+ };
+
+ Application(const QSharedPointer<SharedWakelock>& sharedWakelock,
DesktopFileReader *desktopFileReader,
- State state,
const QStringList &arguments,
ApplicationManager *parent);
virtual ~Application();
@@ -71,6 +89,8 @@ public:
QUrl icon() const override;
Stage stage() const override;
State state() const override;
+ RequestedState requestedState() const override;
+ void setRequestedState(RequestedState) override;
bool focused() const override;
QString splashTitle() const override;
QUrl splashImage() const override;
@@ -82,12 +102,16 @@ public:
bool rotatesWindowContents() const override;
void setStage(Stage stage);
- void setState(State state);
- Session* session() const;
+
+ void setProcessState(ProcessState value);
+
+ QStringList arguments() const { return m_arguments; }
+
+ SessionInterface* session() const;
+ void setSession(SessionInterface *session);
bool canBeResumed() const;
- void setCanBeResumed(const bool);
bool isValid() const;
QString desktopFile() const;
@@ -98,40 +122,58 @@ public:
pid_t pid() const;
+ // for tests
+ InternalState internalState() const { return m_state; }
+
+ static QStringList lifecycleExceptions;
+
Q_SIGNALS:
void fullscreenChanged(bool fullscreen);
void stageChanged(Stage stage);
- void sessionChanged(Session *session);
+ void sessionChanged(SessionInterface *session);
+
+ void startProcessRequested();
+ void suspendProcessRequested();
+ void resumeProcessRequested();
+ void stopped();
private Q_SLOTS:
- void onSessionSuspended();
- void onSessionResumed();
+ void onSessionStateChanged(SessionInterface::State sessionState);
void respawn();
private:
+
QString longAppId() const;
- void holdWakelock(bool enable) const;
+ void acquireWakelock() const;
+ void releaseWakelock() const;
void setPid(pid_t pid);
void setArguments(const QStringList arguments);
void setFocused(bool focus);
- void setSession(Session *session);
+ void setInternalState(InternalState state);
+ void wipeQMLCache();
+ void suspend();
+ void resume();
QColor colorFromString(const QString &colorString, const char *colorName) const;
+ static const char* internalStateToStr(InternalState state);
+ void applyRequestedState();
+ void applyRequestedRunning();
+ void applyRequestedSuspended();
- QSharedPointer<TaskController> m_taskController;
QSharedPointer<SharedWakelock> m_sharedWakelock;
DesktopFileReader* m_desktopData;
QString m_longAppId;
qint64 m_pid;
Stage m_stage;
Stages m_supportedStages;
- State m_state;
+ InternalState m_state;
bool m_focused;
- bool m_canBeResumed;
QStringList m_arguments;
Qt::ScreenOrientations m_supportedOrientations;
bool m_rotatesWindowContents;
- Session *m_session;
+ SessionInterface *m_session;
+ RequestedState m_requestedState;
+ ProcessState m_processState;
friend class ApplicationManager;
friend class SessionManager;
diff --git a/src/modules/Unity/Application/application_manager.cpp b/src/modules/Unity/Application/application_manager.cpp
index ea316e7..0624552 100644
--- a/src/modules/Unity/Application/application_manager.cpp
+++ b/src/modules/Unity/Application/application_manager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013,2014 Canonical, Ltd.
+ * Copyright (C) 2013-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -96,11 +96,13 @@ void connectToTaskController(ApplicationManager *manager, TaskController *contro
manager, &ApplicationManager::onProcessStarting);
QObject::connect(controller, &TaskController::processStopped,
manager, &ApplicationManager::onProcessStopped);
+ QObject::connect(controller, &TaskController::processSuspended,
+ manager, &ApplicationManager::onProcessSuspended);
QObject::connect(controller, &TaskController::processFailed,
manager, &ApplicationManager::onProcessFailed);
- QObject::connect(controller, &TaskController::requestFocus,
+ QObject::connect(controller, &TaskController::focusRequested,
manager, &ApplicationManager::onFocusRequested);
- QObject::connect(controller, &TaskController::requestResume,
+ QObject::connect(controller, &TaskController::resumeRequested,
manager, &ApplicationManager::onResumeRequested);
}
@@ -180,16 +182,12 @@ ApplicationManager::ApplicationManager(
: ApplicationManagerInterface(parent)
, m_mirServer(mirServer)
, m_focusedApplication(nullptr)
- , m_mainStageApplication(nullptr)
- , m_sideStageApplication(nullptr)
, m_dbusWindowStack(new DBusWindowStack(this))
, m_taskController(taskController)
, m_desktopFileReaderFactory(desktopFileReaderFactory)
, m_procInfo(procInfo)
, m_sharedWakelock(sharedWakelock)
, m_settings(settings)
- , m_suspended(false)
- , m_forceDashActive(false)
{
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::ApplicationManager (this=%p)" << this;
setObjectName("qtmir::ApplicationManager");
@@ -198,7 +196,7 @@ ApplicationManager::ApplicationManager(
m_roleNames.insert(RoleFullscreen, "fullscreen");
if (settings.data()) {
- m_lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList();
+ Application::lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList();
connect(m_settings.data(), &Settings::changed, this, &ApplicationManager::onSettingsChanged);
}
}
@@ -289,98 +287,6 @@ QString ApplicationManager::focusedApplicationId() const
}
}
-bool ApplicationManager::suspended() const
-{
- return m_suspended;
-}
-
-void ApplicationManager::setSuspended(bool suspended)
-{
- if (suspended == m_suspended) {
- return;
- }
- m_suspended = suspended;
- Q_EMIT suspendedChanged();
-
- if (m_suspended) {
- suspendApplication(m_mainStageApplication);
- suspendApplication(m_sideStageApplication);
- if (m_focusedApplication) {
- m_focusedApplication->setFocused(false);
- m_dbusWindowStack->FocusedWindowChanged(0, QString(), 0);
- }
- } else {
- resumeApplication(m_mainStageApplication);
- resumeApplication(m_sideStageApplication);
- if (m_focusedApplication) {
- m_focusedApplication->setFocused(true);
- m_dbusWindowStack->FocusedWindowChanged(0, m_focusedApplication->appId(), m_focusedApplication->stage());
- }
- }
-}
-
-bool ApplicationManager::forceDashActive() const
-{
- return m_forceDashActive;
-}
-
-void ApplicationManager::setForceDashActive(bool forceDashActive)
-{
- if (m_forceDashActive == forceDashActive) {
- return;
- }
-
- m_forceDashActive = forceDashActive;
- Q_EMIT forceDashActiveChanged();
-
- Application *dashApp = findApplication("unity8-dash");
- if (!dashApp) {
- qCWarning(QTMIR_APPLICATIONS) << "Dash doesn't seem to be running... Ignoring.";
- return;
- }
-
- if (m_forceDashActive && dashApp->state() != Application::Running) {
- resumeApplication(dashApp);
- } else if (!m_forceDashActive && dashApp->state() == Application::Running
- && m_mainStageApplication != dashApp
- && m_sideStageApplication != dashApp) {
- suspendApplication(dashApp);
- }
-}
-
-bool ApplicationManager::suspendApplication(Application *application)
-{
- if (application == nullptr)
- return false;
- qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::suspendApplication - appId=" << application->appId();
-
- // Present in exceptions list, explicitly release wakelock and return. There's no need to keep the wakelock
- // as the process is never suspended and thus has no cleanup to perform when (for example) the display is blanked
- if (!m_lifecycleExceptions.filter(application->appId().section('_',0,0)).empty()) {
- m_sharedWakelock->release(application);
- return false;
- }
-
- if (m_forceDashActive && application->appId() == "unity8-dash") {
- return false;
- }
-
- if (application->state() == Application::Running)
- application->setState(Application::Suspended);
-
- return true;
-}
-
-void ApplicationManager::resumeApplication(Application *application)
-{
- if (application == nullptr)
- return;
- qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::resumeApplication - appId=" << application->appId();
-
- if (application->state() == Application::Suspended || application->state() == Application::Stopped)
- application->setState(Application::Running);
-}
-
bool ApplicationManager::focusApplication(const QString &inputAppId)
{
const QString appId = toShortAppIdIfPossible(inputAppId);
@@ -392,27 +298,8 @@ bool ApplicationManager::focusApplication(const QString &inputAppId)
return false;
}
- resumeApplication(application);
-
- // set state of previously focused app to suspended
if (m_focusedApplication) {
m_focusedApplication->setFocused(false);
- Application *lastApplication = applicationForStage(application->stage());
- if (lastApplication != application) {
- suspendApplication(lastApplication);
- }
- }
-
- if (application->stage() == Application::MainStage) {
- m_mainStageApplication = application;
- } else {
- m_sideStageApplication = application;
- }
-
- if (!m_suspended) {
- resumeApplication(application); // in case unfocusCurrentApplication() was last called
- } else {
- suspendApplication(application); // Make sure we also have this one suspended if everything is suspended
}
m_focusedApplication = application;
@@ -422,9 +309,6 @@ bool ApplicationManager::focusApplication(const QString &inputAppId)
Q_EMIT focusedApplicationIdChanged();
m_dbusWindowStack->FocusedWindowChanged(0, application->appId(), application->stage());
- // FIXME(dandrader): lying here. The operation is async. So we will only know whether
- // the focusing was successful once the server replies. Maybe the API in unity-api should
- // reflect that?
return true;
}
@@ -432,9 +316,6 @@ void ApplicationManager::unfocusCurrentApplication()
{
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::unfocusCurrentApplication";
- suspendApplication(m_sideStageApplication);
- suspendApplication(m_mainStageApplication);
-
m_focusedApplication = nullptr;
Q_EMIT focusedApplicationIdChanged();
}
@@ -484,10 +365,8 @@ Application *ApplicationManager::startApplication(const QString &inputAppId, Exe
application->setArguments(arguments);
} else {
application = new Application(
- m_taskController,
m_sharedWakelock,
m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)),
- Application::Starting,
arguments,
this);
@@ -514,10 +393,8 @@ void ApplicationManager::onProcessStarting(const QString &appId)
Application *application = findApplication(appId);
if (!application) { // then shell did not start this application, so ubuntu-app-launch must have - add to list
application = new Application(
- m_taskController,
m_sharedWakelock,
m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)),
- Application::Starting,
QStringList(),
this);
@@ -530,17 +407,17 @@ void ApplicationManager::onProcessStarting(const QString &appId)
Q_EMIT focusRequested(appId);
}
else {
- // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned
- // application and focus it immediately (as user expects app to still be running).
if (application->state() == Application::Stopped) {
+ // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned
+ // application and focus it immediately (as user expects app to still be running).
qCDebug(QTMIR_APPLICATIONS) << "Stopped application appId=" << appId << "is being resumed externally";
- application->setState(Application::Starting);
Q_EMIT focusRequested(appId);
} else {
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting application already found with appId"
<< appId;
}
}
+ application->setProcessState(Application::ProcessRunning);
}
/**
@@ -559,14 +436,7 @@ bool ApplicationManager::stopApplication(const QString &inputAppId)
return false;
}
- if (application == m_focusedApplication) {
- // unfocus, and let shell decide what next to focus
- m_focusedApplication = nullptr;
- Q_EMIT focusedApplicationIdChanged();
- }
-
remove(application);
- m_dbusWindowStack->WindowDestroyed(0, appId);
bool result = m_taskController->stop(application->longAppId());
@@ -583,10 +453,7 @@ bool ApplicationManager::stopApplication(const QString &inputAppId)
void ApplicationManager::onProcessFailed(const QString &appId, const bool duringStartup)
{
- /* Applications fail if they fail to launch, crash or are killed. If failed to start, must
- * immediately remove from list of applications. If crash or kill, instead we set flag on the
- * Application to indicate it can be resumed.
- */
+ // Applications fail if they fail to launch, crash or are killed.
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessFailed - appId=" << appId << "duringStartup=" << duringStartup;
@@ -598,20 +465,8 @@ void ApplicationManager::onProcessFailed(const QString &appId, const bool during
}
Q_UNUSED(duringStartup); // FIXME(greyback) upstart reports app that fully started up & crashes as failing during startup??
- if (application->state() == Application::Starting) {
- if (application == m_focusedApplication) {
- m_focusedApplication = nullptr;
- Q_EMIT focusedApplicationIdChanged();
- }
- remove(application);
- m_dbusWindowStack->WindowDestroyed(0, application->appId());
- delete application;
- } else {
- // We need to set flags on the Application to say the app can be resumed, and thus should not be removed
- // from the list by onProcessStopped.
- application->setCanBeResumed(true);
- application->setPid(0);
- }
+ application->setProcessState(Application::ProcessStopped);
+ application->setPid(0);
}
void ApplicationManager::onProcessStopped(const QString &appId)
@@ -626,29 +481,15 @@ void ApplicationManager::onProcessStopped(const QString &appId)
return;
}
- // if shell did not stop the application, but ubuntu-app-launch says it died, we assume the process has been
- // killed, so it can be respawned later. Only exception is if that application is focused or running
- // as then it most likely crashed. Update this logic when ubuntu-app-launch gives some failure info.
- bool removeApplication = true;
-
- if (application == m_focusedApplication) {
- // Very bad case where focused application dies. Remove from list. Should give error message
- m_focusedApplication = nullptr;
- Q_EMIT focusedApplicationIdChanged();
- }
-
- // The following scenario is the only time that we do NOT remove the application from the app list:
- if ((application->state() == Application::Suspended || application->state() == Application::Stopped)
- && application->pid() == 0 // i.e. onProcessFailed was called, which resets the PID of this application
- && application->canBeResumed()) {
- removeApplication = false;
- }
+ application->setProcessState(Application::ProcessStopped);
+ application->setPid(0);
+}
- if (removeApplication) {
- qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - removing appId=" << appId;
- remove(application);
- m_dbusWindowStack->WindowDestroyed(0, application->appId());
- delete application;
+void ApplicationManager::onProcessSuspended(const QString &appId)
+{
+ Application *application = findApplication(appId);
+ if (application) {
+ application->setProcessState(Application::ProcessSuspended);
}
}
@@ -670,10 +511,10 @@ void ApplicationManager::onResumeRequested(const QString& appId)
return;
}
- // If app Stopped, trust that ubuntu-app-launch respawns it itself, and AppManager will
- // be notified of that through the onProcessStartReportReceived slot. Else resume.
+ // We interpret this as a focus request for a suspended app.
+ // Shell will have this app resumed if it complies with the focus request
if (application->state() == Application::Suspended) {
- application->setState(Application::Running);
+ Q_EMIT focusRequested(appId);
}
}
@@ -693,7 +534,7 @@ void ApplicationManager::onAppDataChanged(const int role)
void ApplicationManager::onSettingsChanged(const QString &key)
{
if (key == "lifecycleExemptAppids") {
- m_lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList();
+ Application::lifecycleExceptions = m_settings->get("lifecycleExemptAppids").toStringList();
}
}
@@ -732,7 +573,6 @@ void ApplicationManager::authorizeSession(const quint64 pid, bool &authorized)
if (info->startsWith("maliit-server") || info->contains("qt5/libexec/QtWebProcess")) {
authorized = true;
- m_hiddenPIDs << pid;
return;
}
@@ -792,15 +632,12 @@ void ApplicationManager::authorizeSession(const quint64 pid, bool &authorized)
QStringList arguments(info->asStringList());
application = new Application(
- m_taskController,
m_sharedWakelock,
desktopData,
- Application::Starting,
arguments,
this);
application->setPid(pid);
application->setStage(stage);
- application->setCanBeResumed(false);
add(application);
authorized = true;
}
@@ -812,51 +649,10 @@ void ApplicationManager::onSessionStarting(std::shared_ptr<ms::Session> const& s
void ApplicationManager::onSessionStopping(std::shared_ptr<ms::Session> const& session)
{
- qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionStopping - sessionName=" << session->name().c_str();
-
- // in case application closed not by hand of shell, check again here:
Application* application = findApplicationWithSession(session);
if (application) {
- /* Can remove the application from the running apps list immediately in these curcumstances:
- * 1. application is not managed by upstart (this message from Mir is only notice the app has stopped, must do
- * it here)
- * 2. application is managed by upstart, but has stopped before it managed to create a surface, we can assume
- * it crashed on startup, and thus cannot be resumed - so remove it.
- * 3. application is managed by upstart and is in foreground (i.e. has Running state), if Mir reports the
- * application disconnects, it either crashed or stopped itself. Either case, remove it.
- */
- if (!application->canBeResumed()
- || application->state() == Application::Starting
- || application->state() == Application::Running) {
- m_dbusWindowStack->WindowDestroyed(0, application->appId());
- remove(application);
-
- // (ricmm) -- To be on the safe side, better wipe the application QML compile cache if it crashes on startup
- QString path(QDir::homePath() + QStringLiteral("/.cache/QML/Apps/"));
- QDir dir(path);
- QStringList apps = dir.entryList();
- for (int i = 0; i < apps.size(); i++) {
- if (apps.at(i).contains(application->appId())) {
- qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionStopping appId=" << apps.at(i) << " Wiping QML Cache";
- dir.cd(apps.at(i));
- dir.removeRecursively();
- break;
- }
- }
-
- delete application;
-
- if (application == m_focusedApplication) {
- m_focusedApplication = nullptr;
- Q_EMIT focusedApplicationIdChanged();
- }
- } else {
- // otherwise, we do not have enough information to make any changes to the model, so await events from
- // upstart to go further, but set the app state
- application->setState(Application::Stopped);
- }
+ m_dbusWindowStack->WindowDestroyed(0, application->appId());
}
- m_hiddenPIDs.removeOne(session->process_id());
}
void ApplicationManager::onSessionCreatedSurface(ms::Session const* session,
@@ -866,12 +662,8 @@ void ApplicationManager::onSessionCreatedSurface(ms::Session const* session,
Q_UNUSED(surface);
Application* application = findApplicationWithSession(session);
- if (application && application->state() == Application::Starting) {
+ if (application) {
m_dbusWindowStack->WindowCreated(0, application->appId());
- application->setState(Application::Running);
- if ((application != m_mainStageApplication && application != m_sideStageApplication) || m_suspended) {
- suspendApplication(application);
- }
}
}
@@ -900,16 +692,6 @@ Application* ApplicationManager::findApplicationWithPid(const qint64 pid)
return nullptr;
}
-Application* ApplicationManager::applicationForStage(Application::Stage stage)
-{
- qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::focusedApplicationForStage" << stage;
-
- if (stage == Application::MainStage)
- return m_mainStageApplication;
- else
- return m_sideStageApplication;
-}
-
void ApplicationManager::add(Application* application)
{
Q_ASSERT(application != nullptr);
@@ -920,6 +702,28 @@ void ApplicationManager::add(Application* application)
connect(application, &Application::stateChanged, this, [this](Application::State) { onAppDataChanged(RoleState); });
connect(application, &Application::stageChanged, this, [this](Application::Stage) { onAppDataChanged(RoleStage); });
+ QString appId = application->appId();
+ QString longAppId = application->longAppId();
+ QStringList arguments = application->arguments();
+
+ // The connection is queued as a workaround an issue in the PhoneStage animation that
+ // happens when you tap on a killed app in the spread to bring it to foreground, causing
+ // a Application::respawn() to take place.
+ // In any case, it seems like in general QML works better when don't do too many things
+ // in the same event loop iteration.
+ connect(application, &Application::startProcessRequested,
+ this, [=]() { m_taskController->start(appId, arguments); },
+ Qt::QueuedConnection);
+
+ connect(application, &Application::suspendProcessRequested, this, [=]() { m_taskController->suspend(longAppId); } );
+ connect(application, &Application::resumeProcessRequested, this, [=]() { m_taskController->resume(longAppId); } );
+
+ connect(application, &Application::stopped, this, [=]() {
+ remove(application);
+ application->deleteLater();
+ });
+
+
beginInsertRows(QModelIndex(), m_applications.count(), m_applications.count());
m_applications.append(application);
endInsertRows();
@@ -935,11 +739,6 @@ void ApplicationManager::remove(Application *application)
Q_ASSERT(application != nullptr);
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::remove - appId=" << application->appId();
- if (application == m_sideStageApplication)
- m_sideStageApplication = nullptr;
- if (application == m_mainStageApplication)
- m_mainStageApplication = nullptr;
-
application->disconnect(this);
int i = m_applications.indexOf(application);
@@ -953,6 +752,11 @@ void ApplicationManager::remove(Application *application)
Q_EMIT emptyChanged();
}
}
+
+ if (application == m_focusedApplication) {
+ m_focusedApplication = nullptr;
+ Q_EMIT focusedApplicationIdChanged();
+ }
}
void ApplicationManager::move(int from, int to) {
diff --git a/src/modules/Unity/Application/application_manager.h b/src/modules/Unity/Application/application_manager.h
index 77ee097..46cfa26 100644
--- a/src/modules/Unity/Application/application_manager.h
+++ b/src/modules/Unity/Application/application_manager.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Canonical, Ltd.
+ * Copyright (C) 2013-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -93,10 +93,6 @@ public:
// ApplicationManagerInterface
QString focusedApplicationId() const override;
- bool suspended() const override;
- void setSuspended(bool suspended) override;
- bool forceDashActive() const override;
- void setForceDashActive(bool forceDashActive) override;
Q_INVOKABLE qtmir::Application* get(int index) const override;
Q_INVOKABLE qtmir::Application* findApplication(const QString &appId) const override;
Q_INVOKABLE bool requestFocusApplication(const QString &appId) override;
@@ -128,6 +124,7 @@ public Q_SLOTS:
void onProcessStarting(const QString& appId);
void onProcessStopped(const QString& appId);
+ void onProcessSuspended(const QString& appId);
void onProcessFailed(const QString& appId, const bool duringStartup);
void onFocusRequested(const QString& appId);
void onResumeRequested(const QString& appId);
@@ -146,9 +143,7 @@ private:
void remove(Application* application);
Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session);
Application* findApplicationWithSession(const mir::scene::Session *session);
- Application* applicationForStage(Application::Stage stage);
QModelIndex findIndex(Application* application);
- bool suspendApplication(Application *application);
void resumeApplication(Application *application);
QString toString() const;
@@ -158,9 +153,6 @@ private:
QList<Application*> m_applications;
Application* m_focusedApplication;
- Application* m_mainStageApplication;
- Application* m_sideStageApplication;
- QStringList m_lifecycleExceptions;
DBusWindowStack* m_dbusWindowStack;
QSharedPointer<TaskController> m_taskController;
QSharedPointer<DesktopFileReader::Factory> m_desktopFileReaderFactory;
@@ -168,9 +160,6 @@ private:
QSharedPointer<SharedWakelock> m_sharedWakelock;
QSharedPointer<SettingsInterface> m_settings;
static ApplicationManager* the_application_manager;
- QList<pid_t> m_hiddenPIDs;
- bool m_suspended;
- bool m_forceDashActive;
friend class Application;
friend class DBusWindowStack;
diff --git a/src/modules/Unity/Application/applicationcontroller.h b/src/modules/Unity/Application/applicationcontroller.h
index 795ac3a..5046efc 100644
--- a/src/modules/Unity/Application/applicationcontroller.h
+++ b/src/modules/Unity/Application/applicationcontroller.h
@@ -57,8 +57,9 @@ Q_SIGNALS:
void applicationAboutToBeStarted(const QString &appId);
void applicationStarted(const QString &appId);
void applicationStopped(const QString &appId);
+ void applicationPaused(const QString &appId);
void applicationFocusRequest(const QString &appId);
- void applicationResumeRequest(const QString &appId);
+ void applicationResumeRequested(const QString &appId);
void applicationError(const QString &appId, ApplicationController::Error error);
diff --git a/src/modules/Unity/Application/applicationscreenshotprovider.cpp b/src/modules/Unity/Application/applicationscreenshotprovider.cpp
index c003f14..d782c33 100644
--- a/src/modules/Unity/Application/applicationscreenshotprovider.cpp
+++ b/src/modules/Unity/Application/applicationscreenshotprovider.cpp
@@ -55,7 +55,7 @@ QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize
// TODO: if app not ready, return an app-provided splash image. If app has been stopped with saved state
// return the screenshot that was saved to disk.
- Session* session = app->session();
+ SessionInterface* session = app->session();
if (!session || !session->session() || !session->session()->default_surface()) {
qWarning() << "ApplicationScreenshotProvider - app session not found - asking for screenshot too early";
return QImage();
diff --git a/src/modules/Unity/Application/mirsurfaceitem.cpp b/src/modules/Unity/Application/mirsurfaceitem.cpp
index 37337a4..53331e4 100644
--- a/src/modules/Unity/Application/mirsurfaceitem.cpp
+++ b/src/modules/Unity/Application/mirsurfaceitem.cpp
@@ -23,7 +23,6 @@
#include "mirbuffersgtexture.h"
#include "session.h"
#include "mirsurfaceitem.h"
-#include "mirshell.h"
#include "logging.h"
#include "ubuntukeyboardinfo.h"
@@ -47,6 +46,7 @@
#include <mir/geometry/rectangle.h>
#include <mir/events/event_builders.h>
#include <mir_toolkit/event.h>
+#include <mir/shell/shell.h>
namespace mg = mir::graphics;
@@ -190,7 +190,7 @@ MirSurfaceItem::MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface,
MirShell *shell,
std::shared_ptr<SurfaceObserver> observer,
QQuickItem *parent)
- : QQuickItem(parent)
+ : MirSurfaceItemInterface(parent)
, m_surface(surface)
, m_session(session)
, m_shell(shell)
@@ -375,7 +375,7 @@ void MirSurfaceItem::surfaceDamaged()
{
if (!m_firstFrameDrawn) {
m_firstFrameDrawn = true;
- Q_EMIT firstFrameDrawn(this);
+ Q_EMIT firstFrameDrawn();
}
scheduleTextureUpdate();
@@ -561,7 +561,7 @@ void MirSurfaceItem::endCurrentTouchSequence(ulong timestamp)
touchEvent.updateTouchPointStatesAndType();
- auto ev = makeMirEvent(touchEvent.modifiers, touchEvent.touchPoints,
+ auto ev = makeMirEvent(touchEvent.modifiers, touchEvent.touchPoints,
touchEvent.touchPointStates, touchEvent.timestamp);
m_surface->consume(*ev);
@@ -672,7 +672,7 @@ void MirSurfaceItem::setState(const State &state)
}
}
-void MirSurfaceItem::setLive(const bool live)
+void MirSurfaceItem::setLive(bool live)
{
if (m_live != live) {
m_live = live;
diff --git a/src/modules/Unity/Application/mirsurfaceitem.h b/src/modules/Unity/Application/mirsurfaceitem.h
index fd3ab45..952d3cd 100644
--- a/src/modules/Unity/Application/mirsurfaceitem.h
+++ b/src/modules/Unity/Application/mirsurfaceitem.h
@@ -22,8 +22,6 @@
// Qt
#include <QMutex>
#include <QPointer>
-#include <QSet>
-#include <QQuickItem>
#include <QTimer>
#include <QQmlListProperty>
@@ -31,34 +29,23 @@
#include <mir/scene/surface.h>
#include <mir_toolkit/common.h>
+#include "mirsurfaceiteminterface.h"
#include "session_interface.h"
+namespace mir { namespace shell { class Shell; }}
+
class SurfaceObserver;
-class MirShell;
+using MirShell = mir::shell::Shell;
namespace qtmir {
class MirSurfaceManager;
class QSGMirSurfaceNode;
class QMirSurfaceTextureProvider;
-class Application;
-class MirSurfaceItem : public QQuickItem
+class MirSurfaceItem : public MirSurfaceItemInterface
{
Q_OBJECT
- Q_ENUMS(Type)
- Q_ENUMS(State)
- Q_ENUMS(OrientationAngle)
-
- Q_PROPERTY(Type type READ type NOTIFY typeChanged)
- Q_PROPERTY(State state READ state NOTIFY stateChanged)
- Q_PROPERTY(QString name READ name NOTIFY nameChanged)
- Q_PROPERTY(bool live READ live NOTIFY liveChanged)
-
- // How many degrees, clockwise, the UI in the surface has to rotate to match with the
- // shell UI orientation
- Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle
- NOTIFY orientationAngleChanged DESIGNABLE false)
public:
explicit MirSurfaceItem(std::shared_ptr<mir::scene::Surface> surface,
@@ -66,57 +53,29 @@ public:
MirShell *shell,
std::shared_ptr<SurfaceObserver> observer,
QQuickItem *parent = 0);
- ~MirSurfaceItem();
-
- enum Type {
- Normal = mir_surface_type_normal,
- Utility = mir_surface_type_utility,
- Dialog = mir_surface_type_dialog,
- Overlay = mir_surface_type_overlay,
- Freestyle = mir_surface_type_freestyle,
- Popover = mir_surface_type_popover,
- InputMethod = mir_surface_type_inputmethod,
- };
-
- enum State {
- Unknown = mir_surface_state_unknown,
- Restored = mir_surface_state_restored,
- Minimized = mir_surface_state_minimized,
- Maximized = mir_surface_state_maximized,
- VertMaximized = mir_surface_state_vertmaximized,
- /* SemiMaximized = mir_surface_state_semimaximized, // see mircommon/mir_toolbox/common.h*/
- Fullscreen = mir_surface_state_fullscreen,
- };
-
- enum OrientationAngle {
- Angle0 = 0,
- Angle90 = 90,
- Angle180 = 180,
- Angle270 = 270
- };
+ virtual ~MirSurfaceItem();
//getters
- Type type() const;
- State state() const;
- QString name() const;
- bool live() const;
- SessionInterface *session() const;
+ Type type() const override;
+ State state() const override;
+ QString name() const override;
+ bool live() const override;
+ SessionInterface *session() const override;
+ OrientationAngle orientationAngle() const override;
- Q_INVOKABLE void release();
+ Q_INVOKABLE void release() override;
// Item surface/texture management
bool isTextureProvider() const { return true; }
QSGTextureProvider *textureProvider() const;
- void stopFrameDropper();
- void startFrameDropper();
-
- bool isFirstFrameDrawn() const { return m_firstFrameDrawn; }
+ void stopFrameDropper() override;
+ void startFrameDropper() override;
- OrientationAngle orientationAngle() const;
- void setOrientationAngle(OrientationAngle angle);
+ bool isFirstFrameDrawn() const override { return m_firstFrameDrawn; }
- void setSession(SessionInterface *app);
+ void setOrientationAngle(OrientationAngle angle) override;
+ void setSession(SessionInterface *app) override;
// to allow easy touch event injection from tests
bool processTouchEvent(int eventType,
@@ -125,14 +84,6 @@ public:
const QList<QTouchEvent::TouchPoint> &touchPoints,
Qt::TouchPointStates touchPointStates);
-Q_SIGNALS:
- void typeChanged();
- void stateChanged();
- void nameChanged();
- void orientationAngleChanged(OrientationAngle angle);
- void liveChanged(bool live);
- void firstFrameDrawn(MirSurfaceItem *item);
-
protected Q_SLOTS:
void onSessionStateChanged(SessionInterface::State state);
@@ -169,7 +120,7 @@ private:
void setType(const Type&);
void setState(const State&);
- void setLive(const bool);
+ void setLive(bool) override;
// called by MirSurfaceManager
void setSurfaceValid(const bool);
@@ -226,13 +177,8 @@ private:
QList<QTouchEvent::TouchPoint> touchPoints;
Qt::TouchPointStates touchPointStates;
} *m_lastTouchEvent;
-
- friend class MirSurfaceManager;
};
} // namespace qtmir
-Q_DECLARE_METATYPE(qtmir::MirSurfaceItem*)
-Q_DECLARE_METATYPE(qtmir::MirSurfaceItem::OrientationAngle)
-
#endif // MIRSURFACEITEM_H
diff --git a/src/modules/Unity/Application/mirsurfaceiteminterface.h b/src/modules/Unity/Application/mirsurfaceiteminterface.h
new file mode 100644
index 0000000..b197cf4
--- /dev/null
+++ b/src/modules/Unity/Application/mirsurfaceiteminterface.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License version 3, as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MIRSURFACEITEMINTERFACE_H
+#define MIRSURFACEITEMINTERFACE_H
+
+// Qt
+#include <QQuickItem>
+
+// mir
+#include <mir_toolkit/common.h>
+
+#include "session_interface.h"
+
+namespace qtmir {
+
+class MirSurfaceItemInterface : public QQuickItem
+{
+ Q_OBJECT
+ Q_ENUMS(Type)
+ Q_ENUMS(State)
+ Q_ENUMS(OrientationAngle)
+
+ Q_PROPERTY(Type type READ type NOTIFY typeChanged)
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged)
+ Q_PROPERTY(bool live READ live NOTIFY liveChanged)
+
+ // How many degrees, clockwise, the UI in the surface has to rotate to match with the
+ // shell UI orientation
+ Q_PROPERTY(OrientationAngle orientationAngle READ orientationAngle WRITE setOrientationAngle
+ NOTIFY orientationAngleChanged DESIGNABLE false)
+
+public:
+ MirSurfaceItemInterface(QQuickItem *parent) : QQuickItem(parent) {}
+ virtual ~MirSurfaceItemInterface() {}
+
+ enum Type {
+ Normal = mir_surface_type_normal,
+ Utility = mir_surface_type_utility,
+ Dialog = mir_surface_type_dialog,
+ Overlay = mir_surface_type_overlay,
+ Freestyle = mir_surface_type_freestyle,
+ Popover = mir_surface_type_popover,
+ InputMethod = mir_surface_type_inputmethod,
+ };
+
+ enum State {
+ Unknown = mir_surface_state_unknown,
+ Restored = mir_surface_state_restored,
+ Minimized = mir_surface_state_minimized,
+ Maximized = mir_surface_state_maximized,
+ VertMaximized = mir_surface_state_vertmaximized,
+ /* SemiMaximized = mir_surface_state_semimaximized, // see mircommon/mir_toolbox/common.h*/
+ Fullscreen = mir_surface_state_fullscreen,
+ };
+
+ enum OrientationAngle {
+ Angle0 = 0,
+ Angle90 = 90,
+ Angle180 = 180,
+ Angle270 = 270
+ };
+
+ //getters
+ virtual Type type() const = 0;
+ virtual State state() const = 0;
+ virtual QString name() const = 0;
+ virtual bool live() const = 0;
+ virtual SessionInterface *session() const = 0;
+ virtual OrientationAngle orientationAngle() const = 0;
+
+ virtual Q_INVOKABLE void release() = 0;
+
+ virtual void stopFrameDropper() = 0;
+ virtual void startFrameDropper() = 0;
+
+ virtual bool isFirstFrameDrawn() const = 0;
+
+ virtual void setOrientationAngle(OrientationAngle angle) = 0;
+ virtual void setSession(SessionInterface *app) = 0;
+
+Q_SIGNALS:
+ void typeChanged();
+ void stateChanged();
+ void nameChanged();
+ void orientationAngleChanged(OrientationAngle angle);
+ void liveChanged(bool live);
+ void firstFrameDrawn();
+
+private:
+ virtual void setLive(bool) = 0;
+
+ friend class MirSurfaceManager;
+};
+
+} // namespace qtmir
+
+Q_DECLARE_METATYPE(qtmir::MirSurfaceItemInterface*)
+Q_DECLARE_METATYPE(qtmir::MirSurfaceItemInterface::OrientationAngle)
+
+#endif // MIRSURFACEITEMINTERFACE_H
+
diff --git a/src/modules/Unity/Application/mirsurfaceitemmodel.h b/src/modules/Unity/Application/mirsurfaceitemmodel.h
index 2d81c11..d0d09f4 100644
--- a/src/modules/Unity/Application/mirsurfaceitemmodel.h
+++ b/src/modules/Unity/Application/mirsurfaceitemmodel.h
@@ -22,8 +22,8 @@
namespace qtmir {
-class MirSurfaceItem;
-typedef ObjectListModel<MirSurfaceItem> MirSurfaceItemModel;
+class MirSurfaceItemInterface;
+typedef ObjectListModel<MirSurfaceItemInterface> MirSurfaceItemModel;
} // namespace qtmir
diff --git a/src/modules/Unity/Application/mirsurfacemanager.cpp b/src/modules/Unity/Application/mirsurfacemanager.cpp
index 183c3a5..9b32363 100644
--- a/src/modules/Unity/Application/mirsurfacemanager.cpp
+++ b/src/modules/Unity/Application/mirsurfacemanager.cpp
@@ -31,7 +31,6 @@
#include "nativeinterface.h"
#include "mirserver.h"
#include "sessionlistener.h"
-#include "mirshell.h"
#include "logging.h"
Q_LOGGING_CATEGORY(QTMIR_SURFACES, "qtmir.surfaces")
@@ -112,11 +111,11 @@ void MirSurfaceManager::onSessionCreatedSurface(const mir::scene::Session *mirSe
session->setSurface(qmlSurface);
// Only notify QML of surface creation once it has drawn its first frame.
- connect(qmlSurface, &MirSurfaceItem::firstFrameDrawn, this, [&](MirSurfaceItem *item) {
+ connect(qmlSurface, &MirSurfaceItemInterface::firstFrameDrawn, this, [=]() {
tracepoint(qtmir, firstFrameDrawn);
- Q_EMIT surfaceCreated(item);
+ Q_EMIT surfaceCreated(qmlSurface);
- insert(0, item);
+ insert(0, qmlSurface);
});
// clean up after MirSurfaceItem is destroyed
@@ -139,7 +138,7 @@ void MirSurfaceManager::onSessionDestroyingSurface(const mir::scene::Session *se
qCDebug(QTMIR_SURFACES) << "MirSurfaceManager::onSessionDestroyingSurface - session=" << session
<< "surface=" << surface.get() << "surface.name=" << surface->name().c_str();
- MirSurfaceItem* item = nullptr;
+ MirSurfaceItemInterface* item = nullptr;
{
QMutexLocker lock(&m_mutex);
auto it = m_mirSurfaceToItemHash.find(surface.get());
diff --git a/src/modules/Unity/Application/mirsurfacemanager.h b/src/modules/Unity/Application/mirsurfacemanager.h
index b9e5533..83ede11 100644
--- a/src/modules/Unity/Application/mirsurfacemanager.h
+++ b/src/modules/Unity/Application/mirsurfacemanager.h
@@ -40,7 +40,6 @@ namespace mir {
}
class MirServer;
-class MirShell;
namespace qtmir {
@@ -64,8 +63,8 @@ public:
static MirSurfaceManager* singleton();
Q_SIGNALS:
- void surfaceCreated(MirSurfaceItem* surface);
- void surfaceDestroyed(MirSurfaceItem* surface);
+ void surfaceCreated(MirSurfaceItemInterface* surface);
+ void surfaceDestroyed(MirSurfaceItemInterface* surface);
// void surfaceResized(MirSurface*);
// void fullscreenSurfaceChanged();
@@ -74,7 +73,7 @@ public Q_SLOTS:
void onSessionDestroyingSurface(const mir::scene::Session *, const std::shared_ptr<mir::scene::Surface> &);
protected:
- QHash<const mir::scene::Surface *, MirSurfaceItem *> m_mirSurfaceToItemHash;
+ QHash<const mir::scene::Surface *, MirSurfaceItemInterface *> m_mirSurfaceToItemHash;
QMutex m_mutex;
private:
diff --git a/src/modules/Unity/Application/plugin.cpp b/src/modules/Unity/Application/plugin.cpp
index 37ff7b4..5d03c43 100644
--- a/src/modules/Unity/Application/plugin.cpp
+++ b/src/modules/Unity/Application/plugin.cpp
@@ -73,7 +73,7 @@ class UnityApplicationPlugin : public QQmlExtensionPlugin {
qRegisterMetaType<qtmir::ApplicationManager*>("ApplicationManager*"); //need for queueing signals
qRegisterMetaType<qtmir::Application*>("Application*");
- qRegisterMetaType<qtmir::MirSurfaceItem*>("MirSurfaceItem*");
+ qRegisterMetaType<qtmir::MirSurfaceItemInterface*>("MirSurfaceItemInterface*");
qRegisterMetaType<qtmir::MirSurfaceItemModel*>("MirSurfaceItemModel*");
qRegisterMetaType<qtmir::Session*>("Session*");
qRegisterMetaType<qtmir::SessionInterface*>("SessionInterface*");
@@ -92,7 +92,7 @@ class UnityApplicationPlugin : public QQmlExtensionPlugin {
uri, 0, 1, "SurfaceManager", surfaceManagerSingleton);
qmlRegisterSingletonType<qtmir::SessionManager>(
uri, 0, 1, "SessionManager", sessionManagerSingleton);
- qmlRegisterUncreatableType<qtmir::MirSurfaceItem>(
+ qmlRegisterUncreatableType<qtmir::MirSurfaceItemInterface>(
uri, 0, 1, "MirSurfaceItem", "MirSurfaceItem can't be instantiated from QML");
qmlRegisterUncreatableType<qtmir::Session>(
uri, 0, 1, "Session", "Session can't be instantiated from QML");
diff --git a/src/modules/Unity/Application/session.cpp b/src/modules/Unity/Application/session.cpp
index 6999a37..2cd1024 100644
--- a/src/modules/Unity/Application/session.cpp
+++ b/src/modules/Unity/Application/session.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014,2015 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,14 +60,7 @@ Session::Session(const std::shared_ptr<ms::Session>& session,
QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);
m_suspendTimer->setSingleShot(true);
- connect(m_suspendTimer, &QTimer::timeout, this, [this]() {
- if (m_surface) {
- m_surface->stopFrameDropper();
- } else {
- qDebug() << "Application::suspend - no surface to call stopFrameDropper() on!";
- }
- Q_EMIT suspended();
- });
+ connect(m_suspendTimer, &QTimer::timeout, this, &Session::doSuspend);
}
Session::~Session()
@@ -89,6 +82,17 @@ Session::~Session()
delete m_children; m_children = nullptr;
}
+void Session::doSuspend()
+{
+ Q_ASSERT(m_state == Session::Suspending);
+ if (m_surface) {
+ m_surface->stopFrameDropper();
+ } else {
+ qDebug() << "Application::suspend - no surface to call stopFrameDropper() on!";
+ }
+ setState(Suspended);
+}
+
void Session::release()
{
qCDebug(QTMIR_SESSIONS) << "Session::release " << name();
@@ -120,7 +124,7 @@ ApplicationInfoInterface* Session::application() const
return m_application;
}
-MirSurfaceItem* Session::surface() const
+MirSurfaceItemInterface* Session::surface() const
{
// Only notify QML of surface creation once it has drawn its first frame.
if (m_surface && m_surface->isFirstFrameDrawn()) {
@@ -140,6 +144,13 @@ Session::State Session::state() const
return m_state;
}
+void Session::setState(State state) {
+ if (state != m_state) {
+ m_state = state;
+ Q_EMIT stateChanged(m_state);
+ }
+}
+
bool Session::fullscreen() const
{
return m_fullscreen;
@@ -159,7 +170,7 @@ void Session::setApplication(ApplicationInfoInterface* application)
Q_EMIT applicationChanged(application);
}
-void Session::setSurface(MirSurfaceItem *newSurface)
+void Session::setSurface(MirSurfaceItemInterface *newSurface)
{
qCDebug(QTMIR_SESSIONS) << "Session::setSurface - session=" << name() << "surface=" << newSurface;
@@ -173,34 +184,46 @@ void Session::setSurface(MirSurfaceItem *newSurface)
m_surface->setParent(nullptr);
}
- MirSurfaceItem *previousSurface = surface();
+ MirSurfaceItemInterface *previousSurface = surface();
m_surface = newSurface;
if (newSurface) {
m_surface->setParent(this);
m_surface->setSession(this);
+ connect(newSurface, &MirSurfaceItemInterface::stateChanged,
+ this, &Session::updateFullscreenProperty);
+
// Only notify QML of surface creation once it has drawn its first frame.
- if (!surface()) {
- connect(newSurface, &MirSurfaceItem::firstFrameDrawn,
- this, [this] { Q_EMIT surfaceChanged(m_surface); });
+ if (m_surface->isFirstFrameDrawn()) {
+ setState(Running);
+ } else {
+ connect(newSurface, &MirSurfaceItemInterface::firstFrameDrawn,
+ this, &Session::onFirstSurfaceFrameDrawn);
}
-
- connect(newSurface, &MirSurfaceItem::stateChanged,
- this, &Session::updateFullscreenProperty);
}
if (previousSurface != surface()) {
+ qCDebug(QTMIR_SESSIONS).nospace() << "Session::surfaceChanged - session=" << this
+ << " surface=" << m_surface;
Q_EMIT surfaceChanged(m_surface);
}
updateFullscreenProperty();
}
+void Session::onFirstSurfaceFrameDrawn()
+{
+ qCDebug(QTMIR_SESSIONS).nospace() << "Session::surfaceChanged - session=" << this
+ << " surface=" << m_surface;
+ Q_EMIT surfaceChanged(m_surface);
+ setState(Running);
+}
+
void Session::updateFullscreenProperty()
{
if (m_surface) {
- setFullscreen(m_surface->state() == MirSurfaceItem::Fullscreen);
+ setFullscreen(m_surface->state() == MirSurfaceItemInterface::Fullscreen);
} else {
// Keep the current value of the fullscreen property until we get a new
// surface
@@ -216,59 +239,71 @@ void Session::setFullscreen(bool fullscreen)
}
}
-void Session::setState(State state)
+void Session::suspend()
{
- qCDebug(QTMIR_SESSIONS) << "Session::setState - session=" << this << "state=" << applicationStateToStr(state);
- if (m_state != state) {
- switch (state)
- {
- case Session::State::Suspended:
- if (m_state == Session::State::Running) {
- session()->set_lifecycle_state(mir_lifecycle_state_will_suspend);
- m_suspendTimer->start(1500);
- }
- break;
- case Session::State::Running:
- if (m_suspendTimer->isActive())
- m_suspendTimer->stop();
-
- if (m_state == Session::State::Suspended) {
- if (m_surface)
- m_surface->startFrameDropper();
- Q_EMIT resumed();
- session()->set_lifecycle_state(mir_lifecycle_state_resumed);
- }
- break;
- case Session::State::Stopped:
- stopPromptSessions();
- if (m_suspendTimer->isActive())
- m_suspendTimer->stop();
- if (m_surface)
- m_surface->stopFrameDropper();
- break;
- default:
- break;
- }
+ qCDebug(QTMIR_SESSIONS) << "Session::suspend - session=" << this << "state=" << applicationStateToStr(m_state);
+ if (m_state == Running) {
+ session()->set_lifecycle_state(mir_lifecycle_state_will_suspend);
+ m_suspendTimer->start(1500);
- m_state = state;
- Q_EMIT stateChanged(state);
-
- foreachPromptSession([this, state](const std::shared_ptr<ms::PromptSession>& promptSession) {
- switch (state) {
- case Session::State::Suspended:
- m_promptSessionManager->suspend_prompt_session(promptSession);
- break;
- case Session::State::Running:
- m_promptSessionManager->resume_prompt_session(promptSession);
- break;
- default:
- break;
- }
+ foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) {
+ m_promptSessionManager->suspend_prompt_session(promptSession);
});
- foreachChildSession([state](SessionInterface* session) {
- session->setState(state);
+ foreachChildSession([](SessionInterface* session) {
+ session->suspend();
});
+
+ setState(Suspending);
+ }
+}
+
+void Session::resume()
+{
+ qCDebug(QTMIR_SESSIONS) << "Session::resume - session=" << this << "state=" << applicationStateToStr(m_state);
+
+ if (m_state == Suspending || m_state == Suspended) {
+ doResume();
+ }
+}
+
+void Session::doResume()
+{
+ if (m_state == Suspending) {
+ Q_ASSERT(m_suspendTimer->isActive());
+ m_suspendTimer->stop();
+ } else if (m_state == Suspended) {
+ Q_ASSERT(m_surface);
+ m_surface->startFrameDropper();
+ }
+
+ session()->set_lifecycle_state(mir_lifecycle_state_resumed);
+
+ foreachPromptSession([this](const std::shared_ptr<ms::PromptSession>& promptSession) {
+ m_promptSessionManager->resume_prompt_session(promptSession);
+ });
+
+ foreachChildSession([](SessionInterface* session) {
+ session->resume();
+ });
+
+ setState(Running);
+}
+
+void Session::stop()
+{
+ if (m_state != Stopped) {
+ stopPromptSessions();
+ if (m_suspendTimer->isActive())
+ m_suspendTimer->stop();
+ if (m_surface)
+ m_surface->stopFrameDropper();
+
+ foreachChildSession([](SessionInterface* session) {
+ session->stop();
+ });
+
+ setState(Stopped);
}
}
@@ -277,6 +312,9 @@ void Session::setLive(const bool live)
if (m_live != live) {
m_live = live;
Q_EMIT liveChanged(m_live);
+ if (!live) {
+ setState(Stopped);
+ }
}
}
@@ -302,7 +340,19 @@ void Session::insertChildSession(uint index, SessionInterface* session)
static_cast<Session*>(session)->setParentSession(this);
m_children->insert(index, session);
- session->setState(state());
+ switch (m_state) {
+ case Starting:
+ case Running:
+ session->resume();
+ break;
+ case Suspending:
+ case Suspended:
+ session->suspend();
+ break;
+ case Stopped:
+ session->stop();
+ break;
+ }
}
void Session::removeChildSession(SessionInterface* session)
diff --git a/src/modules/Unity/Application/session.h b/src/modules/Unity/Application/session.h
index 36ffb45..cbc4cac 100644
--- a/src/modules/Unity/Application/session.h
+++ b/src/modules/Unity/Application/session.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014-2015 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,15 +52,18 @@ public:
//getters
QString name() const override;
unity::shell::application::ApplicationInfoInterface* application() const override;
- MirSurfaceItem* surface() const override;
+ MirSurfaceItemInterface* surface() const override;
SessionInterface* parentSession() const override;
State state() const override;
bool fullscreen() const override;
bool live() const override;
void setApplication(unity::shell::application::ApplicationInfoInterface* item) override;
- void setSurface(MirSurfaceItem* surface) override;
- void setState(State state) override;
+ void setSurface(MirSurfaceItemInterface* surface) override;
+
+ void suspend() override;
+ void resume() override;
+ void stop() override;
void addChildSession(SessionInterface* session) override;
void insertChildSession(uint index, SessionInterface* session) override;
@@ -74,23 +77,29 @@ public:
SessionModel* childSessions() const override;
-protected:
void setFullscreen(bool fullscreen) override;
void setLive(const bool) override;
void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) override;
void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) override;
+public Q_SLOTS:
+ // it's public to ease testing
+ void doSuspend();
+
private Q_SLOTS:
void updateFullscreenProperty();
+ void onFirstSurfaceFrameDrawn();
private:
void setParentSession(Session* session);
+ void setState(State state);
+ void doResume();
void stopPromptSessions();
std::shared_ptr<mir::scene::Session> m_session;
Application* m_application;
- MirSurfaceItem* m_surface;
+ MirSurfaceItemInterface* m_surface;
SessionInterface* m_parentSession;
SessionModel* m_children;
bool m_fullscreen;
@@ -103,6 +112,4 @@ private:
} // namespace qtmir
-Q_DECLARE_METATYPE(qtmir::Session*)
-
#endif // SESSION_H
diff --git a/src/modules/Unity/Application/session_interface.h b/src/modules/Unity/Application/session_interface.h
index 526a96a..186e372 100644
--- a/src/modules/Unity/Application/session_interface.h
+++ b/src/modules/Unity/Application/session_interface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014,2015 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,11 +35,11 @@ namespace mir {
namespace qtmir {
-class MirSurfaceItem;
+class MirSurfaceItemInterface;
class SessionInterface : public QObject {
Q_OBJECT
- Q_PROPERTY(MirSurfaceItem* surface READ surface NOTIFY surfaceChanged)
+ Q_PROPERTY(MirSurfaceItemInterface* surface READ surface NOTIFY surfaceChanged)
Q_PROPERTY(unity::shell::application::ApplicationInfoInterface* application READ application NOTIFY applicationChanged DESIGNABLE false)
Q_PROPERTY(SessionInterface* parentSession READ parentSession NOTIFY parentSessionChanged DESIGNABLE false)
Q_PROPERTY(SessionModel* childSessions READ childSessions DESIGNABLE false CONSTANT)
@@ -49,58 +49,66 @@ public:
SessionInterface(QObject *parent = 0) : QObject(parent) {}
virtual ~SessionInterface() {}
- // Session State
- typedef unity::shell::application::ApplicationInfoInterface::State State;
+ enum State {
+ Starting,
+ Running,
+ Suspending,
+ Suspended,
+ Stopped
+ };
Q_INVOKABLE virtual void release() = 0;
//getters
virtual QString name() const = 0;
virtual unity::shell::application::ApplicationInfoInterface* application() const = 0;
- virtual MirSurfaceItem* surface() const = 0;
+ virtual MirSurfaceItemInterface* surface() const = 0;
virtual SessionInterface* parentSession() const = 0;
+ virtual SessionModel* childSessions() const = 0;
virtual State state() const = 0;
virtual bool fullscreen() const = 0;
virtual bool live() const = 0;
+ virtual std::shared_ptr<mir::scene::Session> session() const = 0;
+
+ // For MirSurfaceItem and MirSurfaceManager use
+
+ virtual void setSurface(MirSurfaceItemInterface* surface) = 0;
+
+ // For Application use
+
virtual void setApplication(unity::shell::application::ApplicationInfoInterface* item) = 0;
- virtual void setSurface(MirSurfaceItem* surface) = 0;
- virtual void setState(State state) = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual void stop() = 0;
+
+ // For SessionManager use
virtual void addChildSession(SessionInterface* session) = 0;
virtual void insertChildSession(uint index, SessionInterface* session) = 0;
virtual void removeChildSession(SessionInterface* session) = 0;
virtual void foreachChildSession(std::function<void(SessionInterface* session)> f) const = 0;
- virtual std::shared_ptr<mir::scene::Session> session() const = 0;
-
virtual std::shared_ptr<mir::scene::PromptSession> activePromptSession() const = 0;
virtual void foreachPromptSession(std::function<void(const std::shared_ptr<mir::scene::PromptSession>&)> f) const = 0;
- virtual SessionModel* childSessions() const = 0;
+ virtual void setFullscreen(bool fullscreen) = 0;
+ virtual void setLive(const bool) = 0;
+ virtual void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0;
+ virtual void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0;
Q_SIGNALS:
- void surfaceChanged(MirSurfaceItem*);
+ void surfaceChanged(MirSurfaceItemInterface*);
void parentSessionChanged(SessionInterface*);
void applicationChanged(unity::shell::application::ApplicationInfoInterface* application);
void aboutToBeDestroyed();
void stateChanged(State state);
void fullscreenChanged(bool fullscreen);
void liveChanged(bool live);
-
- void suspended();
- void resumed();
-
-protected:
- virtual void setFullscreen(bool fullscreen) = 0;
- virtual void setLive(const bool) = 0;
- virtual void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0;
- virtual void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session) = 0;
-
- friend class SessionManager;
};
} // namespace qtmir
+Q_DECLARE_METATYPE(qtmir::SessionInterface*)
#endif // SESSION_INTERFACE_H
diff --git a/src/modules/Unity/Application/sessionmanager.cpp b/src/modules/Unity/Application/sessionmanager.cpp
index 75c4ba0..9b5e14f 100644
--- a/src/modules/Unity/Application/sessionmanager.cpp
+++ b/src/modules/Unity/Application/sessionmanager.cpp
@@ -26,7 +26,6 @@
#include "nativeinterface.h"
#include "mirserver.h"
#include "sessionlistener.h"
-#include "mirshell.h"
#include "logging.h"
#include "promptsessionlistener.h"
diff --git a/src/modules/Unity/Application/taskcontroller.cpp b/src/modules/Unity/Application/taskcontroller.cpp
index e61a46d..1d9ef0d 100644
--- a/src/modules/Unity/Application/taskcontroller.cpp
+++ b/src/modules/Unity/Application/taskcontroller.cpp
@@ -50,14 +50,19 @@ TaskController::TaskController(
&TaskController::processStopped);
connect(m_appController.data(),
+ &ApplicationController::applicationPaused,
+ this,
+ &TaskController::processSuspended);
+
+ connect(m_appController.data(),
&ApplicationController::applicationFocusRequest,
this,
- &TaskController::onApplicationFocusRequest);
+ &TaskController::focusRequested);
connect(m_appController.data(),
- &ApplicationController::applicationResumeRequest,
+ &ApplicationController::applicationResumeRequested,
this,
- &TaskController::onApplicationResumeRequest);
+ &TaskController::resumeRequested);
connect(m_appController.data(),
&ApplicationController::applicationError,
@@ -108,16 +113,6 @@ bool TaskController::resume(const QString &appId)
return m_appController->resumeApplicationWithAppId(appId);
}
-void TaskController::onApplicationFocusRequest(const QString& id)
-{
- Q_EMIT requestFocus(id);
-}
-
-void TaskController::onApplicationResumeRequest(const QString& id)
-{
- Q_EMIT requestResume(id);
-}
-
void TaskController::onApplicationError(const QString& id, ApplicationController::Error error)
{
Q_EMIT processFailed(id, (error == ApplicationController::Error::APPLICATION_FAILED_TO_START) );
diff --git a/src/modules/Unity/Application/taskcontroller.h b/src/modules/Unity/Application/taskcontroller.h
index 6a549a0..c9a5591 100644
--- a/src/modules/Unity/Application/taskcontroller.h
+++ b/src/modules/Unity/Application/taskcontroller.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 Canonical, Ltd.
+ * Copyright (C) 2013-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -48,14 +48,12 @@ public:
Q_SIGNALS:
void processStarting(const QString &appId);
void processStopped(const QString &appId);
+ void processSuspended(const QString &appId);
void processFailed(const QString &appId, const bool duringStartup);
- void requestFocus(const QString &appId);
- void requestResume(const QString &appId);
+ void focusRequested(const QString &appId);
+ void resumeRequested(const QString &appId);
private Q_SLOTS:
- void onApplicationFocusRequest(const QString &id);
- void onApplicationResumeRequest(const QString &id);
-
void onApplicationError(const QString &id, ApplicationController::Error error);
private:
diff --git a/src/modules/Unity/Application/upstart/applicationcontroller.cpp b/src/modules/Unity/Application/upstart/applicationcontroller.cpp
index bc5d45c..4179285 100644
--- a/src/modules/Unity/Application/upstart/applicationcontroller.cpp
+++ b/src/modules/Unity/Application/upstart/applicationcontroller.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014,2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -40,6 +40,7 @@ struct ApplicationController::Private
UbuntuAppLaunchAppObserver stopCallback = nullptr;
UbuntuAppLaunchAppObserver focusCallback = nullptr;
UbuntuAppLaunchAppObserver resumeCallback = nullptr;
+ UbuntuAppLaunchAppPausedResumedObserver pausedCallback = nullptr;
UbuntuAppLaunchAppFailedObserver failureCallback = nullptr;
};
@@ -125,7 +126,12 @@ ApplicationController::ApplicationController()
impl->resumeCallback = [](const gchar * appId, gpointer userData) {
auto thiz = static_cast<ApplicationController*>(userData);
- Q_EMIT(thiz->applicationResumeRequest(toShortAppIdIfPossible(appId)));
+ Q_EMIT(thiz->applicationResumeRequested(toShortAppIdIfPossible(appId)));
+ };
+
+ impl->pausedCallback = [](const gchar * appId, GPid *, gpointer userData) {
+ auto thiz = static_cast<ApplicationController*>(userData);
+ Q_EMIT(thiz->applicationPaused(toShortAppIdIfPossible(appId)));
};
impl->failureCallback = [](const gchar * appId, UbuntuAppLaunchAppFailed failureType, gpointer userData) {
@@ -145,6 +151,7 @@ ApplicationController::ApplicationController()
ubuntu_app_launch_observer_add_app_stop(impl->stopCallback, this);
ubuntu_app_launch_observer_add_app_focus(impl->focusCallback, this);
ubuntu_app_launch_observer_add_app_resume(impl->resumeCallback, this);
+ ubuntu_app_launch_observer_add_app_paused(impl->pausedCallback, this);
ubuntu_app_launch_observer_add_app_failed(impl->failureCallback, this);
}
@@ -155,6 +162,7 @@ ApplicationController::~ApplicationController()
ubuntu_app_launch_observer_delete_app_stop(impl->stopCallback, this);
ubuntu_app_launch_observer_delete_app_focus(impl->focusCallback, this);
ubuntu_app_launch_observer_delete_app_resume(impl->resumeCallback, this);
+ ubuntu_app_launch_observer_delete_app_paused(impl->pausedCallback, this);
ubuntu_app_launch_observer_delete_app_failed(impl->failureCallback, this);
}