summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt22
-rw-r--r--debian/changelog13
-rw-r--r--debian/control8
-rwxr-xr-xdebian/rules7
-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
-rw-r--r--src/platforms/mirserver/CMakeLists.txt4
-rw-r--r--src/platforms/mirserver/miropenglcontext.cpp6
-rw-r--r--src/platforms/mirserver/miropenglcontext.h9
-rw-r--r--src/platforms/mirserver/mirserver.cpp16
-rw-r--r--src/platforms/mirserver/mirserver.h3
-rw-r--r--src/platforms/mirserver/mirserverintegration.cpp17
-rw-r--r--src/platforms/mirserver/mirserverintegration.h8
-rw-r--r--src/platforms/mirserver/mirshell.cpp164
-rw-r--r--src/platforms/mirserver/mirshell.h47
-rw-r--r--src/platforms/mirserver/mirwindowmanager.cpp112
-rw-r--r--src/platforms/mirserver/mirwindowmanager.h73
-rw-r--r--src/platforms/mirserver/qteventfeeder.cpp388
-rw-r--r--tests/modules/Application/CMakeLists.txt4
-rw-r--r--tests/modules/Application/application_test.cpp170
-rw-r--r--tests/modules/ApplicationManager/CMakeLists.txt5
-rw-r--r--tests/modules/ApplicationManager/application_manager_test.cpp959
-rw-r--r--tests/modules/MirSurfaceItem/CMakeLists.txt2
-rw-r--r--tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp2
-rw-r--r--tests/modules/SessionManager/CMakeLists.txt3
-rw-r--r--tests/modules/SessionManager/session_manager_test.cpp2
-rw-r--r--tests/modules/SessionManager/session_test.cpp79
-rw-r--r--tests/modules/TaskController/CMakeLists.txt1
-rw-r--r--tests/modules/common/fake_mirsurfaceitem.h95
-rw-r--r--tests/modules/common/mock_mirsurfaceitem.h50
-rw-r--r--tests/modules/common/mock_session.h49
-rw-r--r--tests/modules/common/qtmir_test.cpp61
-rw-r--r--tests/modules/common/qtmir_test.h10
52 files changed, 1994 insertions, 1735 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 665acfe..8555ffa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -50,13 +50,13 @@ add_custom_target(cppcheck COMMAND cppcheck --enable=all -q --error-exitcode=2
${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/tests)
include(FindPkgConfig)
-find_package(Qt5Core 5.3 REQUIRED)
-find_package(Qt5DBus 5.3 REQUIRED)
-find_package(Qt5Gui 5.3 REQUIRED)
-find_package(Qt5Qml 5.3 REQUIRED)
-find_package(Qt5Quick 5.3 REQUIRED)
-find_package(Qt5Sensors 5.3 REQUIRED)
-find_package(Qt5Test 5.3 REQUIRED)
+find_package(Qt5Core 5.4 REQUIRED)
+find_package(Qt5DBus 5.4 REQUIRED)
+find_package(Qt5Gui 5.4 REQUIRED)
+find_package(Qt5Qml 5.4 REQUIRED)
+find_package(Qt5Quick 5.4 REQUIRED)
+find_package(Qt5Sensors 5.4 REQUIRED)
+find_package(Qt5Test 5.4 REQUIRED)
find_package(Threads REQUIRED)
@@ -65,8 +65,8 @@ if(PROTOBUF_PROTOC_EXECUTABLE STREQUAL "PROTOBUF_PROTOC_EXECUTABLE-NOTFOUND")
message(SEND_ERROR "protoc executable not found! Missing protobuf-compiler package?")
endif()
-pkg_check_modules(MIRSERVER mirserver>=0.13 REQUIRED)
-pkg_check_modules(MIRCLIENT mirclient>=0.13 REQUIRED)
+pkg_check_modules(MIRSERVER mirserver>=0.14 REQUIRED)
+pkg_check_modules(MIRCLIENT mirclient>=0.14 REQUIRED)
pkg_check_modules(GLIB glib-2.0 REQUIRED)
pkg_check_modules(PROCESS_CPP process-cpp REQUIRED)
@@ -80,7 +80,9 @@ pkg_check_modules(LTTNG lttng-ust)
pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED)
pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED)
-pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=6)
+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=7)
+
+include_directories(${APPLICATION_API_INCLUDE_DIRS})
add_definitions(-DMIR_REQUIRE_DEPRECATED_EVENT_OPT_IN=1)
diff --git a/debian/changelog b/debian/changelog
index a1e2064..5817a72 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+qtmir (0.4.5+15.10.20150728-0ubuntu2~gcc5.1) wily; urgency=medium
+
+ * No change rebuild using GCC 5.
+
+ -- Matthias Klose <doko@ubuntu.com> Wed, 29 Jul 2015 15:04:01 +0200
+
+qtmir (0.4.5+15.10.20150728-0ubuntu1) wily; urgency=medium
+
+ [ Gerry Boland ]
+ * Remove explicit gcc4.9 dependency (LP: #1452338)
+
+ -- CI Train Bot <ci-train-bot@canonical.com> Tue, 28 Jul 2015 09:57:00 +0000
+
qtmir (0.4.5+15.10.20150722-0ubuntu1) wily; urgency=medium
[ Andreas Pokorny ]
diff --git a/debian/control b/debian/control
index 93bca1e..cf63849 100644
--- a/debian/control
+++ b/debian/control
@@ -5,12 +5,6 @@ Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Build-Depends: cmake,
cmake-extras (>= 0.3),
debhelper (>= 9),
-# We rely on C++11 features, and to prevent from ABI breaks
-# in libstdc++ causing us issues, we explicitly select a G++
-# version. To allow cross-compiling to work, we also must
-# append :native to g++-4.9 so we don't try to run armhf g++
-# on an x86 CPU for example, when cross-compiling.
- g++-4.9:native,
google-mock (>= 1.6.0+svn437),
libfontconfig1-dev,
libgles2-mesa-dev,
@@ -28,7 +22,7 @@ Build-Depends: cmake,
libubuntu-app-launch2-dev,
libubuntu-application-api-dev (>= 2.1.0),
libudev-dev,
- libunity-api-dev (>= 7.97),
+ libunity-api-dev (>= 7.98),
liburl-dispatcher1-dev,
libxkbcommon-dev,
libxrender-dev,
diff --git a/debian/rules b/debian/rules
index 027327b..f355f45 100755
--- a/debian/rules
+++ b/debian/rules
@@ -5,13 +5,6 @@ export DPKG_GENSYMBOLS_CHECK_LEVEL=4
include /usr/share/dpkg/default.mk
-# Explicitly selecting a G{CC,++}-version here to avoid accidental
-# ABI breaks introduced by toolchain updates.
-export CC=$(DEB_HOST_GNU_TYPE)-gcc-4.9
-export CXX=$(DEB_HOST_GNU_TYPE)-g++-4.9
-
-FLAGS = "QMAKE_CXX=$(CXX)" "QMAKE_LINK=$(CXX)" "QMAKE_LINK_SHLIB=$(CXX)"
-
ANDROID_DIR = build-android
DESKTOP_DIR = build-desktop
TMP1_DIR = $(CURDIR)/debian/tmp1
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);
}
diff --git a/src/platforms/mirserver/CMakeLists.txt b/src/platforms/mirserver/CMakeLists.txt
index 60abe20..36d9321 100644
--- a/src/platforms/mirserver/CMakeLists.txt
+++ b/src/platforms/mirserver/CMakeLists.txt
@@ -31,6 +31,8 @@ include_directories(
${QT5PLATFORM_SUPPORT_INCLUDE_DIRS}
${Qt5Gui_PRIVATE_INCLUDE_DIRS}
${QT5_PLATFORMSUPPORT_INCLUDE_DIRS}
+
+ ${APPLICATION_API_INCLUDE_DIRS}
)
# We have to remove -pedantic for tracepoints.c
@@ -40,7 +42,7 @@ add_definitions(-DBYTE_ORDER=__BYTE_ORDER)
set(MIRSERVER_QPA_PLUGIN_SRC
${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
- mirshell.cpp
+ mirwindowmanager.cpp
qteventfeeder.cpp
plugin.cpp
qmirserver.cpp
diff --git a/src/platforms/mirserver/miropenglcontext.cpp b/src/platforms/mirserver/miropenglcontext.cpp
index cb84666..6c9360a 100644
--- a/src/platforms/mirserver/miropenglcontext.cpp
+++ b/src/platforms/mirserver/miropenglcontext.cpp
@@ -36,7 +36,7 @@
// (i.e. individual display output buffers) to use as a common base context.
MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server, const QSurfaceFormat &format)
-#if GL_DEBUG
+#ifndef QT_NO_DEBUG
: m_logger(new QOpenGLDebugLogger(this))
#endif
{
@@ -96,10 +96,8 @@ MirOpenGLContext::MirOpenGLContext(const QSharedPointer<MirServer> &server, cons
qDebug() << "OpenGL ES extensions:" << qPrintable(string);
q_printEglConfig(eglDisplay, eglConfig);
-#if GL_DEBUG
QObject::connect(m_logger, &QOpenGLDebugLogger::messageLogged,
this, &MirOpenGLContext::onGlDebugMessageLogged, Qt::DirectConnection);
-#endif // Qt>=5.2
#endif // debug
}
@@ -122,7 +120,7 @@ bool MirOpenGLContext::makeCurrent(QPlatformSurface *surface)
if (displayBuffer) {
displayBuffer->makeCurrent();
-#if GL_DEBUG
+#ifndef QT_NO_DEBUG
if (!m_logger->isLogging() && m_logger->initialize()) {
m_logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
m_logger->enableMessages();
diff --git a/src/platforms/mirserver/miropenglcontext.h b/src/platforms/mirserver/miropenglcontext.h
index de3ec9c..c1d6274 100644
--- a/src/platforms/mirserver/miropenglcontext.h
+++ b/src/platforms/mirserver/miropenglcontext.h
@@ -21,9 +21,7 @@
#include <qpa/qplatformopenglcontext.h>
-#define GL_DEBUG (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) && !defined(QT_NO_DEBUG))
-
-#if GL_DEBUG
+#ifndef QT_NO_DEBUG
#include <QOpenGLDebugLogger>
#endif
@@ -46,14 +44,13 @@ public:
QFunctionPointer getProcAddress(const QByteArray &procName) override;
-// "#if GL_DEBUG" does not work as MOC does not understand #define
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) && !defined(QT_NO_DEBUG))
+#ifndef QT_NO_DEBUG
Q_SLOT void onGlDebugMessageLogged(QOpenGLDebugMessage m) { qDebug() << m; }
#endif
private:
QSurfaceFormat m_format;
-#if GL_DEBUG
+#ifndef QT_NO_DEBUG
QOpenGLDebugLogger *m_logger;
#endif
};
diff --git a/src/platforms/mirserver/mirserver.cpp b/src/platforms/mirserver/mirserver.cpp
index a60fb0d..f7bb74a 100644
--- a/src/platforms/mirserver/mirserver.cpp
+++ b/src/platforms/mirserver/mirserver.cpp
@@ -19,7 +19,7 @@
#include "mirserver.h"
// local
-#include "mirshell.h"
+#include "mirwindowmanager.h"
#include "mirglconfig.h"
#include "mirserverstatuslistener.h"
#include "promptsessionlistener.h"
@@ -86,17 +86,10 @@ MirServer::MirServer(int argc, char const* argv[], QObject* parent)
return std::make_shared<MirServerStatusListener>();
});
- override_the_shell([this]
+ override_the_window_manager_builder([this](mir::shell::FocusController* /*focus_controller*/)
+ -> std::shared_ptr<mir::shell::WindowManager>
{
- auto const shell = std::make_shared<MirShell>(
- the_input_targeter(),
- the_surface_coordinator(),
- the_session_coordinator(),
- the_prompt_session_manager(),
- the_shell_display_layout());
-
- m_shell = shell;
- return shell;
+ return std::make_shared<MirWindowManager>(the_shell_display_layout());
});
set_terminator([&](int)
@@ -151,5 +144,6 @@ PromptSessionListener *MirServer::promptSessionListener()
MirShell *MirServer::shell()
{
+ std::weak_ptr<MirShell> m_shell = the_shell();
return m_shell.lock().get();
}
diff --git a/src/platforms/mirserver/mirserver.h b/src/platforms/mirserver/mirserver.h
index b4b8dc2..3956f9c 100644
--- a/src/platforms/mirserver/mirserver.h
+++ b/src/platforms/mirserver/mirserver.h
@@ -23,7 +23,7 @@
class QtEventFeeder;
class SessionListener;
class SessionAuthorizer;
-class MirShell;
+using MirShell = mir::shell::Shell;
class PromptSessionListener;
// We use virtual inheritance of mir::Server to facilitate derived classes (e.g. testing)
@@ -61,7 +61,6 @@ public:
private:
std::shared_ptr<QtEventFeeder> m_qtEventFeeder;
- std::weak_ptr<MirShell> m_shell;
};
#endif // MIRSERVER_H
diff --git a/src/platforms/mirserver/mirserverintegration.cpp b/src/platforms/mirserver/mirserverintegration.cpp
index ad33caa..28c8c9d 100644
--- a/src/platforms/mirserver/mirserverintegration.cpp
+++ b/src/platforms/mirserver/mirserverintegration.cpp
@@ -31,11 +31,6 @@
#include <QCoreApplication>
#include <QOpenGLContext>
-
-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
-#include <private/qguiapplication_p.h>
-#endif
-
#include <QDebug>
// Mir
@@ -59,9 +54,6 @@ MirServerIntegration::MirServerIntegration()
: m_accessibility(new QPlatformAccessibility())
, m_fontDb(new QGenericUnixFontDatabase())
, m_services(new Services)
-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
- , m_eventDispatcher(createUnixEventDispatcher())
-#endif
, m_mirServer(new QMirServer(QCoreApplication::arguments()))
, m_display(nullptr)
, m_nativeInterface(nullptr)
@@ -82,11 +74,6 @@ MirServerIntegration::MirServerIntegration()
QObject::connect(m_mirServer.data(), &QMirServer::stopped,
QCoreApplication::instance(), &QCoreApplication::quit);
-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
- QGuiApplicationPrivate::instance()->setEventDispatcher(eventDispatcher_);
- initialize();
-#endif
-
m_inputContext = QPlatformInputContextFactory::create();
}
@@ -105,10 +92,8 @@ bool MirServerIntegration::hasCapability(QPlatformIntegration::Capability cap) c
case SharedGraphicsCache: return true;
case BufferQueueingOpenGL: return true;
case MultipleWindows: return false; // multi-monitor support
-#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
case WindowManagement: return false; // platform has no WM, as this implements the WM!
case NonFullScreenWindows: return false;
-#endif
default: return QPlatformIntegration::hasCapability(cap);
}
}
@@ -158,12 +143,10 @@ QPlatformOpenGLContext *MirServerIntegration::createPlatformOpenGLContext(QOpenG
return new MirOpenGLContext(m_mirServer->mirServer(), context->format());
}
-#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
QAbstractEventDispatcher *MirServerIntegration::createEventDispatcher() const
{
return createUnixEventDispatcher();
}
-#endif
void MirServerIntegration::initialize()
{
diff --git a/src/platforms/mirserver/mirserverintegration.h b/src/platforms/mirserver/mirserverintegration.h
index a02405e..cc719e8 100644
--- a/src/platforms/mirserver/mirserverintegration.h
+++ b/src/platforms/mirserver/mirserverintegration.h
@@ -47,13 +47,8 @@ public:
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override;
-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
- QAbstractEventDispatcher* guiThreadEventDispatcher() const override { return eventDispatcher_; }
- void initialize();
-#else
QAbstractEventDispatcher *createEventDispatcher() const override;
void initialize() override;
-#endif
QPlatformClipboard *clipboard() const override;
@@ -72,9 +67,6 @@ private:
QScopedPointer<QPlatformAccessibility> m_accessibility;
QScopedPointer<QPlatformFontDatabase> m_fontDb;
QScopedPointer<QPlatformServices> m_services;
-#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
- QScopedPointer<QAbstractEventDispatcher> m_eventDispatcher;
-#endif
QScopedPointer<QMirServer> m_mirServer;
diff --git a/src/platforms/mirserver/mirshell.cpp b/src/platforms/mirserver/mirshell.cpp
deleted file mode 100644
index 3b1e9c4..0000000
--- a/src/platforms/mirserver/mirshell.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright © 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/>.
- */
-
-#include "mirshell.h"
-#include "logging.h"
-#include "tracepoints.h" // generated from tracepoints.tp
-
-#include <mir/geometry/rectangle.h>
-#include <mir/scene/session.h>
-#include <mir/scene/surface_creation_parameters.h>
-#include <mir/scene/surface.h>
-#include <mir/shell/display_layout.h>
-#include <mir/shell/window_manager.h>
-
-namespace ms = mir::scene;
-using mir::shell::AbstractShell;
-
-namespace
-{
-class NullWindowManager : public mir::shell::WindowManager
-{
-public:
- void add_session(std::shared_ptr<ms::Session> const& session) override;
-
- void remove_session(std::shared_ptr<ms::Session> const& session) override;
-
- mir::frontend::SurfaceId add_surface(
- std::shared_ptr<ms::Session> const& session,
- ms::SurfaceCreationParameters const& params,
- std::function<mir::frontend::SurfaceId(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)> const& build) override;
-
- void remove_surface(
- std::shared_ptr<ms::Session> const& session,
- std::weak_ptr<ms::Surface> const& surface) override;
-
- void add_display(mir::geometry::Rectangle const& area) override;
-
- void remove_display(mir::geometry::Rectangle const& area) override;
-
- bool handle_keyboard_event(MirKeyboardEvent const* event) override;
-
- bool handle_touch_event(MirTouchEvent const* event) override;
-
- bool handle_pointer_event(MirPointerEvent const* event) override;
-
- int set_surface_attribute(
- std::shared_ptr<ms::Session> const& session,
- std::shared_ptr<ms::Surface> const& surface,
- MirSurfaceAttrib attrib,
- int value) override;
-
- void modify_surface(const std::shared_ptr<mir::scene::Session>&, const std::shared_ptr<mir::scene::Surface>&, const mir::shell::SurfaceSpecification&);
-};
-}
-
-
-MirShell::MirShell(
- const std::shared_ptr<mir::shell::InputTargeter> &inputTargeter,
- const std::shared_ptr<mir::scene::SurfaceCoordinator> &surfaceCoordinator,
- const std::shared_ptr<mir::scene::SessionCoordinator> &sessionCoordinator,
- const std::shared_ptr<mir::scene::PromptSessionManager> &promptSessionManager,
- const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout) :
- AbstractShell(inputTargeter, surfaceCoordinator, sessionCoordinator, promptSessionManager,
- [](mir::shell::FocusController*) { return std::make_shared<NullWindowManager>(); }),
- m_displayLayout{displayLayout}
-{
- qCDebug(QTMIR_MIR_MESSAGES) << "MirShell::MirShell";
-}
-
-mir::frontend::SurfaceId MirShell::create_surface(const std::shared_ptr<ms::Session> &session, const ms::SurfaceCreationParameters &requestParameters)
-{
- tracepoint(qtmirserver, surfacePlacementStart);
-
- // TODO: Callback unity8 so that it can make a decision on that.
- // unity8 must bear in mind that the called function will be on a Mir thread though.
- // The QPA shouldn't be deciding for itself on such things.
-
- ms::SurfaceCreationParameters placedParameters = requestParameters;
-
- // Just make it fullscreen for now
- mir::geometry::Rectangle rect{requestParameters.top_left, requestParameters.size};
- m_displayLayout->size_to_output(rect);
- placedParameters.size = rect.size;
-
- qCDebug(QTMIR_MIR_MESSAGES) << "MirShell::create_surface(): size requested ("
- << requestParameters.size.width.as_int() << "," << requestParameters.size.height.as_int() << ") and placed ("
- << placedParameters.size.width.as_int() << "," << placedParameters.size.height.as_int() << ")";
-
- tracepoint(qtmirserver, surfacePlacementEnd);
-
- return AbstractShell::create_surface(session, placedParameters);
-}
-
-void NullWindowManager::add_session(std::shared_ptr<ms::Session> const& /*session*/)
-{
-}
-
-void NullWindowManager::remove_session(std::shared_ptr<ms::Session> const& /*session*/)
-{
-}
-
-auto NullWindowManager::add_surface(
- std::shared_ptr<ms::Session> const& session,
- ms::SurfaceCreationParameters const& params,
- std::function<mir::frontend::SurfaceId(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)> const& build)
--> mir::frontend::SurfaceId
-{
- return build(session, params);
-}
-
-void NullWindowManager::remove_surface(
- std::shared_ptr<ms::Session> const& /*session*/,
- std::weak_ptr<ms::Surface> const& /*surface*/)
-{
-}
-
-void NullWindowManager::add_display(mir::geometry::Rectangle const& /*area*/)
-{
-}
-
-void NullWindowManager::remove_display(mir::geometry::Rectangle const& /*area*/)
-{
-}
-
-bool NullWindowManager::handle_keyboard_event(MirKeyboardEvent const* /*event*/)
-{
- return false;
-}
-
-bool NullWindowManager::handle_touch_event(MirTouchEvent const* /*event*/)
-{
- return false;
-}
-
-bool NullWindowManager::handle_pointer_event(MirPointerEvent const* /*event*/)
-{
- return false;
-}
-
-int NullWindowManager::set_surface_attribute(
- std::shared_ptr<ms::Session> const& /*session*/,
- std::shared_ptr<ms::Surface> const& surface,
- MirSurfaceAttrib attrib,
- int value)
-{
- return surface->configure(attrib, value);
-}
-
-void NullWindowManager::modify_surface(const std::shared_ptr<mir::scene::Session>&, const std::shared_ptr<mir::scene::Surface>&, const mir::shell::SurfaceSpecification&)
-{
-}
diff --git a/src/platforms/mirserver/mirshell.h b/src/platforms/mirserver/mirshell.h
deleted file mode 100644
index 85c243e..0000000
--- a/src/platforms/mirserver/mirshell.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright © 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 QPAMIRSERVER_SHELL_H
-#define QPAMIRSERVER_SHELL_H
-
-#include <mir/shell/abstract_shell.h>
-#include <QObject>
-
-namespace mir {
- namespace shell {
- class DisplayLayout;
- }
-}
-
-class MirShell : public QObject, public mir::shell::AbstractShell
-{
- Q_OBJECT
-
-public:
- MirShell(
- const std::shared_ptr<mir::shell::InputTargeter> &inputTargeter,
- const std::shared_ptr<mir::scene::SurfaceCoordinator> &surfaceCoordinator,
- const std::shared_ptr<mir::scene::SessionCoordinator> &sessionCoordinator,
- const std::shared_ptr<mir::scene::PromptSessionManager> &promptSessionManager,
- const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout);
-
- virtual mir::frontend::SurfaceId create_surface(const std::shared_ptr<mir::scene::Session>& session, const mir::scene::SurfaceCreationParameters &params);
-
-private:
- std::shared_ptr<mir::shell::DisplayLayout> const m_displayLayout;
-};
-
-#endif /* QPAMIRSERVER_SHELL_H */
diff --git a/src/platforms/mirserver/mirwindowmanager.cpp b/src/platforms/mirserver/mirwindowmanager.cpp
new file mode 100644
index 0000000..cae66d4
--- /dev/null
+++ b/src/platforms/mirserver/mirwindowmanager.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 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/>.
+ */
+
+#include "mirwindowmanager.h"
+#include "logging.h"
+#include "tracepoints.h" // generated from tracepoints.tp
+
+#include <mir/geometry/rectangle.h>
+#include <mir/scene/session.h>
+#include <mir/scene/surface_creation_parameters.h>
+#include <mir/scene/surface.h>
+#include <mir/shell/display_layout.h>
+
+namespace ms = mir::scene;
+
+MirWindowManager::MirWindowManager(const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout) :
+ m_displayLayout{displayLayout}
+{
+ qCDebug(QTMIR_MIR_MESSAGES) << "MirWindowManager::MirWindowManager";
+}
+
+void MirWindowManager::add_session(std::shared_ptr<ms::Session> const& /*session*/)
+{
+}
+
+void MirWindowManager::remove_session(std::shared_ptr<ms::Session> const& /*session*/)
+{
+}
+
+auto MirWindowManager::add_surface(
+ std::shared_ptr<ms::Session> const& session,
+ ms::SurfaceCreationParameters const& requestParameters,
+ std::function<mir::frontend::SurfaceId(std::shared_ptr<ms::Session> const& session, ms::SurfaceCreationParameters const& params)> const& build)
+-> mir::frontend::SurfaceId
+{
+ tracepoint(qtmirserver, surfacePlacementStart);
+
+ // TODO: Callback unity8 so that it can make a decision on that.
+ // unity8 must bear in mind that the called function will be on a Mir thread though.
+ // The QPA shouldn't be deciding for itself on such things.
+
+ ms::SurfaceCreationParameters placedParameters = requestParameters;
+
+ // Just make it fullscreen for now
+ mir::geometry::Rectangle rect{requestParameters.top_left, requestParameters.size};
+ m_displayLayout->size_to_output(rect);
+ placedParameters.size = rect.size;
+
+ qCDebug(QTMIR_MIR_MESSAGES) << "MirWindowManager::add_surface(): size requested ("
+ << requestParameters.size.width.as_int() << "," << requestParameters.size.height.as_int() << ") and placed ("
+ << placedParameters.size.width.as_int() << "," << placedParameters.size.height.as_int() << ")";
+
+ tracepoint(qtmirserver, surfacePlacementEnd);
+
+ return build(session, placedParameters);
+}
+
+void MirWindowManager::remove_surface(
+ std::shared_ptr<ms::Session> const& /*session*/,
+ std::weak_ptr<ms::Surface> const& /*surface*/)
+{
+}
+
+void MirWindowManager::add_display(mir::geometry::Rectangle const& /*area*/)
+{
+}
+
+void MirWindowManager::remove_display(mir::geometry::Rectangle const& /*area*/)
+{
+}
+
+bool MirWindowManager::handle_keyboard_event(MirKeyboardEvent const* /*event*/)
+{
+ return false;
+}
+
+bool MirWindowManager::handle_touch_event(MirTouchEvent const* /*event*/)
+{
+ return false;
+}
+
+bool MirWindowManager::handle_pointer_event(MirPointerEvent const* /*event*/)
+{
+ return false;
+}
+
+int MirWindowManager::set_surface_attribute(
+ std::shared_ptr<ms::Session> const& /*session*/,
+ std::shared_ptr<ms::Surface> const& surface,
+ MirSurfaceAttrib attrib,
+ int value)
+{
+ return surface->configure(attrib, value);
+}
+
+void MirWindowManager::modify_surface(const std::shared_ptr<mir::scene::Session>&, const std::shared_ptr<mir::scene::Surface>&, const mir::shell::SurfaceSpecification&)
+{
+ // TODO support surface modifications
+}
diff --git a/src/platforms/mirserver/mirwindowmanager.h b/src/platforms/mirserver/mirwindowmanager.h
new file mode 100644
index 0000000..0ec1839
--- /dev/null
+++ b/src/platforms/mirserver/mirwindowmanager.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 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 QPAMIRSERVER_WINDOW_MANAGER_H
+#define QPAMIRSERVER_WINDOW_MANAGER_H
+
+#include <mir/shell/window_manager.h>
+
+#include <QObject>
+
+namespace mir {
+ namespace shell {
+ class DisplayLayout;
+ }
+}
+
+class MirWindowManager : public QObject, public mir::shell::WindowManager
+{
+ Q_OBJECT
+
+public:
+
+ MirWindowManager(const std::shared_ptr<mir::shell::DisplayLayout> &displayLayout);
+
+ void add_session(std::shared_ptr<mir::scene::Session> const& session) override;
+
+ void remove_session(std::shared_ptr<mir::scene::Session> const& session) override;
+
+ mir::frontend::SurfaceId add_surface(
+ std::shared_ptr<mir::scene::Session> const& session,
+ mir::scene::SurfaceCreationParameters const& params,
+ std::function<mir::frontend::SurfaceId(std::shared_ptr<mir::scene::Session> const& session, mir::scene::SurfaceCreationParameters const& params)> const& build) override;
+
+ void remove_surface(
+ std::shared_ptr<mir::scene::Session> const& session,
+ std::weak_ptr<mir::scene::Surface> const& surface) override;
+
+ void add_display(mir::geometry::Rectangle const& area) override;
+
+ void remove_display(mir::geometry::Rectangle const& area) override;
+
+ bool handle_keyboard_event(MirKeyboardEvent const* event) override;
+
+ bool handle_touch_event(MirTouchEvent const* event) override;
+
+ bool handle_pointer_event(MirPointerEvent const* event) override;
+
+ int set_surface_attribute(
+ std::shared_ptr<mir::scene::Session> const& session,
+ std::shared_ptr<mir::scene::Surface> const& surface,
+ MirSurfaceAttrib attrib,
+ int value) override;
+
+ void modify_surface(const std::shared_ptr<mir::scene::Session>&, const std::shared_ptr<mir::scene::Surface>&, const mir::shell::SurfaceSpecification&);
+
+private:
+ std::shared_ptr<mir::shell::DisplayLayout> const m_displayLayout;
+};
+
+#endif /* QPAMIRSERVER_WINDOW_MANAGER_H */
diff --git a/src/platforms/mirserver/qteventfeeder.cpp b/src/platforms/mirserver/qteventfeeder.cpp
index 5490096..e51c8d1 100644
--- a/src/platforms/mirserver/qteventfeeder.cpp
+++ b/src/platforms/mirserver/qteventfeeder.cpp
@@ -37,87 +37,315 @@ Q_LOGGING_CATEGORY(QTMIR_MIR_INPUT, "qtmir.mir.input", QtWarningMsg)
// XKB Keysyms which do not map directly to Qt types (i.e. Unicode points)
static const uint32_t KeyTable[] = {
- XKB_KEY_Escape, Qt::Key_Escape,
- XKB_KEY_Tab, Qt::Key_Tab,
- XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab,
- XKB_KEY_BackSpace, Qt::Key_Backspace,
- XKB_KEY_Return, Qt::Key_Return,
- XKB_KEY_Insert, Qt::Key_Insert,
- XKB_KEY_Delete, Qt::Key_Delete,
- XKB_KEY_Clear, Qt::Key_Delete,
- XKB_KEY_Pause, Qt::Key_Pause,
- XKB_KEY_Print, Qt::Key_Print,
-
- XKB_KEY_Home, Qt::Key_Home,
- XKB_KEY_End, Qt::Key_End,
- XKB_KEY_Left, Qt::Key_Left,
- XKB_KEY_Up, Qt::Key_Up,
- XKB_KEY_Right, Qt::Key_Right,
- XKB_KEY_Down, Qt::Key_Down,
- XKB_KEY_Prior, Qt::Key_PageUp,
- XKB_KEY_Next, Qt::Key_PageDown,
-
- XKB_KEY_Shift_L, Qt::Key_Shift,
- XKB_KEY_Shift_R, Qt::Key_Shift,
- XKB_KEY_Shift_Lock, Qt::Key_Shift,
- XKB_KEY_Control_L, Qt::Key_Control,
- XKB_KEY_Control_R, Qt::Key_Control,
- XKB_KEY_Meta_L, Qt::Key_Meta,
- XKB_KEY_Meta_R, Qt::Key_Meta,
- XKB_KEY_Alt_L, Qt::Key_Alt,
- XKB_KEY_Alt_R, Qt::Key_Alt,
- XKB_KEY_Caps_Lock, Qt::Key_CapsLock,
- XKB_KEY_Num_Lock, Qt::Key_NumLock,
- XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock,
- XKB_KEY_Super_L, Qt::Key_Super_L,
- XKB_KEY_Super_R, Qt::Key_Super_R,
- XKB_KEY_Menu, Qt::Key_Menu,
- XKB_KEY_Hyper_L, Qt::Key_Hyper_L,
- XKB_KEY_Hyper_R, Qt::Key_Hyper_R,
- XKB_KEY_Help, Qt::Key_Help,
-
- XKB_KEY_KP_Space, Qt::Key_Space,
- XKB_KEY_KP_Tab, Qt::Key_Tab,
- XKB_KEY_KP_Enter, Qt::Key_Enter,
- XKB_KEY_KP_Home, Qt::Key_Home,
- XKB_KEY_KP_Left, Qt::Key_Left,
- XKB_KEY_KP_Up, Qt::Key_Up,
- XKB_KEY_KP_Right, Qt::Key_Right,
- XKB_KEY_KP_Down, Qt::Key_Down,
- XKB_KEY_KP_Prior, Qt::Key_PageUp,
- XKB_KEY_KP_Next, Qt::Key_PageDown,
- XKB_KEY_KP_End, Qt::Key_End,
- XKB_KEY_KP_Begin, Qt::Key_Clear,
- XKB_KEY_KP_Insert, Qt::Key_Insert,
- XKB_KEY_KP_Delete, Qt::Key_Delete,
- XKB_KEY_KP_Equal, Qt::Key_Equal,
- XKB_KEY_KP_Multiply, Qt::Key_Asterisk,
- XKB_KEY_KP_Add, Qt::Key_Plus,
- XKB_KEY_KP_Separator, Qt::Key_Comma,
- XKB_KEY_KP_Subtract, Qt::Key_Minus,
- XKB_KEY_KP_Decimal, Qt::Key_Period,
- XKB_KEY_KP_Divide, Qt::Key_Slash,
-
- XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr,
- XKB_KEY_Multi_key, Qt::Key_Multi_key,
- XKB_KEY_Codeinput, Qt::Key_Codeinput,
- XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate,
- XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
- XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
-
- XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
- XKB_KEY_script_switch, Qt::Key_Mode_switch,
- XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
+ // misc keys
+ XKB_KEY_Escape, Qt::Key_Escape,
+ XKB_KEY_Tab, Qt::Key_Tab,
+ XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab,
+ XKB_KEY_BackSpace, Qt::Key_Backspace,
+ XKB_KEY_Return, Qt::Key_Return,
+ XKB_KEY_Insert, Qt::Key_Insert,
+ XKB_KEY_Delete, Qt::Key_Delete,
+ XKB_KEY_Clear, Qt::Key_Delete,
+ XKB_KEY_Pause, Qt::Key_Pause,
+ XKB_KEY_Print, Qt::Key_Print,
+ 0x1005FF60, Qt::Key_SysReq, // hardcoded Sun SysReq
+ 0x1007ff00, Qt::Key_SysReq, // hardcoded X386 SysReq
+
+ // cursor movement
+
+ XKB_KEY_Home, Qt::Key_Home,
+ XKB_KEY_End, Qt::Key_End,
+ XKB_KEY_Left, Qt::Key_Left,
+ XKB_KEY_Up, Qt::Key_Up,
+ XKB_KEY_Right, Qt::Key_Right,
+ XKB_KEY_Down, Qt::Key_Down,
+ XKB_KEY_Prior, Qt::Key_PageUp,
+ XKB_KEY_Next, Qt::Key_PageDown,
+
+ // modifiers
+
+ XKB_KEY_Shift_L, Qt::Key_Shift,
+ XKB_KEY_Shift_R, Qt::Key_Shift,
+ XKB_KEY_Shift_Lock, Qt::Key_Shift,
+ XKB_KEY_Control_L, Qt::Key_Control,
+ XKB_KEY_Control_R, Qt::Key_Control,
+ XKB_KEY_Meta_L, Qt::Key_Meta,
+ XKB_KEY_Meta_R, Qt::Key_Meta,
+ XKB_KEY_Alt_L, Qt::Key_Alt,
+ XKB_KEY_Alt_R, Qt::Key_Alt,
+ XKB_KEY_Caps_Lock, Qt::Key_CapsLock,
+ XKB_KEY_Num_Lock, Qt::Key_NumLock,
+ XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock,
+ XKB_KEY_Super_L, Qt::Key_Super_L,
+ XKB_KEY_Super_R, Qt::Key_Super_R,
+ XKB_KEY_Menu, Qt::Key_Menu,
+ XKB_KEY_Hyper_L, Qt::Key_Hyper_L,
+ XKB_KEY_Hyper_R, Qt::Key_Hyper_R,
+ XKB_KEY_Help, Qt::Key_Help,
+ 0x1000FF74, Qt::Key_Backtab, // hardcoded HP backtab
+ 0x1005FF10, Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
+ 0x1005FF11, Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
+
+ // numeric and function keypad keys
+
+ XKB_KEY_KP_Space, Qt::Key_Space,
+ XKB_KEY_KP_Tab, Qt::Key_Tab,
+ XKB_KEY_KP_Enter, Qt::Key_Enter,
+ //XKB_KEY_KP_F1, Qt::Key_F1,
+ //XKB_KEY_KP_F2, Qt::Key_F2,
+ //XKB_KEY_KP_F3, Qt::Key_F3,
+ //XKB_KEY_KP_F4, Qt::Key_F4,
+ XKB_KEY_KP_Home, Qt::Key_Home,
+ XKB_KEY_KP_Left, Qt::Key_Left,
+ XKB_KEY_KP_Up, Qt::Key_Up,
+ XKB_KEY_KP_Right, Qt::Key_Right,
+ XKB_KEY_KP_Down, Qt::Key_Down,
+ XKB_KEY_KP_Prior, Qt::Key_PageUp,
+ XKB_KEY_KP_Next, Qt::Key_PageDown,
+ XKB_KEY_KP_End, Qt::Key_End,
+ XKB_KEY_KP_Begin, Qt::Key_Clear,
+ XKB_KEY_KP_Insert, Qt::Key_Insert,
+ XKB_KEY_KP_Delete, Qt::Key_Delete,
+ XKB_KEY_KP_Equal, Qt::Key_Equal,
+ XKB_KEY_KP_Multiply, Qt::Key_Asterisk,
+ XKB_KEY_KP_Add, Qt::Key_Plus,
+ XKB_KEY_KP_Separator, Qt::Key_Comma,
+ XKB_KEY_KP_Subtract, Qt::Key_Minus,
+ XKB_KEY_KP_Decimal, Qt::Key_Period,
+ XKB_KEY_KP_Divide, Qt::Key_Slash,
+
+ // International input method support keys
+
+ // International & multi-key character composition
+ XKB_KEY_ISO_Level3_Shift, Qt::Key_AltGr,
+ XKB_KEY_Multi_key, Qt::Key_Multi_key,
+ XKB_KEY_Codeinput, Qt::Key_Codeinput,
+ XKB_KEY_SingleCandidate, Qt::Key_SingleCandidate,
+ XKB_KEY_MultipleCandidate, Qt::Key_MultipleCandidate,
+ XKB_KEY_PreviousCandidate, Qt::Key_PreviousCandidate,
+
+ // Misc Functions
+ XKB_KEY_Mode_switch, Qt::Key_Mode_switch,
+ XKB_KEY_script_switch, Qt::Key_Mode_switch,
+
+ // Japanese keyboard support
+ XKB_KEY_Kanji, Qt::Key_Kanji,
+ XKB_KEY_Muhenkan, Qt::Key_Muhenkan,
+ //XKB_KEY_Henkan_Mode, Qt::Key_Henkan_Mode,
+ XKB_KEY_Henkan_Mode, Qt::Key_Henkan,
+ XKB_KEY_Henkan, Qt::Key_Henkan,
+ XKB_KEY_Romaji, Qt::Key_Romaji,
+ XKB_KEY_Hiragana, Qt::Key_Hiragana,
+ XKB_KEY_Katakana, Qt::Key_Katakana,
+ XKB_KEY_Hiragana_Katakana, Qt::Key_Hiragana_Katakana,
+ XKB_KEY_Zenkaku, Qt::Key_Zenkaku,
+ XKB_KEY_Hankaku, Qt::Key_Hankaku,
+ XKB_KEY_Zenkaku_Hankaku, Qt::Key_Zenkaku_Hankaku,
+ XKB_KEY_Touroku, Qt::Key_Touroku,
+ XKB_KEY_Massyo, Qt::Key_Massyo,
+ XKB_KEY_Kana_Lock, Qt::Key_Kana_Lock,
+ XKB_KEY_Kana_Shift, Qt::Key_Kana_Shift,
+ XKB_KEY_Eisu_Shift, Qt::Key_Eisu_Shift,
+ XKB_KEY_Eisu_toggle, Qt::Key_Eisu_toggle,
+ //XKB_KEY_Kanji_Bangou, Qt::Key_Kanji_Bangou,
+ //XKB_KEY_Zen_Koho, Qt::Key_Zen_Koho,
+ //XKB_KEY_Mae_Koho, Qt::Key_Mae_Koho,
+ XKB_KEY_Kanji_Bangou, Qt::Key_Codeinput,
+ XKB_KEY_Zen_Koho, Qt::Key_MultipleCandidate,
+ XKB_KEY_Mae_Koho, Qt::Key_PreviousCandidate,
+
+#ifdef XKB_KEY_KOREAN
+ // Korean keyboard support
+ XKB_KEY_Hangul, Qt::Key_Hangul,
+ XKB_KEY_Hangul_Start, Qt::Key_Hangul_Start,
+ XKB_KEY_Hangul_End, Qt::Key_Hangul_End,
+ XKB_KEY_Hangul_Hanja, Qt::Key_Hangul_Hanja,
+ XKB_KEY_Hangul_Jamo, Qt::Key_Hangul_Jamo,
+ XKB_KEY_Hangul_Romaja, Qt::Key_Hangul_Romaja,
+ //XKB_KEY_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
+ XKB_KEY_Hangul_Codeinput, Qt::Key_Codeinput,
+ XKB_KEY_Hangul_Jeonja, Qt::Key_Hangul_Jeonja,
+ XKB_KEY_Hangul_Banja, Qt::Key_Hangul_Banja,
+ XKB_KEY_Hangul_PreHanja, Qt::Key_Hangul_PreHanja,
+ XKB_KEY_Hangul_PostHanja, Qt::Key_Hangul_PostHanja,
+ //XKB_KEY_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
+ //XKB_KEY_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
+ //XKB_KEY_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
+ XKB_KEY_Hangul_SingleCandidate, Qt::Key_SingleCandidate,
+ XKB_KEY_Hangul_MultipleCandidate,Qt::Key_MultipleCandidate,
+ XKB_KEY_Hangul_PreviousCandidate,Qt::Key_PreviousCandidate,
+ XKB_KEY_Hangul_Special, Qt::Key_Hangul_Special,
+ //XKB_KEY_Hangul_switch, Qt::Key_Hangul_switch,
+ XKB_KEY_Hangul_switch, Qt::Key_Mode_switch,
+#endif // XKB_KEY_KOREAN
+
+ // dead keys
+ XKB_KEY_dead_grave, Qt::Key_Dead_Grave,
+ XKB_KEY_dead_acute, Qt::Key_Dead_Acute,
+ XKB_KEY_dead_circumflex, Qt::Key_Dead_Circumflex,
+ XKB_KEY_dead_tilde, Qt::Key_Dead_Tilde,
+ XKB_KEY_dead_macron, Qt::Key_Dead_Macron,
+ XKB_KEY_dead_breve, Qt::Key_Dead_Breve,
+ XKB_KEY_dead_abovedot, Qt::Key_Dead_Abovedot,
+ XKB_KEY_dead_diaeresis, Qt::Key_Dead_Diaeresis,
+ XKB_KEY_dead_abovering, Qt::Key_Dead_Abovering,
+ XKB_KEY_dead_doubleacute, Qt::Key_Dead_Doubleacute,
+ XKB_KEY_dead_caron, Qt::Key_Dead_Caron,
+ XKB_KEY_dead_cedilla, Qt::Key_Dead_Cedilla,
+ XKB_KEY_dead_ogonek, Qt::Key_Dead_Ogonek,
+ XKB_KEY_dead_iota, Qt::Key_Dead_Iota,
+ XKB_KEY_dead_voiced_sound, Qt::Key_Dead_Voiced_Sound,
+ XKB_KEY_dead_semivoiced_sound, Qt::Key_Dead_Semivoiced_Sound,
+ XKB_KEY_dead_belowdot, Qt::Key_Dead_Belowdot,
+ XKB_KEY_dead_hook, Qt::Key_Dead_Hook,
+ XKB_KEY_dead_horn, Qt::Key_Dead_Horn,
+
+ // Special keys from X.org - This include multimedia keys,
+ // wireless/bluetooth/uwb keys, special launcher keys, etc.
+ XKB_KEY_XF86Back, Qt::Key_Back,
+ XKB_KEY_XF86Forward, Qt::Key_Forward,
+ XKB_KEY_XF86Stop, Qt::Key_Stop,
+ XKB_KEY_XF86Refresh, Qt::Key_Refresh,
+ XKB_KEY_XF86Favorites, Qt::Key_Favorites,
+ XKB_KEY_XF86AudioMedia, Qt::Key_LaunchMedia,
+ XKB_KEY_XF86OpenURL, Qt::Key_OpenUrl,
+ XKB_KEY_XF86HomePage, Qt::Key_HomePage,
+ XKB_KEY_XF86Search, Qt::Key_Search,
XKB_KEY_XF86AudioLowerVolume, Qt::Key_VolumeDown,
- XKB_KEY_XF86PowerOff, Qt::Key_PowerOff,
- XKB_KEY_XF86PowerDown, Qt::Key_PowerDown,
-
- /* Bluetooth / Wired headset multimedia keys */
+ XKB_KEY_XF86AudioMute, Qt::Key_VolumeMute,
+ XKB_KEY_XF86AudioRaiseVolume, Qt::Key_VolumeUp,
XKB_KEY_XF86AudioPlay, Qt::Key_MediaPlay,
+ XKB_KEY_XF86AudioStop, Qt::Key_MediaStop,
XKB_KEY_XF86AudioPrev, Qt::Key_MediaPrevious,
XKB_KEY_XF86AudioNext, Qt::Key_MediaNext,
+ XKB_KEY_XF86AudioRecord, Qt::Key_MediaRecord,
XKB_KEY_XF86AudioPause, Qt::Key_MediaPause,
- XKB_KEY_XF86AudioMedia, Qt::Key_MediaTogglePlayPause,
+ XKB_KEY_XF86Mail, Qt::Key_LaunchMail,
+ XKB_KEY_XF86MyComputer, Qt::Key_Launch0, // ### Qt 6: remap properly
+ XKB_KEY_XF86Calculator, Qt::Key_Launch1,
+ XKB_KEY_XF86Memo, Qt::Key_Memo,
+ XKB_KEY_XF86ToDoList, Qt::Key_ToDoList,
+ XKB_KEY_XF86Calendar, Qt::Key_Calendar,
+ XKB_KEY_XF86PowerDown, Qt::Key_PowerDown,
+ XKB_KEY_XF86ContrastAdjust, Qt::Key_ContrastAdjust,
+ XKB_KEY_XF86Standby, Qt::Key_Standby,
+ XKB_KEY_XF86MonBrightnessUp, Qt::Key_MonBrightnessUp,
+ XKB_KEY_XF86MonBrightnessDown, Qt::Key_MonBrightnessDown,
+ XKB_KEY_XF86KbdLightOnOff, Qt::Key_KeyboardLightOnOff,
+ XKB_KEY_XF86KbdBrightnessUp, Qt::Key_KeyboardBrightnessUp,
+ XKB_KEY_XF86KbdBrightnessDown, Qt::Key_KeyboardBrightnessDown,
+ XKB_KEY_XF86PowerOff, Qt::Key_PowerOff,
+ XKB_KEY_XF86WakeUp, Qt::Key_WakeUp,
+ XKB_KEY_XF86Eject, Qt::Key_Eject,
+ XKB_KEY_XF86ScreenSaver, Qt::Key_ScreenSaver,
+ XKB_KEY_XF86WWW, Qt::Key_WWW,
+ XKB_KEY_XF86Sleep, Qt::Key_Sleep,
+ XKB_KEY_XF86LightBulb, Qt::Key_LightBulb,
+ XKB_KEY_XF86Shop, Qt::Key_Shop,
+ XKB_KEY_XF86History, Qt::Key_History,
+ XKB_KEY_XF86AddFavorite, Qt::Key_AddFavorite,
+ XKB_KEY_XF86HotLinks, Qt::Key_HotLinks,
+ XKB_KEY_XF86BrightnessAdjust, Qt::Key_BrightnessAdjust,
+ XKB_KEY_XF86Finance, Qt::Key_Finance,
+ XKB_KEY_XF86Community, Qt::Key_Community,
+ XKB_KEY_XF86AudioRewind, Qt::Key_AudioRewind,
+ XKB_KEY_XF86BackForward, Qt::Key_BackForward,
+ XKB_KEY_XF86ApplicationLeft, Qt::Key_ApplicationLeft,
+ XKB_KEY_XF86ApplicationRight, Qt::Key_ApplicationRight,
+ XKB_KEY_XF86Book, Qt::Key_Book,
+ XKB_KEY_XF86CD, Qt::Key_CD,
+ XKB_KEY_XF86Calculater, Qt::Key_Calculator,
+ XKB_KEY_XF86Clear, Qt::Key_Clear,
+ XKB_KEY_XF86ClearGrab, Qt::Key_ClearGrab,
+ XKB_KEY_XF86Close, Qt::Key_Close,
+ XKB_KEY_XF86Copy, Qt::Key_Copy,
+ XKB_KEY_XF86Cut, Qt::Key_Cut,
+ XKB_KEY_XF86Display, Qt::Key_Display,
+ XKB_KEY_XF86DOS, Qt::Key_DOS,
+ XKB_KEY_XF86Documents, Qt::Key_Documents,
+ XKB_KEY_XF86Excel, Qt::Key_Excel,
+ XKB_KEY_XF86Explorer, Qt::Key_Explorer,
+ XKB_KEY_XF86Game, Qt::Key_Game,
+ XKB_KEY_XF86Go, Qt::Key_Go,
+ XKB_KEY_XF86iTouch, Qt::Key_iTouch,
+ XKB_KEY_XF86LogOff, Qt::Key_LogOff,
+ XKB_KEY_XF86Market, Qt::Key_Market,
+ XKB_KEY_XF86Meeting, Qt::Key_Meeting,
+ XKB_KEY_XF86MenuKB, Qt::Key_MenuKB,
+ XKB_KEY_XF86MenuPB, Qt::Key_MenuPB,
+ XKB_KEY_XF86MySites, Qt::Key_MySites,
+ XKB_KEY_XF86New, Qt::Key_New,
+ XKB_KEY_XF86News, Qt::Key_News,
+ XKB_KEY_XF86OfficeHome, Qt::Key_OfficeHome,
+ XKB_KEY_XF86Open, Qt::Key_Open,
+ XKB_KEY_XF86Option, Qt::Key_Option,
+ XKB_KEY_XF86Paste, Qt::Key_Paste,
+ XKB_KEY_XF86Phone, Qt::Key_Phone,
+ XKB_KEY_XF86Reply, Qt::Key_Reply,
+ XKB_KEY_XF86Reload, Qt::Key_Reload,
+ XKB_KEY_XF86RotateWindows, Qt::Key_RotateWindows,
+ XKB_KEY_XF86RotationPB, Qt::Key_RotationPB,
+ XKB_KEY_XF86RotationKB, Qt::Key_RotationKB,
+ XKB_KEY_XF86Save, Qt::Key_Save,
+ XKB_KEY_XF86Send, Qt::Key_Send,
+ XKB_KEY_XF86Spell, Qt::Key_Spell,
+ XKB_KEY_XF86SplitScreen, Qt::Key_SplitScreen,
+ XKB_KEY_XF86Support, Qt::Key_Support,
+ XKB_KEY_XF86TaskPane, Qt::Key_TaskPane,
+ XKB_KEY_XF86Terminal, Qt::Key_Terminal,
+ XKB_KEY_XF86Tools, Qt::Key_Tools,
+ XKB_KEY_XF86Travel, Qt::Key_Travel,
+ XKB_KEY_XF86Video, Qt::Key_Video,
+ XKB_KEY_XF86Word, Qt::Key_Word,
+ XKB_KEY_XF86Xfer, Qt::Key_Xfer,
+ XKB_KEY_XF86ZoomIn, Qt::Key_ZoomIn,
+ XKB_KEY_XF86ZoomOut, Qt::Key_ZoomOut,
+ XKB_KEY_XF86Away, Qt::Key_Away,
+ XKB_KEY_XF86Messenger, Qt::Key_Messenger,
+ XKB_KEY_XF86WebCam, Qt::Key_WebCam,
+ XKB_KEY_XF86MailForward, Qt::Key_MailForward,
+ XKB_KEY_XF86Pictures, Qt::Key_Pictures,
+ XKB_KEY_XF86Music, Qt::Key_Music,
+ XKB_KEY_XF86Battery, Qt::Key_Battery,
+ XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
+ XKB_KEY_XF86WLAN, Qt::Key_WLAN,
+ XKB_KEY_XF86UWB, Qt::Key_UWB,
+ XKB_KEY_XF86AudioForward, Qt::Key_AudioForward,
+ XKB_KEY_XF86AudioRepeat, Qt::Key_AudioRepeat,
+ XKB_KEY_XF86AudioRandomPlay, Qt::Key_AudioRandomPlay,
+ XKB_KEY_XF86Subtitle, Qt::Key_Subtitle,
+ XKB_KEY_XF86AudioCycleTrack, Qt::Key_AudioCycleTrack,
+ XKB_KEY_XF86Time, Qt::Key_Time,
+ XKB_KEY_XF86Select, Qt::Key_Select,
+ XKB_KEY_XF86View, Qt::Key_View,
+ XKB_KEY_XF86TopMenu, Qt::Key_TopMenu,
+ XKB_KEY_XF86Red, Qt::Key_Red,
+ XKB_KEY_XF86Green, Qt::Key_Green,
+ XKB_KEY_XF86Yellow, Qt::Key_Yellow,
+ XKB_KEY_XF86Blue, Qt::Key_Blue,
+ XKB_KEY_XF86Bluetooth, Qt::Key_Bluetooth,
+ XKB_KEY_XF86Suspend, Qt::Key_Suspend,
+ XKB_KEY_XF86Hibernate, Qt::Key_Hibernate,
+ XKB_KEY_XF86TouchpadToggle, Qt::Key_TouchpadToggle,
+ XKB_KEY_XF86TouchpadOn, Qt::Key_TouchpadOn,
+ XKB_KEY_XF86TouchpadOff, Qt::Key_TouchpadOff,
+ XKB_KEY_XF86AudioMicMute, Qt::Key_MicMute,
+ XKB_KEY_XF86Launch0, Qt::Key_Launch2, // ### Qt 6: remap properly
+ XKB_KEY_XF86Launch1, Qt::Key_Launch3,
+ XKB_KEY_XF86Launch2, Qt::Key_Launch4,
+ XKB_KEY_XF86Launch3, Qt::Key_Launch5,
+ XKB_KEY_XF86Launch4, Qt::Key_Launch6,
+ XKB_KEY_XF86Launch5, Qt::Key_Launch7,
+ XKB_KEY_XF86Launch6, Qt::Key_Launch8,
+ XKB_KEY_XF86Launch7, Qt::Key_Launch9,
+ XKB_KEY_XF86Launch8, Qt::Key_LaunchA,
+ XKB_KEY_XF86Launch9, Qt::Key_LaunchB,
+ XKB_KEY_XF86LaunchA, Qt::Key_LaunchC,
+ XKB_KEY_XF86LaunchB, Qt::Key_LaunchD,
+ XKB_KEY_XF86LaunchC, Qt::Key_LaunchE,
+ XKB_KEY_XF86LaunchD, Qt::Key_LaunchF,
+ XKB_KEY_XF86LaunchE, Qt::Key_LaunchG,
+ XKB_KEY_XF86LaunchF, Qt::Key_LaunchH,
0, 0
};
@@ -271,10 +499,12 @@ Qt::MouseButton getQtMouseButtonsfromMirPointerEvent(MirPointerEvent const* pev)
if (mir_pointer_event_button_state(pev, mir_pointer_button_secondary))
buttons |= Qt::RightButton;
if (mir_pointer_event_button_state(pev, mir_pointer_button_tertiary))
- buttons |= Qt::MidButton;
+ buttons |= Qt::MiddleButton;
+ if (mir_pointer_event_button_state(pev, mir_pointer_button_back))
+ buttons |= Qt::BackButton;
+ if (mir_pointer_event_button_state(pev, mir_pointer_button_forward))
+ buttons |= Qt::ForwardButton;
- // TODO: Should mir back and forward buttons exist?
- // should they be Qt::X button 1 and 2?
return static_cast<Qt::MouseButton>(buttons);
}
}
diff --git a/tests/modules/Application/CMakeLists.txt b/tests/modules/Application/CMakeLists.txt
index efef3c3..7787d26 100644
--- a/tests/modules/Application/CMakeLists.txt
+++ b/tests/modules/Application/CMakeLists.txt
@@ -1,9 +1,11 @@
set(
APPLICATION_TEST_SOURCES
application_test.cpp
+ ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp
)
include_directories(
+ ${APPLICATION_API_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src/platforms/mirserver
${CMAKE_SOURCE_DIR}/src/modules
${CMAKE_SOURCE_DIR}/tests/modules/common
@@ -18,6 +20,8 @@ target_link_libraries(
unityapplicationplugin
qpa-mirserver
+ Qt5::Test
+
${GTEST_BOTH_LIBRARIES}
${GMOCK_LIBRARIES}
)
diff --git a/tests/modules/Application/application_test.cpp b/tests/modules/Application/application_test.cpp
index b201917..e2b0e19 100644
--- a/tests/modules/Application/application_test.cpp
+++ b/tests/modules/Application/application_test.cpp
@@ -20,6 +20,10 @@
#include "qtmir_test.h"
+#include <mock_session.h>
+
+#include <QScopedPointer>
+#include <QSignalSpy>
using namespace qtmir;
@@ -30,93 +34,163 @@ public:
{}
};
-TEST_F(ApplicationTests, checkFocusAcquiresWakeLock)
+TEST_F(ApplicationTests, acquiresWakelockWhenRunningAndReleasesWhenSuspended)
{
using namespace ::testing;
+ QString appId("foo-app");
- EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
+ auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true));
- startApplication(123, "app");
- applicationManager.focusApplication("app");
-}
+ QScopedPointer<Application> application(new Application(
+ QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
+ desktopFileReader, QStringList(), nullptr));
-TEST_F(ApplicationTests, checkSuspendReleasesWakeLock)
-{
- using namespace ::testing;
+ application->setProcessState(Application::ProcessRunning);
+
+ NiceMock<MockSession> *session = new NiceMock<MockSession>;
+
+ EXPECT_CALL(*session, setApplication(_));
+ EXPECT_CALL(*session, fullscreen()).WillRepeatedly(Return(false));
+
+ application->setSession(session);
+
+ ASSERT_EQ(Application::InternalState::Starting, application->internalState());
+
+ session->setState(SessionInterface::Running);
+
+ EXPECT_TRUE(sharedWakelock.enabled());
- auto app = startApplication(123, "app");
- auto session = app->session();
+ ASSERT_EQ(Application::InternalState::Running, application->internalState());
- applicationManager.focusApplication("app");
+ application->setRequestedState(Application::RequestedSuspended);
+
+ ASSERT_EQ(SessionInterface::Suspending, session->state());
+ ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
+
+ session->setState(SessionInterface::Suspended);
+
+ ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
+
+ application->setProcessState(Application::ProcessSuspended);
+
+ ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
- Q_EMIT session->suspended();
EXPECT_FALSE(sharedWakelock.enabled());
}
TEST_F(ApplicationTests, checkResumeAcquiresWakeLock)
{
using namespace ::testing;
+ QString appId("foo-app");
+
+ auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true));
+
+ QScopedPointer<Application> application(new Application(
+ QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
+ desktopFileReader, QStringList(), nullptr));
+ NiceMock<MockSession> *session = new NiceMock<MockSession>;
+
+ // Get it running and then suspend it
+ application->setProcessState(Application::ProcessRunning);
+ application->setSession(session);
+ session->setState(SessionInterface::Running);
+ application->setRequestedState(Application::RequestedSuspended);
+ session->setState(SessionInterface::Suspended);
+ application->setProcessState(Application::ProcessSuspended);
+ ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
+
+ EXPECT_FALSE(sharedWakelock.enabled());
- EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
+ application->setRequestedState(Application::RequestedRunning);
- auto app = startApplication(123, "app");
- auto session = app->session();
+ ASSERT_EQ(Application::InternalState::Running, application->internalState());
- Q_EMIT session->resumed();
+ EXPECT_TRUE(sharedWakelock.enabled());
}
TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock)
{
using namespace ::testing;
+ QString appId("foo-app");
+
+ auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true));
+
+ QScopedPointer<Application> application(new Application(
+ QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
+ desktopFileReader, QStringList(), nullptr));
+ NiceMock<MockSession> *session = new NiceMock<MockSession>;
+
+ // Get it running, suspend it, and finally stop it
+ application->setProcessState(Application::ProcessRunning);
+ application->setSession(session);
+ session->setState(SessionInterface::Running);
+ application->setRequestedState(Application::RequestedSuspended);
+ session->setState(SessionInterface::Suspended);
+ application->setProcessState(Application::ProcessSuspended);
+ ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
+ session->setState(SessionInterface::Stopped);
+ application->setProcessState(Application::ProcessStopped);
+ ASSERT_EQ(Application::InternalState::StoppedUnexpectedly, application->internalState());
- EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
- const QString appId = "app";
+ EXPECT_FALSE(sharedWakelock.enabled());
- auto app = startApplication(123, "app");
+ QSignalSpy spyStartProcess(application.data(), SIGNAL(startProcessRequested()));
+ application->setRequestedState(Application::RequestedRunning);
+ ASSERT_EQ(1, spyStartProcess.count());
+ application->setProcessState(Application::ProcessRunning);
- // as respawn fires startApplicationWithAppIdAndArgs again, keep gmock quiet about another call
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
- .Times(1)
- .WillRepeatedly(Return(true));
+ ASSERT_EQ(Application::InternalState::Starting, application->internalState());
- // respawn by setting app state as Stopped, delete the Session associated, then set to Running state
- app->setState(Session::State::Stopped);
- delete app->session();
- app->setState(Session::State::Running);
+ EXPECT_TRUE(sharedWakelock.enabled());
}
-TEST_F(ApplicationTests, checkDashFocusDoesNotAcquireWakeLock)
+TEST_F(ApplicationTests, checkDashDoesNotImpactWakeLock)
{
using namespace ::testing;
+ QString appId("unity8-dash");
EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
+ EXPECT_CALL(sharedWakelock, release(_)).Times(0);
- startApplication(123, "unity8-dash");
- applicationManager.focusApplication("unity8-dash");
-}
+ auto desktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*desktopFileReader, loaded()).WillByDefault(Return(true));
-TEST_F(ApplicationTests, checkDashSuspendDoesNotImpactWakeLock)
-{
- using namespace ::testing;
+ QScopedPointer<Application> application(new Application(
+ QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
+ desktopFileReader, QStringList(), nullptr));
- auto app = startApplication(123, "unity8-dash");
- auto session = app->session();
+ application->setProcessState(Application::ProcessRunning);
- applicationManager.focusApplication("unity8-dash");
+ NiceMock<MockSession> *session = new NiceMock<MockSession>;
- Q_EMIT session->suspended();
- EXPECT_FALSE(sharedWakelock.enabled());
-}
+ EXPECT_CALL(*session, setApplication(_));
+ EXPECT_CALL(*session, fullscreen()).WillRepeatedly(Return(false));
-TEST_F(ApplicationTests, checkDashResumeDoesNotAcquireWakeLock)
-{
- using namespace ::testing;
+ application->setSession(session);
- EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
+ ASSERT_EQ(Application::InternalState::Starting, application->internalState());
- auto app = startApplication(123, "unity8-dash");
- auto session = app->session();
+ session->setState(SessionInterface::Running);
- Q_EMIT session->resumed();
-}
+ ASSERT_EQ(Application::InternalState::Running, application->internalState());
+
+ application->setRequestedState(Application::RequestedSuspended);
+
+ ASSERT_EQ(SessionInterface::Suspending, session->state());
+ ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
+
+ session->setState(SessionInterface::Suspended);
+
+ ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
+ application->setProcessState(Application::ProcessSuspended);
+
+ ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
+
+ application->setRequestedState(Application::RequestedRunning);
+
+ ASSERT_EQ(Application::InternalState::Running, application->internalState());
+}
diff --git a/tests/modules/ApplicationManager/CMakeLists.txt b/tests/modules/ApplicationManager/CMakeLists.txt
index 6590576..d90491c 100644
--- a/tests/modules/ApplicationManager/CMakeLists.txt
+++ b/tests/modules/ApplicationManager/CMakeLists.txt
@@ -2,9 +2,12 @@ set(
APPLICATION_MANAGER_TEST_SOURCES
application_manager_test.cpp
${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
+ ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp
+ ../common/fake_mirsurfaceitem.h
)
include_directories(
+ ${APPLICATION_API_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src/platforms/mirserver
${CMAKE_SOURCE_DIR}/src/modules
${CMAKE_SOURCE_DIR}/tests/modules/common
@@ -15,7 +18,7 @@ add_executable(applicationmanager_test ${APPLICATION_MANAGER_TEST_SOURCES})
target_link_libraries(
applicationmanager_test
-
+
qpa-mirserver
unityapplicationplugin
diff --git a/tests/modules/ApplicationManager/application_manager_test.cpp b/tests/modules/ApplicationManager/application_manager_test.cpp
index 751000d..a21a5c8 100644
--- a/tests/modules/ApplicationManager/application_manager_test.cpp
+++ b/tests/modules/ApplicationManager/application_manager_test.cpp
@@ -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
@@ -23,8 +23,9 @@
#include <Unity/Application/applicationscreenshotprovider.h>
- #include "mock_surface.h"
- #include "qtmir_test.h"
+ #include <fake_mirsurfaceitem.h>
+ #include <mock_surface.h>
+ #include <qtmir_test.h>
using namespace qtmir;
using mir::scene::MockSession;
@@ -45,100 +46,41 @@ public:
applicationManager.onSessionStopping(session);
sessionManager.onSessionStopping(session);
}
-};
-
-TEST_F(ApplicationManagerTests, SuspendingAndResumingARunningApplicationResultsInOomScoreAdjustment)
-{
- using namespace ::testing;
-
- const QString appId("com.canonical.does.not.exist");
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(_, _)).Times(1);
- EXPECT_CALL(appController, findDesktopFileForAppId(appId)).Times(1);
-
- EXPECT_CALL(desktopFileReaderFactory, createInstance(_, _)).Times(1);
-
- auto application = applicationManager.startApplication(
- appId,
- ApplicationManager::NoFlag,
- QStringList());
-
- // FIXME - this is doesn't really excerise the actualt behaviour since suspend/resume should be
- // controlled by state changes. Requires using suspend timer.
- QMetaObject::invokeMethod(application, "onSessionSuspended");
- QMetaObject::invokeMethod(application, "onSessionResumed");
-}
-
-TEST_F(ApplicationManagerTests, SuspendingAndResumingDashResultsInOomScoreAdjustment)
-{
- using namespace ::testing;
-
- quint64 procId = 5921;
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
- QByteArray cmdLine( "/usr/bin/app1 --desktop_file_hint=unity8-dash");
-
- EXPECT_CALL(procInfo,command_line(procId))
- .Times(1)
- .WillOnce(Return(cmdLine));
-
- ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
-
- bool authed = true;
-
- std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("Oo", procId);
- applicationManager.authorizeSession(procId, authed);
- onSessionStarting(session);
-
- auto application = applicationManager.findApplication("unity8-dash");
- applicationManager.onSessionCreatedSurface(session.get(), aSurface);
-
- // FIXME - this is doesn't really excerise the actualt behaviour since suspend/resume should be
- // controlled by state changes. Requires using suspend timer.
- QMetaObject::invokeMethod(application, "onSessionSuspended");
- QMetaObject::invokeMethod(application, "onSessionResumed");
-}
-
-// Currently disabled as we need to make sure that we have a corresponding mir session, too.
-TEST_F(ApplicationManagerTests, DISABLED_FocusingRunningApplicationResultsInOomScoreAdjustment)
-{
- using namespace ::testing;
-
- const QString appId("com.canonical.does.not.exist");
-
- QSet<QString> appIds;
-
- for (unsigned int i = 0; i < 50; i++)
- {
- QString appIdFormat("%1.does.not.exist");
- auto appId = appIdFormat.arg(i);
-
- auto application = applicationManager.startApplication(
- appId,
- ApplicationManager::NoFlag,
- QStringList());
-
- std::shared_ptr<mir::scene::Session> mirSession = std::make_shared<MockSession>(appIdFormat.toStdString(), i);
- onSessionStarting( mirSession );
-
- EXPECT_NE(nullptr, application);
+ inline void onSessionCreatedSurface(const mir::scene::Session *mirSession,
+ MirSurfaceItemInterface *qmlSurface) {
+
+ SessionInterface* qmlSession = sessionManager.findSession(mirSession);
+ if (qmlSession) {
+ qmlSession->setSurface(qmlSurface);
+ }
+
+ // I assume that applicationManager ignores the mirSurface parameter, so sending
+ // a null shared pointer must suffice
+ std::shared_ptr<mir::scene::Surface> mirSurface(nullptr);
+ applicationManager.onSessionCreatedSurface(mirSession, mirSurface);
}
- for (auto appId : appIds)
- {
- applicationManager.focusApplication(appId);
+ inline void suspend(Application *application) {
+ application->setRequestedState(Application::RequestedSuspended);
+ ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
+ static_cast<qtmir::Session*>(application->session())->doSuspend();
+ ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
+ applicationManager.onProcessSuspended(application->appId());
+ ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
}
-}
+};
TEST_F(ApplicationManagerTests,bug_case_1240400_second_dialer_app_fails_to_authorize_and_gets_mixed_up_with_first_one)
{
using namespace ::testing;
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
quint64 firstProcId = 5921;
quint64 secondProcId = 5922;
const char dialer_app_id[] = "dialer-app";
QByteArray cmdLine( "/usr/bin/dialer-app --desktop_file_hint=dialer-app");
QByteArray secondcmdLine( "/usr/bin/dialer-app");
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+
EXPECT_CALL(procInfo,command_line(firstProcId))
.Times(1)
.WillOnce(Return(cmdLine));
@@ -150,18 +92,20 @@ TEST_F(ApplicationManagerTests,bug_case_1240400_second_dialer_app_fails_to_autho
std::shared_ptr<mir::scene::Session> mirSession = std::make_shared<MockSession>(dialer_app_id, firstProcId);
applicationManager.authorizeSession(firstProcId, authed);
- EXPECT_EQ(true, authed);
+ ASSERT_EQ(true, authed);
onSessionStarting(mirSession);
- applicationManager.onSessionCreatedSurface(mirSession.get(),aSurface);
- Application * app = applicationManager.findApplication(dialer_app_id);
- EXPECT_NE(nullptr,app);
+ onSessionCreatedSurface(mirSession.get(), surface);
+ surface->drawFirstFrame();
+ Application * application = applicationManager.findApplication(dialer_app_id);
+ ASSERT_NE(nullptr,application);
+ ASSERT_EQ(Application::InternalState::Running, application->internalState());
// now a second session without desktop file is launched:
applicationManager.authorizeSession(secondProcId, authed);
applicationManager.onProcessStarting(dialer_app_id);
EXPECT_FALSE(authed);
- EXPECT_EQ(app,applicationManager.findApplication(dialer_app_id));
+ EXPECT_EQ(application, applicationManager.findApplication(dialer_app_id));
}
TEST_F(ApplicationManagerTests,application_dies_while_starting)
@@ -182,6 +126,7 @@ TEST_F(ApplicationManagerTests,application_dies_while_starting)
onSessionStarting(mirSession);
Application * beforeFailure = applicationManager.findApplication(app_id);
applicationManager.onProcessStarting(app_id);
+ onSessionStopping(mirSession);
applicationManager.onProcessFailed(app_id, true);
Application * afterFailure = applicationManager.findApplication(app_id);
@@ -190,34 +135,6 @@ TEST_F(ApplicationManagerTests,application_dies_while_starting)
EXPECT_EQ(nullptr, afterFailure);
}
-TEST_F(ApplicationManagerTests,application_start_failure_after_starting)
-{
- using namespace ::testing;
- quint64 procId = 5921;
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
- const char app_id[] = "my-app";
- QByteArray cmdLine( "/usr/bin/my-app --desktop_file_hint=my-app");
-
- EXPECT_CALL(procInfo,command_line(procId))
- .Times(1)
- .WillOnce(Return(cmdLine));
-
- bool authed = true;
-
- std::shared_ptr<mir::scene::Session> mirSession = std::make_shared<MockSession>(app_id, procId);
- applicationManager.authorizeSession(procId, authed);
- onSessionStarting(mirSession);
- Application * beforeFailure = applicationManager.findApplication(app_id);
- applicationManager.onSessionCreatedSurface(mirSession.get(), aSurface);
- applicationManager.onProcessStarting(app_id);
- applicationManager.onProcessFailed(app_id, false);
- Application * afterFailure = applicationManager.findApplication(app_id);
-
- EXPECT_EQ(true, authed);
- EXPECT_NE(nullptr, beforeFailure);
- EXPECT_EQ(beforeFailure, afterFailure);
-}
-
TEST_F(ApplicationManagerTests,startApplicationSupportsShortAppId)
{
using namespace ::testing;
@@ -400,7 +317,7 @@ TEST_F(ApplicationManagerTests,two_session_on_one_application_after_starting)
quint64 a_procId = 5921;
const char an_app_id[] = "some_app";
QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app");
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
+ FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem;
ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd));
@@ -413,8 +330,8 @@ TEST_F(ApplicationManagerTests,two_session_on_one_application_after_starting)
applicationManager.authorizeSession(a_procId, authed);
onSessionStarting(first_session);
- applicationManager.focusApplication(an_app_id);
- applicationManager.onSessionCreatedSurface(first_session.get(), aSurface);
+ onSessionCreatedSurface(first_session.get(), aSurface);
+ aSurface->drawFirstFrame();
onSessionStarting(second_session);
Application * the_app = applicationManager.findApplication(an_app_id);
@@ -430,18 +347,19 @@ TEST_F(ApplicationManagerTests, focused_app_can_rerequest_focus)
quint64 a_procId = 5921;
const char an_app_id[] = "some_app";
QByteArray a_cmd("/usr/bin/app1 --desktop_file_hint=some_app");
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
+ FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem;
ON_CALL(procInfo, command_line(_)).WillByDefault(Return(a_cmd));
ON_CALL(appController, appIdHasProcessId(_,_)).WillByDefault(Return(false));
-
+
bool authed = true;
std::shared_ptr<mir::scene::Session> a_session = std::make_shared<MockSession>("Oo", a_procId);
-
+
applicationManager.authorizeSession(a_procId, authed);
onSessionStarting(a_session);
- applicationManager.onSessionCreatedSurface(a_session.get(), aSurface);
+ onSessionCreatedSurface(a_session.get(), aSurface);
+ aSurface->drawFirstFrame();
Application * the_app = applicationManager.findApplication(an_app_id);
applicationManager.focusApplication(an_app_id);
@@ -453,188 +371,38 @@ TEST_F(ApplicationManagerTests, focused_app_can_rerequest_focus)
EXPECT_EQ(true, the_app->focused());
}
-TEST_F(ApplicationManagerTests,suspended_suspends_focused_app_and_marks_it_unfocused_in_the_model)
+TEST_F(ApplicationManagerTests,starting_app_is_suspended_when_it_gets_ready_if_requested)
{
using namespace ::testing;
- quint64 a_procId = 5921;
- const char an_app_id[] = "some_app";
- QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app");
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
-
- ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd));
-
- ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
-
- bool authed = true;
-
- std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", a_procId);
- std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", a_procId);
- applicationManager.authorizeSession(a_procId, authed);
-
- onSessionStarting(first_session);
- applicationManager.onSessionCreatedSurface(first_session.get(), aSurface);
- onSessionStarting(second_session);
-
- Application * the_app = applicationManager.findApplication(an_app_id);
- applicationManager.focusApplication(an_app_id);
-
- EXPECT_EQ(Application::Running, the_app->state());
-
- applicationManager.setSuspended(true);
-
- EXPECT_EQ(Application::Suspended, the_app->state());
- EXPECT_FALSE(the_app->focused());
-
- applicationManager.setSuspended(false);
-
- EXPECT_EQ(Application::Running, the_app->state());
- EXPECT_EQ(true, the_app->focused());
-}
-
-TEST_F(ApplicationManagerTests,suspended_suspends_starting_app_when_it_gets_ready)
-{
- using namespace ::testing;
- quint64 a_procId = 5921;
- const char an_app_id[] = "some_app";
- QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app");
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
-
- ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd));
-
- ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
-
- bool authed = true;
-
- std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", a_procId);
- applicationManager.authorizeSession(a_procId, authed);
-
- onSessionStarting(first_session);
-
- Application * the_app = applicationManager.findApplication(an_app_id);
- applicationManager.focusApplication(an_app_id);
- EXPECT_EQ(Application::Starting, the_app->state());
-
- applicationManager.setSuspended(true);
-
- // Not suspending yet, as it's still starting
- EXPECT_EQ(Application::Starting, the_app->state());
-
- // This signals the app is ready now
- applicationManager.onSessionCreatedSurface(first_session.get(), aSurface);
-
- // And given that the AppManager is suspended now, this should go to suspended too
- EXPECT_EQ(Application::Suspended, the_app->state());
- EXPECT_FALSE(the_app->focused());
-
- applicationManager.setSuspended(false);
-
- EXPECT_EQ(Application::Running, the_app->state());
- EXPECT_EQ(true, the_app->focused());
-}
-
-TEST_F(ApplicationManagerTests,focus_change_suspends_starting_app_when_it_gets_ready)
-{
- using namespace ::testing;
- quint64 first_procId = 5921;
- quint64 second_procId = 5922;
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
- QByteArray first_cmdLine( "/usr/bin/app1 --desktop_file_hint=app1");
- QByteArray second_cmdLine( "/usr/bin/app2--desktop_file_hint=app2");
+ quint64 procId = 5921;
+ FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem;
+ QByteArray cmdLine( "/usr/bin/app --desktop_file_hint=app");
- EXPECT_CALL(procInfo,command_line(first_procId))
+ EXPECT_CALL(procInfo,command_line(procId))
.Times(1)
- .WillOnce(Return(first_cmdLine));
+ .WillOnce(Return(cmdLine));
ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
- EXPECT_CALL(procInfo,command_line(second_procId))
- .Times(1)
- .WillOnce(Return(second_cmdLine));
-
bool authed = true;
- std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", first_procId);
- std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", second_procId);
- applicationManager.authorizeSession(first_procId, authed);
- applicationManager.authorizeSession(second_procId, authed);
- onSessionStarting(first_session);
+ std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("Oo", procId);
+ applicationManager.authorizeSession(procId, authed);
+ onSessionStarting(session);
- Application * app1 = applicationManager.findApplication("app1");
- applicationManager.focusApplication("app1");
+ Application * app = applicationManager.findApplication("app");
+ app->setRequestedState(Application::RequestedSuspended);
// First app starting...
- EXPECT_EQ(Application::Starting, app1->state());
+ EXPECT_EQ(Application::Starting, app->state());
- onSessionStarting(second_session);
- Application * app2 = applicationManager.findApplication("app2");
- applicationManager.focusApplication("app2");
-
- // Second app starting...
- EXPECT_EQ(Application::Starting, app2->state());
-
- // Make sure first one is still in starting state
- EXPECT_EQ(Application::Starting, app1->state());
-
- // Signal app1 is ready now
- applicationManager.onSessionCreatedSurface(first_session.get(), aSurface);
+ // Signal app is ready now
+ applicationManager.onProcessStarting("app");
+ onSessionCreatedSurface(session.get(), aSurface);
+ aSurface->drawFirstFrame();
- // Make sure AppMan suspended it now that its ready
- EXPECT_EQ(Application::Suspended, app1->state());
-}
-
-TEST_F(ApplicationManagerTests,forceDashActive_activates_dash_while_not_focused)
-{
- using namespace ::testing;
- quint64 first_procId = 5921;
- quint64 second_procId = 5922;
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
- QByteArray first_cmdLine( "/usr/bin/app1 --desktop_file_hint=unity8-dash");
- QByteArray second_cmdLine( "/usr/bin/app2--desktop_file_hint=app2");
-
- EXPECT_CALL(procInfo,command_line(first_procId))
- .Times(1)
- .WillOnce(Return(first_cmdLine));
-
- ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
-
- EXPECT_CALL(procInfo,command_line(second_procId))
- .Times(1)
- .WillOnce(Return(second_cmdLine));
-
- bool authed = true;
-
- std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", first_procId);
- std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", second_procId);
- applicationManager.authorizeSession(first_procId, authed);
- applicationManager.authorizeSession(second_procId, authed);
- onSessionStarting(first_session);
-
- Application * dashApp = applicationManager.findApplication("unity8-dash");
- applicationManager.onSessionCreatedSurface(first_session.get(), aSurface);
- applicationManager.focusApplication("unity8-dash");
-
- // Dash app should be ready now...
- EXPECT_EQ(Application::Running, dashApp->state());
-
- // Launch second app
- onSessionStarting(second_session);
- applicationManager.onSessionCreatedSurface(second_session.get(), aSurface);
- applicationManager.focusApplication("app2");
- EXPECT_EQ(applicationManager.focusedApplicationId(), "app2");
-
- // Make sure the dash is suspended
- EXPECT_EQ(dashApp->state(), Application::Suspended);
-
- // Now set the dashactive flag
- applicationManager.setForceDashActive(true);
-
- // And make sure the dash is woken up but not focused
- EXPECT_EQ(applicationManager.focusedApplicationId(), "app2");
- EXPECT_EQ(dashApp->state(), Application::Running);
-
- // Unset the dashactive flag
- applicationManager.setForceDashActive(false);
- EXPECT_EQ(dashApp->state(), Application::Suspended);
+ // now that its ready, suspend process should have begun
+ EXPECT_EQ(Application::InternalState::SuspendingWaitSession, app->internalState());
}
TEST_F(ApplicationManagerTests,requestFocusApplication)
@@ -713,20 +481,20 @@ TEST_F(ApplicationManagerTests,appStartedByShell)
Application *theApp = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
// check application data
- EXPECT_EQ(theApp->state(), Application::Starting);
- EXPECT_EQ(theApp->appId(), appId);
- EXPECT_EQ(theApp->name(), name);
- EXPECT_EQ(theApp->canBeResumed(), true);
+ EXPECT_EQ(Application::Starting, theApp->state());
+ EXPECT_EQ(appId, theApp->appId());
+ EXPECT_EQ(name, theApp->name());
+ EXPECT_FALSE(theApp->canBeResumed());
// check signals were emitted
- EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback)
- EXPECT_EQ(applicationManager.count(), 1);
- EXPECT_EQ(addedSpy.count(), 1);
- EXPECT_EQ(addedSpy.takeFirst().at(0).toString(), appId);
+ EXPECT_EQ(2, countSpy.count()); //FIXME(greyback)
+ EXPECT_EQ(1, applicationManager.count());
+ EXPECT_EQ(1, addedSpy.count());
+ EXPECT_EQ(appId, addedSpy.takeFirst().at(0).toString());
// check application in list of apps
Application *theAppAgain = applicationManager.findApplication(appId);
- EXPECT_EQ(theAppAgain, theApp);
+ EXPECT_EQ(theApp, theAppAgain);
}
/*
@@ -757,18 +525,18 @@ TEST_F(ApplicationManagerTests,appStartedByUpstart)
Application *theApp = applicationManager.findApplication(appId);
// check application data
- EXPECT_EQ(theApp->state(), Application::Starting);
- EXPECT_EQ(theApp->appId(), appId);
- EXPECT_EQ(theApp->name(), name);
- EXPECT_EQ(theApp->canBeResumed(), true);
+ EXPECT_EQ(Application::Starting, theApp->state());
+ EXPECT_EQ(appId, theApp->appId());
+ EXPECT_EQ(name, theApp->name());
+ EXPECT_EQ(true, theApp->canBeResumed());
// check signals were emitted
- EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback)
- EXPECT_EQ(applicationManager.count(), 1);
- EXPECT_EQ(addedSpy.count(), 1);
- EXPECT_EQ(addedSpy.takeFirst().at(0).toString(), appId);
- EXPECT_EQ(focusSpy.count(), 1);
- EXPECT_EQ(focusSpy.takeFirst().at(0).toString(), appId);
+ EXPECT_EQ(2, countSpy.count()); //FIXME(greyback)
+ EXPECT_EQ(1, applicationManager.count());
+ EXPECT_EQ(1, addedSpy.count());
+ EXPECT_EQ(appId, addedSpy.takeFirst().at(0).toString());
+ EXPECT_EQ(1, focusSpy.count());
+ EXPECT_EQ(appId, focusSpy.takeFirst().at(0).toString());
}
/*
@@ -1067,7 +835,6 @@ TEST_F(ApplicationManagerTests,onceAppAddedToApplicationLists_mirSurfaceCreatedE
applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
- applicationManager.focusApplication(appId);
std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
@@ -1075,9 +842,10 @@ TEST_F(ApplicationManagerTests,onceAppAddedToApplicationLists_mirSurfaceCreatedE
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
- applicationManager.onSessionCreatedSurface(session.get(), surface);
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
// Check application state is correctly set
Application *theApp = applicationManager.findApplication(appId);
@@ -1124,7 +892,7 @@ TEST_F(ApplicationManagerTests,shellStopsAppCorrectlyBeforeSurfaceCreated)
}
/*
- * Test that the foreground application is stopped correctly (is in Running state, has surface)
+ * Test that a running application is stopped correctly (is in Running state, has surface)
*/
TEST_F(ApplicationManagerTests,shellStopsForegroundAppCorrectly)
{
@@ -1150,10 +918,9 @@ TEST_F(ApplicationManagerTests,shellStopsForegroundAppCorrectly)
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- EXPECT_EQ(applicationManager.focusedApplicationId(), appId);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1168,9 +935,9 @@ TEST_F(ApplicationManagerTests,shellStopsForegroundAppCorrectly)
}
/*
- * Test that the background application is stopped correctly
+ * Test that a suspended application is stopped correctly
*/
-TEST_F(ApplicationManagerTests,shellStopsBackgroundAppCorrectly)
+TEST_F(ApplicationManagerTests,shellStopsSuspendedAppCorrectly)
{
using namespace ::testing;
const QString appId("testAppId");
@@ -1187,18 +954,19 @@ TEST_F(ApplicationManagerTests,shellStopsBackgroundAppCorrectly)
.Times(1)
.WillOnce(Return(true));
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ Application *application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
bool authed = true;
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
+ applicationManager.onProcessStarting(appId);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.unfocusCurrentApplication();
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
+ suspend(application);
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1213,45 +981,6 @@ TEST_F(ApplicationManagerTests,shellStopsBackgroundAppCorrectly)
}
/*
- * Test that if an application is stopped by upstart, before it has created a surface, AppMan cleans up after it ok
- */
-TEST_F(ApplicationManagerTests,upstartNotificationOfStartingAppBeingStopped)
-{
- using namespace ::testing;
- const QString appId("testAppId");
- quint64 procId = 5551;
-
- // Set up Mocks & signal watcher
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
-
- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
- .Times(1)
- .WillOnce(Return(true));
-
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
- applicationManager.onProcessStarting(appId);
- std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
- bool authed = true;
- applicationManager.authorizeSession(procId, authed);
- onSessionStarting(session);
-
- QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
- QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
-
- // Upstart notifies of stopping app
- applicationManager.onProcessStopped(appId);
-
- EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback)
- EXPECT_EQ(applicationManager.count(), 0);
- EXPECT_EQ(removedSpy.count(), 1);
- EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId);
-}
-
-/*
* Test that if the foreground Running application is stopped by upstart, AppMan cleans up after it ok
*/
TEST_F(ApplicationManagerTests,upstartNotifiesOfStoppingForegroundApp)
@@ -1278,28 +1007,28 @@ TEST_F(ApplicationManagerTests,upstartNotifiesOfStoppingForegroundApp)
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- EXPECT_EQ(applicationManager.focusedApplicationId(), appId);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
+ onSessionStopping(session);
// Upstart notifies of stopping app
applicationManager.onProcessStopped(appId);
- EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback)
- EXPECT_EQ(applicationManager.count(), 0);
- EXPECT_EQ(removedSpy.count(), 1);
- EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId);
+ EXPECT_EQ(2, countSpy.count()); //FIXME(greyback)
+ EXPECT_EQ(0, applicationManager.count());
+ EXPECT_EQ(1, removedSpy.count());
+ EXPECT_EQ(appId, removedSpy.takeFirst().at(0).toString());
}
/*
- * Test that if the foreground Running application is reported to unexpectedly stop by upstart, AppMan
- * cleans up after it ok (as was not in background, had not lifecycle saved its state, so cannot be resumed)
+ * Test that if a running application is reported to have stopped unexpectedly by upstart, AppMan
+ * cleans up after it ok (as was not suspended, had not lifecycle saved its state, so cannot be resumed)
*/
-TEST_F(ApplicationManagerTests,upstartNotifiesOfUnexpectedStopOfForegroundApp)
+TEST_F(ApplicationManagerTests,upstartNotifiesOfUnexpectedStopOfRunningApp)
{
using namespace ::testing;
const QString appId("testAppId");
@@ -1323,14 +1052,15 @@ TEST_F(ApplicationManagerTests,upstartNotifiesOfUnexpectedStopOfForegroundApp)
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- EXPECT_EQ(applicationManager.focusedApplicationId(), appId);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
+ onSessionStopping(session);
+
// Upstart notifies of crashing / OOM killed app
applicationManager.onProcessFailed(appId, false);
@@ -1344,53 +1074,6 @@ TEST_F(ApplicationManagerTests,upstartNotifiesOfUnexpectedStopOfForegroundApp)
}
/*
- * Test that if a background application is stopped by upstart, AppMan removes it from the app list
- * as the event is a result of direct user interaction
- */
-TEST_F(ApplicationManagerTests,upstartNotifiesOfStoppingBackgroundApp)
-{
- using namespace ::testing;
- const QString appId("testAppId");
- quint64 procId = 5551;
-
- // Set up Mocks & signal watcher
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
-
- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
- .Times(1)
- .WillOnce(Return(true));
-
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
- applicationManager.onProcessStarting(appId);
- std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
- bool authed = true;
- applicationManager.authorizeSession(procId, authed);
- onSessionStarting(session);
-
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.unfocusCurrentApplication();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
-
- QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
- QSignalSpy focusSpy(&applicationManager, SIGNAL(focusedApplicationIdChanged()));
- QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
-
- // Upstart notifies of stopping app
- applicationManager.onProcessStopped(appId);
-
- EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback)
- EXPECT_EQ(applicationManager.count(), 0);
- EXPECT_EQ(focusSpy.count(), 0);
- EXPECT_EQ(removedSpy.count(), 1);
- EXPECT_EQ(removedSpy.takeFirst().at(0).toString(), appId);
-}
-
-/*
* Test that if a background application is reported to unexpectedly stop by upstart, AppMan does not remove
* it from the app lists but instead considers it Stopped, ready to be resumed. This is due to the fact the
* app should have saved its state, so can be resumed. This situation can occur due to the OOM killer, or
@@ -1413,18 +1096,18 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfBackgroundApp)
.Times(1)
.WillOnce(Return(true));
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
bool authed = true;
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- applicationManager.unfocusCurrentApplication();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
+
+ suspend(app);
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy focusSpy(&applicationManager, SIGNAL(focusedApplicationIdChanged()));
@@ -1436,14 +1119,14 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfBackgroundApp)
// Upstart notifies of crashing / OOM-killed app
applicationManager.onProcessFailed(appId, false);
- EXPECT_EQ(focusSpy.count(), 0);
+ EXPECT_EQ(0, focusSpy.count());
// Upstart finally notifies the app stopped
applicationManager.onProcessStopped(appId);
- EXPECT_EQ(countSpy.count(), 0);
- EXPECT_EQ(applicationManager.count(), 1);
- EXPECT_EQ(removedSpy.count(), 0);
+ EXPECT_EQ(0, countSpy.count());
+ EXPECT_EQ(1, applicationManager.count());
+ EXPECT_EQ(0, removedSpy.count());
}
/*
@@ -1471,18 +1154,18 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfBackgroundAppCheckingUpstartBug)
.Times(1)
.WillOnce(Return(true));
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
bool authed = true;
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- applicationManager.unfocusCurrentApplication();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
+
+ suspend(app);
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy focusSpy(&applicationManager, SIGNAL(focusedApplicationIdChanged()));
@@ -1571,10 +1254,9 @@ TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingForegroundApp)
onSessionStarting(session);
// Associate a surface so AppMan considers app Running, check focused
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- EXPECT_EQ(applicationManager.focusedApplicationId(), appId);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1589,10 +1271,10 @@ TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingForegroundApp)
}
/*
- * Test that if a foreground application (one launched via desktop_file_hint) is reported to be stopping by
+ * Test that if an application (one launched via desktop_file_hint) is reported to be stopping by
* Mir, AppMan removes it from the model immediately
*/
-TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingForegroundAppLaunchedWithDesktopFileHint)
+TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingAppLaunchedWithDesktopFileHint)
{
using namespace ::testing;
const QString appId("testAppId");
@@ -1621,10 +1303,9 @@ TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingForegroundAppLaunchedWithDes
onSessionStarting(session);
// Associate a surface so AppMan considers app Running, check focused
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- EXPECT_EQ(applicationManager.focusedApplicationId(), appId);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1661,73 +1342,31 @@ TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingBackgroundApp)
.Times(1)
.WillOnce(Return(true));
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
bool authed = true;
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
+ EXPECT_EQ(Application::Starting, app->state());
- // Associate a surface so AppMan considers app Running, check in background
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- applicationManager.unfocusCurrentApplication();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
-
- QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
- QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
-
- // Mir notifies of stopping app
- onSessionStopping(session);
-
- EXPECT_EQ(countSpy.count(), 0);
- EXPECT_EQ(applicationManager.count(), 1);
- EXPECT_EQ(removedSpy.count(), 0);
-
- Application * app = applicationManager.findApplication(appId);
- EXPECT_NE(nullptr,app);
- EXPECT_EQ(app->state(), Application::Stopped);
-}
+ app->setRequestedState(Application::RequestedSuspended);
-/*
- * Test that if a background application (one launched via desktop_file_hint) is reported to be stopping by
- * Mir, AppMan removes it from the model immediately
- */
-TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingBackgroundAppLaunchedWithDesktopFileHint)
-{
- using namespace ::testing;
- const QString appId("testAppId");
- const QString name("Test App");
- quint64 procId = 5551;
- QByteArray cmdLine("/usr/bin/testApp --desktop_file_hint=");
- cmdLine = cmdLine.append(appId);
-
- // Set up Mocks & signal watcher
- EXPECT_CALL(procInfo,command_line(procId))
- .Times(1)
- .WillOnce(Return(cmdLine));
+ // should not suspend an app that`s still starting up
+ ASSERT_EQ(Application::InternalState::Starting, app->internalState());
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
- ON_CALL(*mockDesktopFileReader, name()).WillByDefault(Return(name));
+ // Associate a surface so AppMan considers app Running
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
+ ASSERT_EQ(Application::InternalState::SuspendingWaitSession, app->internalState());
- // Mir requests authentication for an application that was started
- bool authed = true;
- applicationManager.authorizeSession(procId, authed);
- EXPECT_EQ(authed, true);
- std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
- onSessionStarting(session);
+ static_cast<qtmir::Session*>(app->session())->doSuspend();
+ ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, app->internalState());
- // Associate a surface so AppMan considers app Running, check in background
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- applicationManager.unfocusCurrentApplication();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
+ applicationManager.onProcessSuspended(app->appId());
+ ASSERT_EQ(Application::InternalState::Suspended, app->internalState());
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1735,12 +1374,11 @@ TEST_F(ApplicationManagerTests,mirNotifiesOfStoppingBackgroundAppLaunchedWithDes
// Mir notifies of stopping app
onSessionStopping(session);
- EXPECT_EQ(countSpy.count(), 2); //FIXME(greyback)
- EXPECT_EQ(applicationManager.count(), 0);
- EXPECT_EQ(removedSpy.count(), 1);
+ EXPECT_EQ(0, countSpy.count());
+ EXPECT_EQ(1, applicationManager.count());
+ EXPECT_EQ(0, removedSpy.count());
- Application * app = applicationManager.findApplication(appId);
- EXPECT_EQ(nullptr,app);
+ EXPECT_EQ(Application::Stopped, app->state());
}
/*
@@ -1822,45 +1460,6 @@ TEST_F(ApplicationManagerTests,shellStoppedApp_mirSessionStoppingEventIgnored)
}
/*
- * Test that if an application is stopped by upstart, the Mir stopping event is ignored
- */
-TEST_F(ApplicationManagerTests,appStoppedByUpstart_mirSessionStoppingEventIgnored)
-{
- using namespace ::testing;
- const QString appId("testAppId");
- quint64 procId = 5551;
-
- // Set up Mocks & signal watcher
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
-
- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
- .Times(1)
- .WillOnce(Return(true));
-
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
- applicationManager.onProcessStarting(appId);
- std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
- bool authed = true;
- applicationManager.authorizeSession(procId, authed);
- onSessionStarting(session);
-
- applicationManager.onProcessStopped(appId);
-
- QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
- QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
-
- // Mir notifies of stopping app
- onSessionStopping(session);
-
- EXPECT_EQ(countSpy.count(), 0);
- EXPECT_EQ(removedSpy.count(), 0);
-}
-
-/*
* Webapps have multiple sessions, but only one is linked to the application (other is considered a hidden session).
* If webapp in foreground stops unexpectedly, remove it and it alone from app list
*/
@@ -1903,8 +1502,9 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfForegroundWebapp)
applicationManager.authorizeSession(procId2, authed);
onSessionStarting(session2);
EXPECT_EQ(authed, true);
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session2.get(), surface);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session2.get(), surface);
+ surface->drawFirstFrame();
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1950,7 +1550,7 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfBackgroundWebapp)
.Times(1)
.WillOnce(Return(true));
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> session1 = std::make_shared<MockSession>("", procId1);
std::shared_ptr<mir::scene::Session> session2 = std::make_shared<MockSession>("", procId2);
@@ -1958,19 +1558,20 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfBackgroundWebapp)
bool authed = false;
applicationManager.authorizeSession(procId1, authed);
onSessionStarting(session1);
- EXPECT_EQ(authed, true);
+ EXPECT_EQ(true, authed);
applicationManager.authorizeSession(procId2, authed);
onSessionStarting(session2);
- EXPECT_EQ(authed, true);
+ EXPECT_EQ(true, authed);
- // both sessions create surfaces, then unfocus everything.
- std::shared_ptr<mir::scene::Surface> surface1(nullptr);
- applicationManager.onSessionCreatedSurface(session1.get(), surface1);
- std::shared_ptr<mir::scene::Surface> surface2(nullptr);
- applicationManager.onSessionCreatedSurface(session2.get(), surface2);
- applicationManager.focusApplication(appId);
- applicationManager.unfocusCurrentApplication();
- EXPECT_EQ(applicationManager.focusedApplicationId(), QString());
+ // both sessions create surfaces, then get them all suspended
+ FakeMirSurfaceItem *surface1 = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session1.get(), surface1);
+ surface1->drawFirstFrame();
+ FakeMirSurfaceItem *surface2 = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session2.get(), surface2);
+ surface2->drawFirstFrame();
+ suspend(app);
+ EXPECT_EQ(Application::Suspended, app->state());
QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged()));
QSignalSpy removedSpy(&applicationManager, SIGNAL(applicationRemoved(const QString &)));
@@ -1979,8 +1580,8 @@ TEST_F(ApplicationManagerTests,unexpectedStopOfBackgroundWebapp)
onSessionStopping(session2);
onSessionStopping(session1);
- EXPECT_EQ(countSpy.count(), 0);
- EXPECT_EQ(removedSpy.count(), 0);
+ EXPECT_EQ(0, countSpy.count());
+ EXPECT_EQ(0, removedSpy.count());
}
/*
@@ -2007,34 +1608,33 @@ TEST_F(ApplicationManagerTests,stoppedBackgroundAppRelaunchedByUpstart)
.Times(1)
.WillOnce(Return(true));
- applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ Application *app = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
bool authed = true;
applicationManager.authorizeSession(procId, authed);
onSessionStarting(session);
- // App creates surface, focuses it, puts it in background, then is OOM killed.
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
- applicationManager.unfocusCurrentApplication();
+ // App creates surface, puts it in background, then is OOM killed.
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
+ suspend(app);
onSessionStopping(session);
applicationManager.onProcessFailed(appId, false);
applicationManager.onProcessStopped(appId);
- Application *app = applicationManager.findApplication(appId);
- EXPECT_EQ(app->state(), Application::Stopped);
+ EXPECT_EQ(Application::Stopped, app->state());
QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &)));
// Upstart re-launches app
applicationManager.onProcessStarting(appId);
- EXPECT_EQ(app->state(), Application::Starting);
- EXPECT_EQ(focusRequestSpy.count(), 1);
- EXPECT_EQ(applicationManager.count(), 1);
+ EXPECT_EQ(Application::Starting, app->state());
+ EXPECT_EQ(1, focusRequestSpy.count());
+ EXPECT_EQ(1, applicationManager.count());
}
/*
@@ -2138,142 +1738,61 @@ TEST_F(ApplicationManagerTests, threadedScreenshotAfterAppDelete)
}
}
-/*
- 1 - launch and focus a main stage app
- * main stage app is running and focused
- 2 - launch and focus a side stage app
- * main stage app is running but is not focused
- * side stage app is running and has focus
- 3 - focus the main stage app
- * main stage app is running and has focus
- * side stage app is running but is not focused
-
- This is a regression test for the bug where on step 3, the main stage app was momentarily
- suspended and then resumed again.
- */
-TEST_F(ApplicationManagerTests, focusMainStageAfterSideStage)
-{
- using namespace testing;
-
- QString webbrowserAppId("webbrowser-app");
- quint64 webbrowserPID = 123;
- std::shared_ptr<mir::scene::Surface> webbrowserSurface(nullptr);
-
- QString dialerAppId("dialer-app");
- quint64 dialerPID = 456;
- std::shared_ptr<mir::scene::Surface> dialerSurface(nullptr);
-
- /*** Start webbrowser-app (main stage) ***/
-
- ON_CALL(appController,appIdHasProcessId(webbrowserPID, webbrowserAppId)).WillByDefault(Return(true));
-
- {
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(webbrowserAppId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(webbrowserAppId));
- ON_CALL(*mockDesktopFileReader, stageHint()).WillByDefault(Return("MainStage"));
-
- ON_CALL(desktopFileReaderFactory, createInstance(webbrowserAppId, _))
- .WillByDefault(Return(mockDesktopFileReader));
- }
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(webbrowserAppId, _))
- .Times(1)
- .WillOnce(Return(true));
-
- /*auto application =*/ applicationManager.startApplication(webbrowserAppId, ApplicationManager::NoFlag);
- applicationManager.onProcessStarting(webbrowserAppId);
-
- {
- bool authed = false;
- applicationManager.authorizeSession(webbrowserPID, authed);
- EXPECT_EQ(authed, true);
- }
-
- auto webbrowserSession = std::make_shared<mir::scene::MockSession>(webbrowserAppId.toStdString(), webbrowserPID);
- sessionManager.onSessionStarting(webbrowserSession);
- applicationManager.focusApplication(webbrowserAppId);
- applicationManager.onSessionCreatedSurface(webbrowserSession.get(), webbrowserSurface);
-
- /*** Start dialer-app (side stage) ***/
-
- ON_CALL(appController, appIdHasProcessId(dialerPID, dialerAppId)).WillByDefault(Return(true));
-
- {
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(dialerAppId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(dialerAppId));
- ON_CALL(*mockDesktopFileReader, stageHint()).WillByDefault(Return("SideStage"));
-
- ON_CALL(desktopFileReaderFactory, createInstance(dialerAppId, _))
- .WillByDefault(Return(mockDesktopFileReader));
- }
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(dialerAppId, _))
- .Times(1)
- .WillOnce(Return(true));
-
- /*auto application =*/ applicationManager.startApplication(dialerAppId, ApplicationManager::NoFlag);
- applicationManager.onProcessStarting(dialerAppId);
-
- {
- bool authed = false;
- applicationManager.authorizeSession(dialerPID, authed);
- EXPECT_EQ(authed, true);
- }
-
- auto dialerSession = std::make_shared<mir::scene::MockSession>(dialerAppId.toStdString(), dialerPID);
- sessionManager.onSessionStarting(dialerSession);
- applicationManager.focusApplication(dialerAppId);
- applicationManager.onSessionCreatedSurface(dialerSession.get(), dialerSurface);
-
- /*** Focus webbrowser ***/
-
- // Nothing should happen as it's already the running main stage app
- EXPECT_CALL(*webbrowserSession.get(), set_lifecycle_state(_))
- .Times(0);
- applicationManager.focusApplication(webbrowserAppId);
-}
-
TEST_F(ApplicationManagerTests,lifecycle_exempt_appId_is_not_suspended)
{
using namespace ::testing;
quint64 a_procId = 5921;
- const char an_app_id[] = "some_app";
- QByteArray a_cmd( "/usr/bin/app1 --desktop_file_hint=some_app");
- std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
+ const QString appId("some_app");
+ QByteArray a_cmd("/usr/bin/app1");
ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd));
- ON_CALL(appController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
+ ON_CALL(appController,appIdHasProcessId(a_procId, appId)).WillByDefault(Return(true));
- bool authed = true;
+ // Set up Mocks & signal watcher
+ auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
+ ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
+
+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
+
+
+ Application *the_app = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ applicationManager.onProcessStarting(appId);
std::shared_ptr<mir::scene::Session> first_session = std::make_shared<MockSession>("Oo", a_procId);
std::shared_ptr<mir::scene::Session> second_session = std::make_shared<MockSession>("oO", a_procId);
- applicationManager.authorizeSession(a_procId, authed);
+ {
+ bool authed = false;
+ applicationManager.authorizeSession(a_procId, authed);
+ ASSERT_EQ(authed, true);
+ }
onSessionStarting(first_session);
- applicationManager.onSessionCreatedSurface(first_session.get(), aSurface);
+ FakeMirSurfaceItem *aSurface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(first_session.get(), aSurface);
+ aSurface->drawFirstFrame();
onSessionStarting(second_session);
- Application * the_app = applicationManager.findApplication(an_app_id);
- applicationManager.focusApplication(an_app_id);
-
// Add to other apps to the list (Not "some_app")
QVariantList lifecycleExemptAppIds;
lifecycleExemptAppIds << "one_app" << "another_app";
ON_CALL(settings,get(_)).WillByDefault(Return(lifecycleExemptAppIds));
settings.changed("lifecycleExemptAppids");
- EXPECT_EQ(Application::Running, the_app->state());
+ ASSERT_EQ(Application::InternalState::Running, the_app->internalState());
- applicationManager.setSuspended(true);
+ EXPECT_CALL(*(mir::scene::MockSession*)first_session.get(), set_lifecycle_state(mir_lifecycle_state_will_suspend));
+ the_app->setRequestedState(Application::RequestedSuspended);
+ ASSERT_EQ(Application::InternalState::SuspendingWaitSession, the_app->internalState());
- // And expect "some_app" to get suspended
- EXPECT_EQ(Application::Suspended, the_app->state());
+ static_cast<qtmir::Session*>(the_app->session())->doSuspend();
+ ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, the_app->internalState());
+ applicationManager.onProcessSuspended(the_app->appId());
+ ASSERT_EQ(Application::InternalState::Suspended, the_app->internalState());
- applicationManager.setSuspended(false);
+ EXPECT_CALL(*(mir::scene::MockSession*)first_session.get(), set_lifecycle_state(mir_lifecycle_state_resumed));
+ the_app->setRequestedState(Application::RequestedRunning);
EXPECT_EQ(Application::Running, the_app->state());
@@ -2284,14 +1803,16 @@ TEST_F(ApplicationManagerTests,lifecycle_exempt_appId_is_not_suspended)
EXPECT_EQ(Application::Running, the_app->state());
- applicationManager.setSuspended(true);
+ EXPECT_CALL(*(mir::scene::MockSession*)first_session.get(), set_lifecycle_state(_)).Times(0);
+ the_app->setRequestedState(Application::RequestedSuspended);
// And expect it to be running still
- EXPECT_EQ(Application::Running, the_app->state());
+ ASSERT_EQ(Application::InternalState::RunningInBackground, the_app->internalState());
- applicationManager.setSuspended(false);
+ the_app->setRequestedState(Application::RequestedRunning);
EXPECT_EQ(Application::Running, the_app->state());
+ ASSERT_EQ(Application::InternalState::Running, the_app->internalState());
}
/*
@@ -2323,51 +1844,13 @@ TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnAttempte
onSessionStarting(session);
// App creates surface, focuses it so state is running
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
-
- applicationManager.unfocusCurrentApplication();
-
- EXPECT_FALSE(sharedWakelock.enabled());
- EXPECT_EQ(application->state(), Application::Running);
-}
-
-/*
- * Test lifecycle exempt applications have their wakelocks released on suspend
- */
-TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnUnSuspend)
-{
- using namespace ::testing;
-
- const QString appId("com.ubuntu.music"); // member of lifecycle exemption list
- const quint64 procId = 12345;
-
- // Set up Mocks & signal watcher
- auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
- ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
- ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
-
- ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
-
- EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
- .Times(1)
- .WillOnce(Return(true));
-
- auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
- applicationManager.onProcessStarting(appId);
- std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
- bool authed = true;
- applicationManager.authorizeSession(procId, authed);
- onSessionStarting(session);
-
- // App creates surface, focuses it so state is running
- std::shared_ptr<mir::scene::Surface> surface(nullptr);
- applicationManager.onSessionCreatedSurface(session.get(), surface);
- applicationManager.focusApplication(appId);
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ onSessionCreatedSurface(session.get(), surface);
+ surface->drawFirstFrame();
- applicationManager.setSuspended(true);
+ application->setRequestedState(Application::RequestedSuspended);
EXPECT_FALSE(sharedWakelock.enabled());
- EXPECT_EQ(application->state(), Application::Running);
+ ASSERT_EQ(Application::InternalState::RunningInBackground, application->internalState());
+ EXPECT_EQ(Application::Running, application->state());
}
diff --git a/tests/modules/MirSurfaceItem/CMakeLists.txt b/tests/modules/MirSurfaceItem/CMakeLists.txt
index 36d16a8..bac797f 100644
--- a/tests/modules/MirSurfaceItem/CMakeLists.txt
+++ b/tests/modules/MirSurfaceItem/CMakeLists.txt
@@ -5,7 +5,7 @@ set(
)
include_directories(
- ${CMAKE_SOURCE_DIR}/src/modules/Unity/Application
+ ${CMAKE_SOURCE_DIR}/src/modules
${CMAKE_SOURCE_DIR}/tests/modules/common
${MIRSERVER_INCLUDE_DIRS}
)
diff --git a/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp b/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp
index 3275b60..bc6a0de 100644
--- a/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp
+++ b/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp
@@ -23,7 +23,7 @@
#include <QTest>
// the test subject
-#include <mirsurfaceitem.h>
+#include <Unity/Application/mirsurfaceitem.h>
// mocks
#include <mock_surface.h>
diff --git a/tests/modules/SessionManager/CMakeLists.txt b/tests/modules/SessionManager/CMakeLists.txt
index a4e25d2..055449b 100644
--- a/tests/modules/SessionManager/CMakeLists.txt
+++ b/tests/modules/SessionManager/CMakeLists.txt
@@ -3,9 +3,12 @@ set(
session_manager_test.cpp
session_test.cpp
${CMAKE_SOURCE_DIR}/src/common/debughelpers.cpp
+ ${CMAKE_SOURCE_DIR}/tests/modules/common/qtmir_test.cpp
+ ${CMAKE_SOURCE_DIR}/tests/modules/common/fake_mirsurfaceitem.h
)
include_directories(
+ ${APPLICATION_API_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src/platforms/mirserver
${CMAKE_SOURCE_DIR}/src/modules
${CMAKE_SOURCE_DIR}/tests/modules/common
diff --git a/tests/modules/SessionManager/session_manager_test.cpp b/tests/modules/SessionManager/session_manager_test.cpp
index f53fe12..0a1a806 100644
--- a/tests/modules/SessionManager/session_manager_test.cpp
+++ b/tests/modules/SessionManager/session_manager_test.cpp
@@ -21,7 +21,7 @@
#include <Unity/Application/session.h>
- #include "qtmir_test.h"
+#include "qtmir_test.h"
using namespace qtmir;
using mir::scene::MockSession;
diff --git a/tests/modules/SessionManager/session_test.cpp b/tests/modules/SessionManager/session_test.cpp
index a108cfe..3f0e0e8 100644
--- a/tests/modules/SessionManager/session_test.cpp
+++ b/tests/modules/SessionManager/session_test.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
@@ -15,16 +15,17 @@
*
*/
+#include <qtmir_test.h>
+#include <fake_mirsurfaceitem.h>
+
#include <Unity/Application/application.h>
#include <Unity/Application/mirsurfaceitem.h>
-#include "qtmir_test.h"
#include "stub_scene_surface.h"
using namespace qtmir;
using mir::scene::MockSession;
-
namespace ms = mir::scene;
namespace mtd = mir::test::doubles;
@@ -43,6 +44,30 @@ public:
}
};
+TEST_F(SessionTests, FromStartingToRunningOnceSurfaceDrawsFirstFrame)
+{
+ using namespace testing;
+
+ const QString appId("test-app");
+ quint64 procId = 5551;
+
+ auto mirSession = std::make_shared<MockSession>(appId.toStdString(), procId);
+
+ auto session = std::make_shared<qtmir::Session>(mirSession, mirServer->the_prompt_session_manager());
+
+ // On Starting as it has no surface.
+ EXPECT_EQ(Session::Starting, session->state());
+
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ session->setSurface(surface);
+
+ // Still on Starting as the surface hasn't drawn its first frame yet
+ EXPECT_EQ(Session::Starting, session->state());
+
+ surface->drawFirstFrame();
+ EXPECT_EQ(Session::Running, session->state());
+}
+
TEST_F(SessionTests, AddChildSession)
{
using namespace testing;
@@ -192,17 +217,6 @@ TEST_F(SessionTests, DeleteSessionDeletesChildSessions)
EXPECT_THAT(destroyed, UnorderedElementsAre(session1, session2, session3));
}
-class MockQtMirSession : public qtmir::Session
-{
-public:
- MockQtMirSession(const std::shared_ptr<ms::Session>& session,
- const std::shared_ptr<ms::PromptSessionManager>& promptSessionManager)
- : Session(session, promptSessionManager)
- {}
-
- using SessionInterface::appendPromptSession;
-};
-
TEST_F(SessionTests, SuspendPromptSessionWhenSessionSuspends)
{
using namespace testing;
@@ -211,17 +225,25 @@ TEST_F(SessionTests, SuspendPromptSessionWhenSessionSuspends)
quint64 procId = 5551;
auto mirSession = std::make_shared<MockSession>(appId.toStdString(), procId);
- EXPECT_CALL(*mirSession, set_lifecycle_state(_));
- auto session = std::make_shared<MockQtMirSession>(mirSession, mirServer->the_prompt_session_manager());
- session->setState(Session::State::Running);
+ auto session = std::make_shared<qtmir::Session>(mirSession, mirServer->the_prompt_session_manager());
+ {
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ session->setSurface(surface);
+ surface->drawFirstFrame();
+ }
+ EXPECT_EQ(Session::Running, session->state());
auto mirPromptSession = std::make_shared<ms::MockPromptSession>();
session->appendPromptSession(mirPromptSession);
EXPECT_CALL(*mirServer->the_mock_prompt_session_manager(), suspend_prompt_session(_)).Times(1);
- session->setState(Session::State::Suspended);
+ EXPECT_CALL(*mirSession, set_lifecycle_state(mir_lifecycle_state_will_suspend));
+ session->suspend();
+ EXPECT_EQ(Session::Suspending, session->state());
+ session->doSuspend();
+ EXPECT_EQ(Session::Suspended, session->state());
Mock::VerifyAndClear(mirServer->the_mock_prompt_session_manager().get());
}
@@ -234,18 +256,29 @@ TEST_F(SessionTests, ResumePromptSessionWhenSessionResumes)
quint64 procId = 5551;
auto mirSession = std::make_shared<MockSession>(appId.toStdString(), procId);
- EXPECT_CALL(*mirSession, set_lifecycle_state(_));
- auto session = std::make_shared<MockQtMirSession>(mirSession, mirServer->the_prompt_session_manager());
- session->setState(Session::State::Suspended);
+ auto session = std::make_shared<qtmir::Session>(mirSession, mirServer->the_prompt_session_manager());
+ {
+ FakeMirSurfaceItem *surface = new FakeMirSurfaceItem;
+ session->setSurface(surface);
+ surface->drawFirstFrame();
+ }
+ EXPECT_EQ(Session::Running, session->state());
+
+ EXPECT_CALL(*mirSession, set_lifecycle_state(mir_lifecycle_state_will_suspend));
+ session->suspend();
+ EXPECT_EQ(Session::Suspending, session->state());
+ session->doSuspend();
+ EXPECT_EQ(Session::Suspended, session->state());
auto mirPromptSession = std::make_shared<ms::MockPromptSession>();
session->appendPromptSession(mirPromptSession);
EXPECT_CALL(*mirServer->the_mock_prompt_session_manager(), resume_prompt_session(_)).Times(1);
- session->setState(Session::State::Running);
+ EXPECT_CALL(*mirSession, set_lifecycle_state(mir_lifecycle_state_resumed));
+ session->resume();
+ EXPECT_EQ(Session::Running, session->state());
Mock::VerifyAndClear(mirServer->the_mock_prompt_session_manager().get());
}
-
diff --git a/tests/modules/TaskController/CMakeLists.txt b/tests/modules/TaskController/CMakeLists.txt
index e6785ab..2e7c227 100644
--- a/tests/modules/TaskController/CMakeLists.txt
+++ b/tests/modules/TaskController/CMakeLists.txt
@@ -5,6 +5,7 @@ set(
)
include_directories(
+ ${APPLICATION_API_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src/modules
${CMAKE_SOURCE_DIR}/tests/modules/common
${MIRSERVER_INCLUDE_DIRS}
diff --git a/tests/modules/common/fake_mirsurfaceitem.h b/tests/modules/common/fake_mirsurfaceitem.h
new file mode 100644
index 0000000..ea55d14
--- /dev/null
+++ b/tests/modules/common/fake_mirsurfaceitem.h
@@ -0,0 +1,95 @@
+/*
+ * 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 FAKE_MIRSURFACEITEMINTERFACE_H
+#define FAKE_MIRSURFACEITEMINTERFACE_H
+
+#include <Unity/Application/mirsurfaceiteminterface.h>
+
+namespace qtmir {
+
+class FakeMirSurfaceItem : public MirSurfaceItemInterface
+{
+ Q_OBJECT
+
+public:
+ FakeMirSurfaceItem(QQuickItem *parent = nullptr)
+ : MirSurfaceItemInterface(parent)
+ , m_state(Restored)
+ , m_live(true)
+ , m_session(nullptr)
+ , m_isFirstFrameDrawn(false)
+ , m_isFrameDropperRunning(true)
+ {}
+
+ Type type() const override { return Normal; }
+ State state() const override { return m_state; }
+ QString name() const override { return QString("fake app surface"); }
+ bool live() const override { return m_live; }
+ SessionInterface *session() const override { return m_session; }
+ OrientationAngle orientationAngle() const override { return Angle0; }
+
+ Q_INVOKABLE void release() override {}
+
+ void stopFrameDropper() override {
+ m_isFrameDropperRunning = false;
+ }
+ void startFrameDropper() override {
+ m_isFrameDropperRunning = true;
+ }
+
+ bool isFirstFrameDrawn() const override {
+ return m_isFirstFrameDrawn;
+ }
+
+ void setOrientationAngle(OrientationAngle) override {
+ }
+
+ void setSession(SessionInterface *session) override {
+ m_session = session;
+ }
+
+ void setState(State state) {
+ if (m_state != state) {
+ m_state = state;
+ Q_EMIT stateChanged();
+ }
+ }
+
+ void drawFirstFrame() {
+ if (!m_isFirstFrameDrawn) {
+ m_isFirstFrameDrawn = true;
+ Q_EMIT firstFrameDrawn();
+ }
+ }
+
+ bool isFrameDropperRunning() const {
+ return m_isFrameDropperRunning;
+ }
+
+private:
+ void setLive(bool value) override { m_live = value; }
+
+ State m_state;
+ bool m_live;
+ SessionInterface *m_session;
+ bool m_isFirstFrameDrawn;
+ bool m_isFrameDropperRunning;
+};
+
+} // namespace qtmir
+
+#endif // FAKE_MIRSURFACEITEMINTERFACE_H
diff --git a/tests/modules/common/mock_mirsurfaceitem.h b/tests/modules/common/mock_mirsurfaceitem.h
new file mode 100644
index 0000000..84409bf
--- /dev/null
+++ b/tests/modules/common/mock_mirsurfaceitem.h
@@ -0,0 +1,50 @@
+/*
+ * 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 MOCK_QTMIR_MIRSURFACEITEM_H
+#define MOCK_QTMIR_MIRSURFACEITEM_H
+
+#include <Unity/Application/mirsurfaceiteminterface.h>
+#include <gmock/gmock.h>
+
+namespace qtmir {
+
+class MockMirSurfaceItem : public MirSurfaceItemInterface {
+public:
+ MockMirSurfaceItem(QQuickItem *parent = nullptr) : MirSurfaceItemInterface(parent) {}
+
+ MOCK_CONST_METHOD0(type, Type());
+ MOCK_CONST_METHOD0(state, State());
+ MOCK_CONST_METHOD0(name, QString());
+ MOCK_CONST_METHOD0(live, bool());
+ MOCK_CONST_METHOD0(orientationAngle, OrientationAngle());
+ MOCK_CONST_METHOD0(session, SessionInterface*());
+
+ MOCK_METHOD0(release, void());
+
+ MOCK_METHOD0(stopFrameDropper, void());
+ MOCK_METHOD0(startFrameDropper, void());
+
+ MOCK_CONST_METHOD0(isFirstFrameDrawn, bool());
+
+ MOCK_METHOD1(setOrientationAngle, void(OrientationAngle angle));
+ MOCK_METHOD1(setSession, void(SessionInterface *app));
+};
+
+} // namespace qtmir
+
+#endif // MOCK_QTMIR_MIRSURFACEITEM_H
diff --git a/tests/modules/common/mock_session.h b/tests/modules/common/mock_session.h
index a6446c6..08941cb 100644
--- a/tests/modules/common/mock_session.h
+++ b/tests/modules/common/mock_session.h
@@ -18,28 +18,39 @@
#ifndef MOCK_QTMIR_SESSION_H
#define MOCK_QTMIR_SESSION_H
-#include <session_interface.h>
+#include <Unity/Application/session_interface.h>
#include <gmock/gmock.h>
namespace qtmir {
class MockSession : public SessionInterface {
public:
- MockSession() : SessionInterface(0) {}
+ MockSession() : SessionInterface(0) {
+ m_state = Starting;
+ ON_CALL(*this, suspend()).WillByDefault(::testing::Invoke(this, &MockSession::doSuspend));
+ ON_CALL(*this, resume()).WillByDefault(::testing::Invoke(this, &MockSession::doResume));
+ ON_CALL(*this, stop()).WillByDefault(::testing::Invoke(this, &MockSession::doStop));
+ ON_CALL(*this, state()).WillByDefault(::testing::Invoke(this, &MockSession::doState));
+ }
MOCK_METHOD0(release, void());
MOCK_CONST_METHOD0(name, QString());
MOCK_CONST_METHOD0(application, unity::shell::application::ApplicationInfoInterface*());
- MOCK_CONST_METHOD0(surface, MirSurfaceItem*());
+ MOCK_CONST_METHOD0(surface, MirSurfaceItemInterface*());
MOCK_CONST_METHOD0(parentSession, SessionInterface*());
+
MOCK_CONST_METHOD0(state, State());
+
MOCK_CONST_METHOD0(fullscreen, bool());
MOCK_CONST_METHOD0(live, bool());
MOCK_METHOD1(setApplication, void(unity::shell::application::ApplicationInfoInterface* item));
- MOCK_METHOD1(setSurface, void(MirSurfaceItem* surface));
- MOCK_METHOD1(setState, void(State state));
+ MOCK_METHOD1(setSurface, void(MirSurfaceItemInterface* surface));
+
+ MOCK_METHOD0(suspend, void());
+ MOCK_METHOD0(resume, void());
+ MOCK_METHOD0(stop, void());
MOCK_METHOD1(addChildSession, void(SessionInterface* session));
MOCK_METHOD2(insertChildSession, void(uint index, SessionInterface* session));
@@ -53,11 +64,39 @@ public:
MOCK_CONST_METHOD0(childSessions, SessionModel*());
+ void setState(State state) {
+ if (m_state != state) {
+ m_state = state;
+ Q_EMIT stateChanged(m_state);
+ }
+ }
+
+ void doSuspend() {
+ if (m_state == Running) {
+ setState(Suspending);
+ }
+ }
+ void doResume() {
+ if (m_state == Suspending || m_state == Suspended) {
+ setState(Running);
+ }
+ }
+ void doStop() {
+ setState(Stopped);
+ }
+ State doState() const {
+ return m_state;
+ }
+
protected:
MOCK_METHOD1(setFullscreen, void(bool fullscreen));
MOCK_METHOD1(setLive, void(const bool));
MOCK_METHOD1(appendPromptSession, void(const std::shared_ptr<mir::scene::PromptSession>& session));
MOCK_METHOD1(removePromptSession, void(const std::shared_ptr<mir::scene::PromptSession>& session));
+
+private:
+
+ State m_state;
};
} // namespace qtmir
diff --git a/tests/modules/common/qtmir_test.cpp b/tests/modules/common/qtmir_test.cpp
new file mode 100644
index 0000000..33a6c27
--- /dev/null
+++ b/tests/modules/common/qtmir_test.cpp
@@ -0,0 +1,61 @@
+#include "qtmir_test.h"
+
+namespace qtmir {
+
+void PrintTo(const Application::InternalState& state, ::std::ostream* os) {
+ switch (state) {
+ case Application::InternalState::Starting:
+ *os << "Starting";
+ break;
+ case Application::InternalState::Running:
+ *os << "Running";
+ break;
+ case Application::InternalState::RunningInBackground:
+ *os << "RunningInBackground";
+ break;
+ case Application::InternalState::SuspendingWaitSession:
+ *os << "SuspendingWaitSession";
+ break;
+ case Application::InternalState::SuspendingWaitProcess:
+ *os << "SuspendingWaitProcess";
+ break;
+ case Application::InternalState::Suspended:
+ *os << "Suspended";
+ break;
+ case Application::InternalState::StoppedUnexpectedly:
+ *os << "StoppedUnexpectedly";
+ break;
+ case Application::InternalState::Stopped:
+ *os << "Stopped";
+ break;
+ default:
+ *os << "???";
+ break;
+ }
+}
+
+void PrintTo(const Session::State& state, ::std::ostream* os)
+{
+ switch (state) {
+ case SessionInterface::Starting:
+ *os << "Starting";
+ break;
+ case SessionInterface::Running:
+ *os << "Running";
+ break;
+ case SessionInterface::Suspending:
+ *os << "Suspending";
+ break;
+ case SessionInterface::Suspended:
+ *os << "Suspended";
+ break;
+ case SessionInterface::Stopped:
+ *os << "Stopped";
+ break;
+ default:
+ *os << "???";
+ break;
+ }
+}
+
+} // namespace qtmir
diff --git a/tests/modules/common/qtmir_test.h b/tests/modules/common/qtmir_test.h
index 9ee81af..7832a73 100644
--- a/tests/modules/common/qtmir_test.h
+++ b/tests/modules/common/qtmir_test.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 Lesser General Public License version 3, as published by
@@ -18,12 +18,16 @@
#ifndef QT_MIR_TEST_FRAMEWORK_H
#define QT_MIR_TEST_FRAMEWORK_H
+#include <memory>
+
#include <gtest/gtest.h>
+#include <Unity/Application/application.h>
#include <Unity/Application/application_manager.h>
#include <Unity/Application/applicationcontroller.h>
#include <Unity/Application/mirsurfacemanager.h>
#include <Unity/Application/sessionmanager.h>
+#include <Unity/Application/session_interface.h>
#include <Unity/Application/sharedwakelock.h>
#include <Unity/Application/taskcontroller.h>
#include <Unity/Application/proc_info.h>
@@ -43,6 +47,10 @@ using namespace qtmir;
namespace qtmir {
+// For better output in ASSERT_* and EXPECT_* error messages
+void PrintTo(const Application::InternalState& state, ::std::ostream* os);
+void PrintTo(const SessionInterface::State& state, ::std::ostream* os);
+
// Initialization of mir::Server needed for by tests
class TestMirServerInit : virtual mir::Server
{