=== modified file 'src/modules/Unity/Application/application.cpp'
--- src/modules/Unity/Application/application.cpp	2017-03-28 17:12:03 +0000
+++ src/modules/Unity/Application/application.cpp	2017-03-31 21:11:21 +0000
@@ -28,10 +28,14 @@
 
 // QPA mirserver
 #include "logging.h"
+#include "initialsurfacesizes.h"
 
 // Unity API
 #include <unity/shell/application/MirSurfaceInterface.h>
 
+// std
+#include <csignal>
+
 namespace unityapp = unity::shell::application;
 
 #define DEBUG_MSG qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::" << __func__
@@ -50,12 +54,10 @@
     , m_supportedStages(Application::MainStage|Application::SideStage)
     , m_state(InternalState::Starting)
     , m_arguments(arguments)
-    , m_session(nullptr)
     , m_requestedState(RequestedRunning)
     , m_processState(ProcessUnknown)
     , m_stopTimer(nullptr)
     , m_exemptFromLifecycle(false)
-    , m_proxySurfaceList(new ProxySurfaceListModel(this))
     , m_proxyPromptSurfaceList(new ProxySurfaceListModel(this))
 {
     INFO_MSG << "()";
@@ -69,7 +71,7 @@
 
     setStopTimer(new Timer);
 
-    connect(m_proxySurfaceList, &unityapp::MirSurfaceListInterface::countChanged, this, &unityapp::ApplicationInfoInterface::surfaceCountChanged);
+    connect(&m_surfaceList, &unityapp::MirSurfaceListInterface::countChanged, this, &unityapp::ApplicationInfoInterface::surfaceCountChanged);
 }
 
 Application::~Application()
@@ -100,10 +102,11 @@
         break;
     }
 
-    if (m_session) {
-        m_session->setApplication(nullptr);
-        delete m_session;
+    for (SessionInterface *session : m_sessions) {
+        session->setApplication(nullptr);
+        delete session;
     }
+    m_sessions.clear();
 
     delete m_stopTimer;
 }
@@ -281,20 +284,22 @@
 
 void Application::updateState()
 {
-    if ((!m_session && m_state != InternalState::Starting && m_state != InternalState::StoppedResumable)
+    SessionInterface *singleSession = m_sessions.count() == 1 ? m_sessions[0] : nullptr;
+
+    if ((m_sessions.isEmpty() && m_state != InternalState::Starting && m_state != InternalState::StoppedResumable)
         ||
-        (m_session && m_session->surfaceList()->isEmpty() && m_session->hasClosingSurfaces())) {
+        (singleSession && singleSession->surfaceList()->isEmpty() && singleSession->hasClosingSurfaces())) {
         // As we might not be able to go to Closing state right now (eg, SuspendingWaitProcess),
         // store the intent in a separate variable.
         m_closing = true;
     }
 
-    bool lostAllSurfaces = m_session && m_session->surfaceList()->isEmpty() && m_session->hadSurface()
-            && !m_session->hasClosingSurfaces();
+    bool lostAllSurfaces = singleSession && singleSession->surfaceList()->isEmpty() && singleSession->hadSurface()
+            && !singleSession->hasClosingSurfaces();
 
     if (m_closing || (lostAllSurfaces && m_state != InternalState::StoppedResumable)) {
         applyClosing();
-    } else if (m_requestedState == RequestedRunning || (m_session && m_session->hasClosingSurfaces())) {
+    } else if (m_requestedState == RequestedRunning || (singleSession && singleSession->hasClosingSurfaces())) {
         applyRequestedRunning();
     } else {
         applyRequestedSuspended();
@@ -410,12 +415,22 @@
 
 bool Application::focused() const
 {
-    return m_session && m_session->focused();
+    for (auto session : m_sessions) {
+        if (session->focused()) {
+            return true;
+        }
+    }
+    return false;
 }
 
 bool Application::fullscreen() const
 {
-    return m_session ? m_session->fullscreen() : false;
+    for (auto session : m_sessions) {
+        if (session->fullscreen()) {
+            return true;
+        }
+    }
+    return false;
 }
 
 void Application::close()
@@ -433,7 +448,9 @@
     case InternalState::SuspendingWaitSession:
     case InternalState::SuspendingWaitProcess:
     case InternalState::Suspended:
-        m_session->close();
+        for (auto session : m_sessions) {
+            session->close();
+        }
         break;
     case InternalState::Closing:
         // already on the way
@@ -453,69 +470,73 @@
     m_arguments = arguments;
 }
 
-void Application::setSession(SessionInterface *newSession)
+void Application::removeSession(SessionInterface *session)
+{
+    if (!m_sessions.contains(session))
+        return;
+
+    m_surfaceList.removeSurfaceList(session->surfaceList());
+    m_proxyPromptSurfaceList->setSourceList(nullptr);
+    session->disconnect(this);
+    session->surfaceList()->disconnect(this);
+    session->setApplication(nullptr);
+    session->setParent(nullptr);
+
+    m_sessions.removeAll(session);
+
+    InitialSurfaceSizes::remove(session->pid());
+}
+
+void Application::addSession(SessionInterface *newSession)
 {
     INFO_MSG << "(session=" << newSession << ")";
 
-    if (newSession == m_session)
+    if (!newSession || m_sessions.contains(newSession))
         return;
 
-    if (m_session) {
-        m_proxySurfaceList->setSourceList(nullptr);
-        m_proxyPromptSurfaceList->setSourceList(nullptr);
-        m_session->disconnect(this);
-        m_session->surfaceList()->disconnect(this);
-        m_session->setApplication(nullptr);
-        m_session->setParent(nullptr);
-    }
-
     bool oldFullscreen = fullscreen();
-    m_session = newSession;
-
-    if (m_session) {
-        m_session->setParent(this);
-        m_session->setApplication(this);
-
-        switch (m_state) {
-        case InternalState::Starting:
-        case InternalState::Running:
-        case InternalState::RunningInBackground:
-        case InternalState::Closing:
-            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);
-        connect(m_session, &SessionInterface::hasClosingSurfacesChanged, this, &Application::updateState);
-        connect(m_session, &SessionInterface::focusRequested, this, &Application::focusRequested);
-        connect(m_session->surfaceList(), &MirSurfaceListModel::emptyChanged, this, &Application::updateState);
-        connect(m_session, &SessionInterface::focusedChanged, this, [&](bool focused) {
-            qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::focusedChanged(" << focused << ")";
-            Q_EMIT focusedChanged(focused);
-        });
-
-        if (oldFullscreen != fullscreen())
-            Q_EMIT fullscreenChanged(fullscreen());
-
-        m_proxySurfaceList->setSourceList(m_session->surfaceList());
-        m_proxyPromptSurfaceList->setSourceList(m_session->promptSurfaceList());
-    } else {
-        // this can only happen after the session has stopped
-        Q_ASSERT(m_state == InternalState::Stopped || m_state == InternalState::StoppedResumable
-                || m_state == InternalState::Closing);
-    }
-
-    Q_EMIT sessionChanged(m_session);
+    m_sessions << newSession;
+
+    newSession->setParent(this);
+    newSession->setApplication(this);
+
+    switch (m_state) {
+    case InternalState::Starting:
+    case InternalState::Running:
+    case InternalState::RunningInBackground:
+    case InternalState::Closing:
+        newSession->resume();
+        break;
+    case InternalState::SuspendingWaitSession:
+    case InternalState::SuspendingWaitProcess:
+    case InternalState::Suspended:
+        newSession->suspend();
+        break;
+    case InternalState::Stopped:
+    default:
+        newSession->stop();
+        break;
+    }
+
+    connect(newSession, &SessionInterface::stateChanged, this, &Application::onSessionStateChanged);
+    connect(newSession, &SessionInterface::fullscreenChanged, this, &Application::fullscreenChanged);
+    connect(newSession, &SessionInterface::hasClosingSurfacesChanged, this, &Application::updateState);
+    connect(newSession, &SessionInterface::focusRequested, this, &Application::focusRequested);
+    connect(newSession->surfaceList(), &MirSurfaceListModel::emptyChanged, this, &Application::updateState);
+    connect(newSession, &SessionInterface::focusedChanged, this, [&](bool focused) {
+        qCDebug(QTMIR_APPLICATIONS).nospace() << "Application[" << appId() <<"]::focusedChanged(" << focused << ")";
+        Q_EMIT focusedChanged(focused);
+    });
+
+    if (m_initialSurfaceSize.isValid() && newSession->pid() != 0) {
+        InitialSurfaceSizes::set(newSession->pid(), m_initialSurfaceSize);
+    }
+
+    if (oldFullscreen != fullscreen())
+        Q_EMIT fullscreenChanged(fullscreen());
+
+    m_surfaceList.addSurfaceList(newSession->surfaceList());
+    m_proxyPromptSurfaceList->setSourceList(newSession->promptSurfaceList());
 }
 
 void Application::setInternalState(Application::InternalState state)
@@ -587,7 +608,7 @@
         break;
     case ProcessFailed:
         // we assume the session always stop before the process
-        Q_ASSERT(!m_session || m_session->state() == Session::Stopped);
+        Q_ASSERT(m_sessions.isEmpty() || combinedSessionState() == Session::Stopped);
 
         if (m_state == InternalState::Starting) {
             // that was way too soon. let it go away
@@ -599,7 +620,7 @@
         break;
     case ProcessStopped:
         // we assume the session always stop before the process
-        Q_ASSERT(!m_session || m_session->state() == Session::Stopped);
+        Q_ASSERT(m_sessions.isEmpty() || combinedSessionState() == Session::Stopped);
 
         if (m_state == InternalState::Starting) {
             // that was way too soon. let it go away
@@ -622,7 +643,7 @@
     INFO_MSG << "()";
 
     Q_ASSERT(m_state == InternalState::Running);
-    Q_ASSERT(m_session != nullptr);
+    Q_ASSERT(!m_sessions.isEmpty());
 
     if (exemptFromLifecycle()) {
         // There's no need to keep the wakelock as the process is never suspended
@@ -631,7 +652,9 @@
         setInternalState(InternalState::RunningInBackground);
     } else {
         setInternalState(InternalState::SuspendingWaitSession);
-        m_session->suspend();
+        for (auto session : m_sessions) {
+            session->suspend();
+        }
     }
 }
 
@@ -645,12 +668,14 @@
         if (m_processState == ProcessSuspended) {
             setProcessState(ProcessRunning); // should we wait for a resumed() signal?
         }
-        if (m_session) {
-            m_session->resume();
+        for (auto session : m_sessions) {
+            session->resume();
         }
     } else if (m_state == InternalState::SuspendingWaitSession) {
         setInternalState(InternalState::Running);
-        m_session->resume();
+        for (auto session : m_sessions) {
+            session->resume();
+        }
     } else if (m_state == InternalState::RunningInBackground) {
         setInternalState(InternalState::Running);
     }
@@ -704,11 +729,6 @@
     return m_rotatesWindowContents;
 }
 
-SessionInterface* Application::session() const
-{
-    return m_session;
-}
-
 void Application::acquireWakelock() const
 {
     if (appId() == QLatin1String("unity8-dash"))
@@ -725,9 +745,28 @@
     m_sharedWakelock->release(this);
 }
 
-void Application::onSessionStateChanged(Session::State sessionState)
-{
-    switch (sessionState) {
+SessionInterface::State Application::combinedSessionState()
+{
+    // This doesn't make sense when there are no sessions
+    Q_ASSERT(m_sessions.count() > 0);
+
+    if (m_sessions.count() == 1) {
+        // easy case
+        return m_sessions[0]->state();
+    }
+
+    SessionInterface::State combinedState = SessionInterface::Stopped;
+    for (auto session : m_sessions) {
+        if (session->state() > combinedState) {
+            combinedState = session->state();
+        }
+    }
+    return combinedState;
+}
+
+void Application::onSessionStateChanged()
+{
+    switch (combinedSessionState()) {
     case Session::Starting:
         break;
     case Session::Running:
@@ -825,13 +864,18 @@
 
     if (size != m_initialSurfaceSize) {
         m_initialSurfaceSize = size;
+        if (m_initialSurfaceSize.isValid()) {
+            for (auto session : m_sessions) {
+                InitialSurfaceSizes::set(session->pid(), size);
+            }
+        }
         Q_EMIT initialSurfaceSizeChanged(m_initialSurfaceSize);
     }
 }
 
 unityapp::MirSurfaceListInterface* Application::surfaceList() const
 {
-    return m_proxySurfaceList;
+    return &m_surfaceList;
 }
 
 unityapp::MirSurfaceListInterface* Application::promptSurfaceList() const
@@ -841,11 +885,11 @@
 
 void Application::requestFocus()
 {
-    if (m_proxySurfaceList->rowCount() > 0) {
+    if (m_surfaceList.rowCount() > 0) {
         INFO_MSG << "() - Requesting focus for most recent toplevel app surface";
 
-        for (int i = 0; i < m_proxySurfaceList->count(); ++i) {
-            auto surface = static_cast<MirSurfaceInterface*>(m_proxySurfaceList->get(i));
+        for (int i = 0; i < m_surfaceList.count(); ++i) {
+            auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i));
             if (!surface->parentSurface()) {
                 surface->requestFocus();
                 break;
@@ -857,4 +901,16 @@
     }
 }
 
+void Application::terminate()
+{
+    for (auto session : m_sessions) {
+        kill(session->pid(), SIGTERM);
+    }
+}
+
+QVector<SessionInterface*> Application::sessions() const
+{
+    return m_sessions;
+}
+
 } // namespace qtmir

=== modified file 'src/modules/Unity/Application/application.h'
--- src/modules/Unity/Application/application.h	2017-03-22 14:57:19 +0000
+++ src/modules/Unity/Application/application.h	2017-03-31 21:11:21 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 Canonical, Ltd.
+ * Copyright (C) 2013-2017 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
@@ -24,6 +24,7 @@
 #include <QtCore/QtCore>
 #include <QImage>
 #include <QSharedPointer>
+#include <QVector>
 
 // Unity API
 #include <unity/shell/application/ApplicationInfoInterface.h>
@@ -109,9 +110,11 @@
     void setProcessState(ProcessState value);
 
     QStringList arguments() const { return m_arguments; }
+    void setArguments(const QStringList &arguments);
 
-    SessionInterface* session() const;
-    void setSession(SessionInterface *session);
+    void addSession(SessionInterface *session);
+    void removeSession(SessionInterface *session);
+    QVector<SessionInterface*> sessions() const;
 
     bool isValid() const;
     bool fullscreen() const;
@@ -123,13 +126,13 @@
 
     void requestFocus();
 
+    void terminate();
+
     // for tests
     void setStopTimer(AbstractTimer *timer);
     AbstractTimer *stopTimer() const { return m_stopTimer; }
-
 Q_SIGNALS:
     void fullscreenChanged(bool fullscreen);
-    void sessionChanged(SessionInterface *session);
 
     void startProcessRequested();
     void stopProcessRequested();
@@ -139,7 +142,7 @@
     void closing();
 
 private Q_SLOTS:
-    void onSessionStateChanged(SessionInterface::State sessionState);
+    void onSessionStateChanged();
 
     void respawn();
 
@@ -147,7 +150,6 @@
 
     void acquireWakelock() const;
     void releaseWakelock() const;
-    void setArguments(const QStringList &arguments);
     void setInternalState(InternalState state);
     void wipeQMLCache();
     void suspend();
@@ -160,6 +162,7 @@
     void applyRequestedSuspended();
     void applyClosing();
     void onSessionStopped();
+    SessionInterface::State combinedSessionState();
 
     QSharedPointer<SharedWakelock> m_sharedWakelock;
     QSharedPointer<ApplicationInfo> m_appInfo;
@@ -168,7 +171,7 @@
     QStringList m_arguments;
     Qt::ScreenOrientations m_supportedOrientations;
     bool m_rotatesWindowContents;
-    SessionInterface *m_session;
+    QVector<SessionInterface*> m_sessions;
     RequestedState m_requestedState;
     ProcessState m_processState;
     AbstractTimer *m_stopTimer;
@@ -176,12 +179,8 @@
     QSize m_initialSurfaceSize;
     bool m_closing{false};
 
-    ProxySurfaceListModel *m_proxySurfaceList;
+    mutable MirSurfaceListModel m_surfaceList;
     ProxySurfaceListModel *m_proxyPromptSurfaceList;
-
-    friend class ApplicationManager;
-    friend class SessionManager;
-    friend class Session;
 };
 
 } // namespace qtmir

=== modified file 'src/modules/Unity/Application/application_manager.cpp'
--- src/modules/Unity/Application/application_manager.cpp	2017-03-28 17:12:54 +0000
+++ src/modules/Unity/Application/application_manager.cpp	2017-03-31 21:11:21 +0000
@@ -28,7 +28,6 @@
 #include "settings.h"
 
 // mirserver
-#include "initialsurfacesizes.h"
 #include "nativeinterface.h"
 #include "logging.h"
 
@@ -425,7 +424,6 @@
 
     Q_UNUSED(error); // FIXME(greyback) upstart reports app that fully started up & crashes as failing during startup??
     application->setProcessState(Application::ProcessFailed);
-    setApplicationPid(application, 0);
 }
 
 void ApplicationManager::onProcessStopped(const QString &appId)
@@ -450,7 +448,6 @@
     // we don't want to override what onProcessFailed already set.
     if (application->processState() != Application::ProcessFailed) {
         application->setProcessState(Application::ProcessStopped);
-        setApplicationPid(application, 0);
     }
 }
 
@@ -527,8 +524,8 @@
         if (app->state() == Application::Starting) {
             tracepoint(qtmir, appIdHasProcessId_start);
             if (m_taskController->appIdHasProcessId(app->appId(), pid)) {
-                setApplicationPid(app, pid);
                 authorized = true;
+                m_authorizedPids.insertMulti(pid, app->appId());
                 tracepoint(qtmir, appIdHasProcessId_end, 1); //found
                 return;
             }
@@ -581,17 +578,18 @@
     // some naughty applications use a script to launch the actual application. Check for the
     // case where shell actually launched the script.
     Application *application = findApplicationMutexHeld(appInfo->appId());
-    if (application && application->state() == Application::Starting) {
+    if (application) {
         qCDebug(QTMIR_APPLICATIONS) << "Process with pid" << pid << "appeared, attaching to existing entry"
                                     << "in application list with appId:" << application->appId();
-        setApplicationPid(application, pid);
         authorized = true;
+        m_authorizedPids.insertMulti(pid, appInfo->appId());
         return;
     }
 
     const QStringList arguments(info->asStringList());
     queuedAddApp(appInfo, arguments, pid);
     authorized = true;
+    m_authorizedPids.insertMulti(pid, appInfo->appId());
 }
 
 
@@ -603,26 +601,22 @@
     auto qtmirSurface = static_cast<qtmir::MirSurfaceInterface*>(surface);
 
     QMutexLocker locker(&m_mutex);
-    return findApplicationWithPid(miral::pid_of(qtmirSurface->session()->session()));
+    return findApplicationWithSession(qtmirSurface->session()->session());
 }
 
-Application* ApplicationManager::findApplicationWithSession(const std::shared_ptr<ms::Session> &session)
+Application* ApplicationManager::findApplicationWithSession(const std::shared_ptr<ms::Session> &session) const
 {
     if (!session)
         return nullptr;
-    return findApplicationWithPid(miral::pid_of(session));
-}
-
-Application* ApplicationManager::findApplicationWithPid(const pid_t pid) const
-{
-    if (pid <= 0)
-        return nullptr;
-
-    for (Application *app : m_applications) {
-        if (m_applicationsPid.value(app) == pid) {
-            return app;
+
+    for (auto *application : m_applications) {
+        for (auto *qmlSession : application->sessions()) {
+            if (qmlSession->session() == session) {
+                return application;
+            }
         }
     }
+
     return nullptr;
 }
 
@@ -638,7 +632,6 @@
         appInfo,
         arguments,
         this);
-    setApplicationPid(application, pid);
     add(application);
 }
 
@@ -653,22 +646,8 @@
     DEBUG_MSG << "(appId=" << application->appId() << ")";
 
     connect(application, &QObject::destroyed, this, [this, application] {
-        const pid_t pid = m_applicationsPid.value(application);
-        if (pid != 0) {
-            InitialSurfaceSizes::remove(pid);
-            m_applicationsPid.remove(application);
-        }
         m_closingApplications.removeAll(application);
     });
-    connect(application, &Application::initialSurfaceSizeChanged, this, [this, application] {
-        const pid_t pid = m_applicationsPid.value(application);
-        if (pid != 0) {
-            const QSize size = application->initialSurfaceSize();
-            if (size.isValid()) {
-                InitialSurfaceSizes::set(pid, size);
-            }
-        }
-    });
 
     Q_ASSERT(!m_modelUnderChange);
     m_modelUnderChange = true;
@@ -707,13 +686,10 @@
 
     connect(application, &Application::stopProcessRequested, this, [=]() {
         if (!m_taskController->stop(appId)) {
-            const pid_t pid = m_applicationsPid.value(application);
-            if (pid > 0) {
-                qWarning() << "FAILED to ask Upstart to stop application with appId" << appId
-                        << "Sending SIGTERM to process:" << appId;
-                kill(pid, SIGTERM);
-                application->setProcessState(Application::ProcessStopped);
-            }
+            qWarning() << "FAILED to ask Upstart to stop application with appId" << appId
+                    << "Sending SIGTERM to process:" << appId;
+            application->terminate();
+            application->setProcessState(Application::ProcessStopped);
         }
     });
 
@@ -805,27 +781,22 @@
     return nullptr;
 }
 
-void ApplicationManager::setApplicationPid(Application *app, pid_t pid)
-{
-    const pid_t oldPid = m_applicationsPid.value(app);
-    if (oldPid != 0) {
-        InitialSurfaceSizes::remove(oldPid);
-    }
-
-    m_applicationsPid.insert(app, pid);
-
-    if (app->initialSurfaceSize().isValid() && pid != 0) {
-        InitialSurfaceSizes::set(pid, app->initialSurfaceSize());
-    }
-}
-
 void ApplicationManager::onSessionStarting(SessionInterface *qmlSession)
 {
     QMutexLocker locker(&m_mutex);
 
-    Application* application = findApplicationWithSession(qmlSession->session());
-    if (application && application->state() != Application::Running) {
-        application->setSession(qmlSession);
+    Application* application = nullptr;
+    {
+        auto iter = m_authorizedPids.find(miral::pid_of(qmlSession->session()));
+        if (iter != m_authorizedPids.end()) {
+            QString appId = iter.value();
+            application = findApplication(appId);
+            m_authorizedPids.erase(iter);
+        }
+    }
+
+    if (application) {
+        application->addSession(qmlSession);
     }
 }
 

=== modified file 'src/modules/Unity/Application/application_manager.h'
--- src/modules/Unity/Application/application_manager.h	2017-03-24 08:44:32 +0000
+++ src/modules/Unity/Application/application_manager.h	2017-03-31 21:11:21 +0000
@@ -110,10 +110,9 @@
 
 private:
     // All calls to private functions happen with the mutex held
-    qtmir::Application* findApplicationWithPid(const pid_t pid) const;
     Application* findApplicationMutexHeld(const QString &inputAppId) const;
 
-    Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session);
+    Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session) const;
     void setFocused(Application *application);
     void add(Application *application);
     void remove(Application* application);
@@ -125,10 +124,7 @@
     Application* findApplicationWithPromptSession(const mir::scene::PromptSession* promptSession);
     Application *findClosingApplication(const QString &inputAppId) const;
 
-    void setApplicationPid(Application *application, pid_t pid);
-
     QList<Application*> m_applications;
-    QHash<Application*, pid_t> m_applicationsPid;
     DBusFocusInfo *m_dbusFocusInfo;
     QSharedPointer<TaskController> m_taskController;
     QSharedPointer<ProcInfo> m_procInfo;
@@ -139,8 +135,8 @@
     bool m_modelUnderChange{false};
     static ApplicationManager* the_application_manager;
 
-    friend class Application;
-    friend class DBusWindowStack;
+    QHash<pid_t, QString> m_authorizedPids;
+
     mutable QMutex m_mutex;
 };
 

=== modified file 'src/modules/Unity/Application/dbusfocusinfo.cpp'
--- src/modules/Unity/Application/dbusfocusinfo.cpp	2017-03-07 20:20:21 +0000
+++ src/modules/Unity/Application/dbusfocusinfo.cpp	2017-03-31 21:11:21 +0000
@@ -75,18 +75,20 @@
 SessionInterface* DBusFocusInfo::findSessionWithPid(const QSet<pid_t> &pidSet)
 {
     Q_FOREACH (Application* application, m_applications) {
-        auto session = application->session();
-        if (pidSet.contains(session->pid())) {
-            return session;
-        }
-        SessionInterface *chosenChildSession = nullptr;
-        session->foreachChildSession([&](SessionInterface* childSession) {
-            if (pidSet.contains(childSession->pid())) {
-                chosenChildSession = childSession;
-            }
-        });
-        if (chosenChildSession) {
-            return chosenChildSession;
+        QVector<SessionInterface*> sessions = application->sessions();
+        for (auto session : sessions) {
+            if (pidSet.contains(session->pid())) {
+                return session;
+            }
+            SessionInterface *chosenChildSession = nullptr;
+            session->foreachChildSession([&](SessionInterface* childSession) {
+                if (pidSet.contains(childSession->pid())) {
+                    chosenChildSession = childSession;
+                }
+            });
+            if (chosenChildSession) {
+                return chosenChildSession;
+            }
         }
     }
     return nullptr;
@@ -111,21 +113,22 @@
 MirSurfaceInterface *DBusFocusInfo::findQmlSurface(const QString &serializedId)
 {
     for (Application* application : m_applications) {
-        auto session = application->session();
-        if (session) {
-            auto surfaceList = static_cast<MirSurfaceListModel*>(session->surfaceList());
-            for (int i = 0; i < surfaceList->count(); ++i) {
-                auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i));
-                if (qmlSurface->persistentId() == serializedId) {
-                    return qmlSurface;
+        for (SessionInterface *session : application->sessions()) {
+            if (session) {
+                auto surfaceList = static_cast<MirSurfaceListModel*>(session->surfaceList());
+                for (int i = 0; i < surfaceList->count(); ++i) {
+                    auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i));
+                    if (qmlSurface->persistentId() == serializedId) {
+                        return qmlSurface;
+                    }
                 }
-            }
 
-            surfaceList = static_cast<MirSurfaceListModel*>(session->promptSurfaceList());
-            for (int i = 0; i < surfaceList->count(); ++i) {
-                auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i));
-                if (qmlSurface->persistentId() == serializedId) {
-                    return qmlSurface;
+                surfaceList = static_cast<MirSurfaceListModel*>(session->promptSurfaceList());
+                for (int i = 0; i < surfaceList->count(); ++i) {
+                    auto qmlSurface = static_cast<MirSurfaceInterface*>(surfaceList->get(i));
+                    if (qmlSurface->persistentId() == serializedId) {
+                        return qmlSurface;
+                    }
                 }
             }
         }

=== modified file 'src/modules/Unity/Application/session.cpp'
--- src/modules/Unity/Application/session.cpp	2017-02-21 18:39:45 +0000
+++ src/modules/Unity/Application/session.cpp	2017-03-31 21:11:21 +0000
@@ -92,7 +92,7 @@
         delete child;
     }
     if (m_application) {
-        m_application->setSession(nullptr);
+        m_application->removeSession(this);
     }
 
     delete m_children; m_children = nullptr;

=== modified file 'src/modules/Unity/Application/session_interface.h'
--- src/modules/Unity/Application/session_interface.h	2017-02-21 18:46:30 +0000
+++ src/modules/Unity/Application/session_interface.h	2017-03-31 21:11:21 +0000
@@ -53,12 +53,13 @@
     SessionInterface(QObject *parent = 0) : QObject(parent) {}
     virtual ~SessionInterface() {}
 
+    // Ordered by importance/activity. Used for calculating the combined state of multiple sessions
     enum State {
-        Starting,
-        Running,
-        Suspending,
-        Suspended,
-        Stopped
+        Running = 4,
+        Starting = 3,
+        Suspending = 2,
+        Suspended = 1,
+        Stopped = 0
     };
 
     //getters

=== modified file 'tests/modules/Application/application_test.cpp'
--- tests/modules/Application/application_test.cpp	2017-02-21 18:46:30 +0000
+++ tests/modules/Application/application_test.cpp	2017-03-31 21:11:21 +0000
@@ -49,7 +49,7 @@
     inline void suspend(Application *application)
     {
         application->setRequestedState(Application::RequestedSuspended);
-        auto session = dynamic_cast<Session*>(application->session());
+        auto session = dynamic_cast<Session*>(application->sessions()[0]);
 
         ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
         ASSERT_EQ(Session::Suspending, session->state());
@@ -115,7 +115,7 @@
 
     FakeSession *session = new FakeSession;
 
-    application->setSession(session);
+    application->addSession(session);
 
     ASSERT_EQ(Application::InternalState::Starting, application->internalState());
 
@@ -150,7 +150,7 @@
 
     // Get it running and then suspend it
     application->setProcessState(Application::ProcessRunning);
-    application->setSession(session);
+    application->addSession(session);
     session->setState(SessionInterface::Running);
     application->setRequestedState(Application::RequestedSuspended);
     session->setState(SessionInterface::Suspended);
@@ -175,7 +175,7 @@
 
     // Get it running, suspend it, and finally stop it
     application->setProcessState(Application::ProcessRunning);
-    application->setSession(session);
+    application->addSession(session);
     session->setState(SessionInterface::Running);
     application->setRequestedState(Application::RequestedSuspended);
     session->setState(SessionInterface::Suspended);
@@ -215,7 +215,7 @@
 
     FakeSession *session = new FakeSession;
 
-    application->setSession(session);
+    application->addSession(session);
 
     ASSERT_EQ(Application::InternalState::Starting, application->internalState());
 
@@ -250,7 +250,7 @@
     application->setProcessState(Application::ProcessRunning);
 
     FakeSession *session = new FakeSession;
-    application->setSession(session);
+    application->addSession(session);
 
     QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped()));
 
@@ -283,7 +283,7 @@
     application->setProcessState(Application::ProcessRunning);
 
     Session *session = createSessionWithFakes();
-    application->setSession(session);
+    application->addSession(session);
 
     QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped()));
 
@@ -318,7 +318,7 @@
     application->setProcessState(Application::ProcessRunning);
 
     FakeSession *session = new FakeSession;
-    application->setSession(session);
+    application->addSession(session);
 
     QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped()));
 
@@ -380,7 +380,7 @@
 
     Session *session = createSessionWithFakes();
 
-    application->setSession(session);
+    application->addSession(session);
 
     FakeMirSurface *surface = new FakeMirSurface;
     session->registerSurface(surface);
@@ -437,7 +437,7 @@
 
     Session *session = createSessionWithFakes();
 
-    application->setSession(session);
+    application->addSession(session);
 
     FakeMirSurface *surface = new FakeMirSurface;
     session->registerSurface(surface);
@@ -488,7 +488,7 @@
 
     QPointer<Session> session(createSessionWithFakes());
 
-    application->setSession(session);
+    application->addSession(session);
 
     FakeMirSurface *surface = new FakeMirSurface;
     session->registerSurface(surface);
@@ -532,7 +532,7 @@
     application->setProcessState(Application::ProcessRunning);
 
     QPointer<Session> session(createSessionWithFakes());
-    application->setSession(session);
+    application->addSession(session);
 
     FakeMirSurface *surface = new FakeMirSurface;
     session->registerSurface(surface);
@@ -570,7 +570,7 @@
 
     Session *session = createSessionWithFakes();
 
-    application->setSession(session);
+    application->addSession(session);
 
     FakeMirSurface *surface = new FakeMirSurface;
     session->registerSurface(surface);
@@ -602,7 +602,7 @@
     application->setProcessState(Application::ProcessRunning);
     Session *session = createSessionWithFakes();
 
-    application->setSession(session);
+    application->addSession(session);
 
     QSignalSpy surfaceCountChangedSpy(application.data(), &Application::surfaceCountChanged);
 
@@ -641,7 +641,7 @@
 
     FakeSession *session = new FakeSession;
 
-    application->setSession(session);
+    application->addSession(session);
 
     QSignalSpy spyStartProcess(application.data(), SIGNAL(startProcessRequested()));
 

=== modified file 'tests/modules/ApplicationManager/application_manager_test.cpp'
--- tests/modules/ApplicationManager/application_manager_test.cpp	2017-02-21 18:46:30 +0000
+++ tests/modules/ApplicationManager/application_manager_test.cpp	2017-03-31 21:11:21 +0000
@@ -59,7 +59,7 @@
     inline void suspend(Application *application) {
         application->setRequestedState(Application::RequestedSuspended);
         ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
-        static_cast<qtmir::Session*>(application->session())->doSuspend();
+        static_cast<qtmir::Session*>(application->sessions()[0])->doSuspend();
         ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
         applicationManager.onProcessSuspended(application->appId());
         ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
@@ -85,6 +85,11 @@
 
     FakeMirSurface surface;
 
+    EXPECT_CALL(*taskController,appIdHasProcessId(QString(dialer_app_id), firstProcId))
+        .WillRepeatedly(Return(true));
+    EXPECT_CALL(*taskController,appIdHasProcessId(QString(dialer_app_id), secondProcId))
+        .WillRepeatedly(Return(true));
+
     EXPECT_CALL(procInfo,command_line(firstProcId))
         .Times(1)
         .WillOnce(Return(cmdLine));
@@ -226,12 +231,22 @@
     const char third_app_id[] = "app3";
     QByteArray third_cmdLine( "/usr/bin/app3 --desktop_file_hint=app3");
 
+    ON_CALL(*taskController,appIdHasProcessId(QString(first_app_id), first_procId)).WillByDefault(Return(true));
+    ON_CALL(*taskController,appIdHasProcessId(QString(first_app_id), second_procId)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString(first_app_id), third_procId)).WillByDefault(Return(false));
+
+    ON_CALL(*taskController,appIdHasProcessId(QString(second_app_id), second_procId)).WillByDefault(Return(true));
+    ON_CALL(*taskController,appIdHasProcessId(QString(second_app_id), first_procId)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString(second_app_id), third_procId)).WillByDefault(Return(false));
+
+    ON_CALL(*taskController,appIdHasProcessId(QString(third_app_id), third_procId)).WillByDefault(Return(true));
+    ON_CALL(*taskController,appIdHasProcessId(QString(third_app_id), first_procId)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString(third_app_id), second_procId)).WillByDefault(Return(false));
+
     EXPECT_CALL(procInfo,command_line(first_procId))
         .Times(1)
         .WillOnce(Return(first_cmdLine));
 
-    ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
-
     EXPECT_CALL(procInfo,command_line(second_procId))
         .Times(1)
         .WillOnce(Return(second_cmdLine));
@@ -257,12 +272,12 @@
     Application * secondApp = applicationManager.findApplication(second_app_id);
     Application * thirdApp = applicationManager.findApplication(third_app_id);
 
-    EXPECT_EQ(firstAppInfo.application(), firstApp->session()->session());
-    EXPECT_EQ(secondAppInfo.application(), secondApp->session()->session());
-    EXPECT_EQ(thirdAppInfo.application(), thirdApp->session()->session());
+    EXPECT_EQ(firstAppInfo.application(), firstApp->sessions()[0]->session());
+    EXPECT_EQ(secondAppInfo.application(), secondApp->sessions()[0]->session());
+    EXPECT_EQ(thirdAppInfo.application(), thirdApp->sessions()[0]->session());
 }
 
-TEST_F(ApplicationManagerTests,two_session_on_one_application)
+TEST_F(ApplicationManagerTests,two_sessions_on_one_application)
 {
     int argc = 0;
     char* argv[0];
@@ -275,28 +290,30 @@
 
     ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd));
 
-    ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString(an_app_id), a_procId)).WillByDefault(Return(true));
 
     bool authed = true;
 
     auto firstAppInfo = createApplicationInfoFor("Oo", a_procId);
     auto secondAppInfo = createApplicationInfoFor("oO", a_procId);
+
     applicationManager.authorizeSession(a_procId, authed);
-
     taskController->onSessionStarting(firstAppInfo);
+
+    applicationManager.authorizeSession(a_procId, authed);
     taskController->onSessionStarting(secondAppInfo);
 
     Application * the_app = applicationManager.findApplication(an_app_id);
 
     EXPECT_EQ(true, authed);
-    EXPECT_EQ(secondAppInfo.application(), the_app->session()->session());
+    EXPECT_EQ(2, the_app->sessions().count());
 
     taskController->onSessionStopping(firstAppInfo);
     taskController->onSessionStopping(secondAppInfo);
     qtApp.sendPostedEvents(nullptr, QEvent::DeferredDelete);
 }
 
-TEST_F(ApplicationManagerTests,two_session_on_one_application_after_starting)
+TEST_F(ApplicationManagerTests,two_sessions_on_one_application_after_starting)
 {
     int argc = 0;
     char* argv[0];
@@ -310,24 +327,30 @@
 
     ON_CALL(procInfo,command_line(_)).WillByDefault(Return(a_cmd));
 
-    ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString(an_app_id), a_procId)).WillByDefault(Return(true));
 
     bool authed = true;
 
     auto firstAppInfo = createApplicationInfoFor("Oo", a_procId);
     auto secondAppInfo = createApplicationInfoFor("oO", a_procId);
+
     applicationManager.authorizeSession(a_procId, authed);
-
     taskController->onSessionStarting(firstAppInfo);
+
+    EXPECT_EQ(true, authed);
+
     onSessionCreatedSurface(firstAppInfo, &aSurface);
     aSurface.setReady();
+
+    Application * the_app = applicationManager.findApplication(an_app_id);
+    EXPECT_EQ(1, the_app->sessions().count());
+
+    applicationManager.authorizeSession(a_procId, authed);
     taskController->onSessionStarting(secondAppInfo);
 
-    Application * the_app = applicationManager.findApplication(an_app_id);
-
     EXPECT_EQ(true, authed);
     EXPECT_EQ(Application::Running, the_app->state());
-    EXPECT_EQ(firstAppInfo.application(), the_app->session()->session());
+    EXPECT_EQ(2, the_app->sessions().count());
 
     taskController->onSessionStopping(firstAppInfo);
     taskController->onSessionStopping(secondAppInfo);
@@ -345,7 +368,7 @@
         .Times(1)
         .WillOnce(Return(cmdLine));
 
-    ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString("app"), procId)).WillByDefault(Return(true));
 
     bool authed = true;
 
@@ -383,7 +406,9 @@
         .Times(1)
         .WillOnce(Return(first_cmdLine));
 
-    ON_CALL(*taskController,appIdHasProcessId(_,_)).WillByDefault(Return(false));
+    ON_CALL(*taskController,appIdHasProcessId(QString("app1"), first_procId)).WillByDefault(Return(true));
+    ON_CALL(*taskController,appIdHasProcessId(QString("app2"), second_procId)).WillByDefault(Return(true));
+    ON_CALL(*taskController,appIdHasProcessId(QString("app3"), third_procId)).WillByDefault(Return(true));
 
     EXPECT_CALL(procInfo,command_line(second_procId))
         .Times(1)
@@ -718,7 +743,7 @@
 
     // Check application state and session are correctly set
     Application *theApp = applicationManager.findApplication(appId);
-    EXPECT_EQ(theApp->session()->session(), appInfo.application());
+    EXPECT_EQ(theApp->sessions()[0]->session(), appInfo.application());
     EXPECT_EQ(theApp->focused(), false);
 }
 
@@ -1115,6 +1140,8 @@
     QByteArray cmdLine("/usr/bin/testApp --desktop_file_hint=");
     cmdLine = cmdLine.append(appId);
 
+    ON_CALL(*taskController,appIdHasProcessId(appId, procId)).WillByDefault(Return(true));
+
     // Set up Mocks & signal watcher
     EXPECT_CALL(procInfo,command_line(procId))
         .Times(1)
@@ -1181,7 +1208,7 @@
 
     ASSERT_EQ(Application::InternalState::SuspendingWaitSession, app->internalState());
 
-    static_cast<qtmir::Session*>(app->session())->doSuspend();
+    static_cast<qtmir::Session*>(app->sessions()[0])->doSuspend();
     ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, app->internalState());
 
     applicationManager.onProcessSuspended(app->appId());
@@ -1412,10 +1439,10 @@
 
     // Session should have called deleteLater() on itself, as it's zombie and doesn't hold any surface
     // But DeferredDelete is special: likes to be called out specifically or it won't come out
-    qtApp.sendPostedEvents(app->session(), QEvent::DeferredDelete);
+    qtApp.sendPostedEvents(app->sessions()[0], QEvent::DeferredDelete);
     qtApp.sendPostedEvents();
 
-    ASSERT_EQ(app->session(), nullptr);
+    ASSERT_EQ(app->sessions().count(), 0);
 
     QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &)));
 
@@ -1461,7 +1488,7 @@
     the_app->setRequestedState(Application::RequestedSuspended);
     ASSERT_EQ(Application::InternalState::SuspendingWaitSession, the_app->internalState());
 
-    static_cast<qtmir::Session*>(the_app->session())->doSuspend();
+    static_cast<qtmir::Session*>(the_app->sessions()[0])->doSuspend();
     ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, the_app->internalState());
     applicationManager.onProcessSuspended(the_app->appId());
     ASSERT_EQ(Application::InternalState::Suspended, the_app->internalState());
@@ -1838,7 +1865,7 @@
     taskController->onSessionStarting(appInfo1);
 
     FakeMirSurface surface1;
-    surface1.setSession(app1->session());
+    surface1.setSession(app1->sessions()[0]);
     onSessionCreatedSurface(appInfo1, &surface1);
     surface1.setReady();
 
@@ -1864,7 +1891,7 @@
     taskController->onSessionStarting(appInfo2);
 
     FakeMirSurface surface2;
-    surface2.setSession(app2->session());
+    surface2.setSession(app2->sessions()[0]);
     onSessionCreatedSurface(appInfo2, &surface2);
     surface2.setReady();
 

