Merge lp:~nick-dedekind/unity-mir/trusted-sessions into lp:unity-mir

Proposed by Nick Dedekind
Status: Superseded
Proposed branch: lp:~nick-dedekind/unity-mir/trusted-sessions
Merge into: lp:unity-mir
Diff against target: 1676 lines (+810/-118)
24 files modified
debian/changelog (+0/-18)
debian/control (+2/-2)
src/modules/Unity/Application/application.cpp (+123/-7)
src/modules/Unity/Application/application.h (+29/-5)
src/modules/Unity/Application/application_manager.cpp (+185/-58)
src/modules/Unity/Application/application_manager.h (+21/-12)
src/modules/Unity/Application/applicationscreenshotprovider.cpp (+2/-1)
src/modules/Unity/Application/dbuswindowstack.cpp (+1/-1)
src/modules/Unity/Application/inputarea.cpp (+5/-4)
src/modules/Unity/Application/mirsurfacemanager.cpp (+3/-3)
src/modules/Unity/Application/proc_info.cpp (+13/-0)
src/modules/Unity/Application/proc_info.h (+3/-0)
src/unity-mir/CMakeLists.txt (+2/-0)
src/unity-mir/focussetter.cpp (+3/-2)
src/unity-mir/promptsessionlistener.cpp (+62/-0)
src/unity-mir/promptsessionlistener.h (+47/-0)
src/unity-mir/shellserverconfiguration.cpp (+20/-1)
src/unity-mir/shellserverconfiguration.h (+4/-0)
tests/CMakeLists.txt (+1/-0)
tests/application_manager_test.cpp (+187/-0)
tests/mock_proc_info.h (+8/-3)
tests/mock_prompt_session.h (+31/-0)
tests/mock_prompt_session_manager.h (+57/-0)
tests/mock_session.h (+1/-1)
To merge this branch: bzr merge lp:~nick-dedekind/unity-mir/trusted-sessions
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Gerry Boland (community) Needs Information
Review via email: mp+224397@code.launchpad.net

This proposal supersedes a proposal from 2014-06-17.

This proposal has been superseded by a proposal from 2014-07-10.

Commit message

Shell implementation of Mir trust sessions.

Description of the change

Shell implementation of Mir trust sessions.
Requires lp:~nick-dedekind/mir/trusted_sessions to land

A mir trust session consists of any number of mir sessions arranged into a parent hierarchy. The last child of the hierarchy is the session which is considered to be the top focused session at all times if the unity-mir Application is in focus.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

Is this actually ready for review? If not, please mark as Work in Progress

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:205
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nick-dedekind/unity-mir/trusted-sessions/+merge/223432/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-mir-devel-ci/16/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-amd64-ci/16/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-armhf-ci/16/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-i386-ci/16/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-mir-devel-ci/16/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:206
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nick-dedekind/unity-mir/trusted-sessions/+merge/223432/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-mir-devel-ci/17/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-amd64-ci/17/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-armhf-ci/17/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-i386-ci/17/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-mir-devel-ci/17/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

Commit message please. Checklist too.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

- std::shared_ptr<::mir::scene::Session> m_session;
+ mutable mir::scene::Session* m_lastTopSession;

So now Application doesn't have a shared_ptr to a Mir Session object. Reason unity-mir held onto that was so that the Session object was only deleted when both Mir and unity-mir had released it, as it may take time for the Application to be removed from the app list, and QML could be asking for properties of that Session after Mir was done with it.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

=== modified file 'debian/control'
not necessary change for this MR, please revert

Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal
Download full text (3.2 KiB)

Taking the smaller bits first

=== added file 'src/modules/Unity/Application/promptsession.h'
+ // Qt
+#include <QSharedPointer>
not needed in header

namespace mir
+{
+namespace scene
+{
+class Session;
+class PromptSession;
+class PromptSessionManager;
please indent like in ApplicationManager

In PromptSession constructor, line 45, please line up the arguments (space missing)

+ virtual ~PromptSession();
Why virtual? Could use "= default" to have default deconstructor generated, saving you these few lines:
 +Session::~Session()
+{
+}

+ std::shared_ptr<mir::scene::Session> topProvider() const;
I find the name confusing. What is a "provider"? It returns a Session. "top" also isn't useful, unless you happen to know the internals of unity-mir::PromptSession is a stack.

+ std::shared_ptr<mir::scene::PromptSession> mirPromptSession() const;
shows that we can now easily confuse mir's PromptSession with unity-mir's PromptSession. Perhaps a slightly different class name? PromptSessionWrapper?

+Q_DECLARE_METATYPE(unitymir::PromptSession*)
Why do you need to register it as a type with MOC?

=== added file 'src/modules/Unity/Application/promptsession.cpp'
+#include <QDebug>
not used

+PromptSession::PromptSession(const std::shared_ptr<mir::scene::PromptSession>& promptSession, const std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager)
please wrap. I'm not strict, but 120 chars is reasonable.

+ m_promptSessionManager->for_each_provider_in(m_promptSession,
+ [&child](std::shared_ptr<mir::scene::Session> const& provider) {
+ child = provider;
+ });
Really? Is there no way to identify the "top" one other than iterating the whole list/stack?!

+ auto helper = m_promptSessionManager->helper_for(m_promptSession);
I only like using auto if the type is really obvious. In this case it's not, I'd prefer you either declare the type, or use name "helperSession"

+ [&](std::shared_ptr<mir::scene::Session> const& provider) {
You only need to capture "found" here, not all locals.

+ }
please add comment to the namespace closing brace, it's a style I'm trying to maintain in this project.

=== added file 'src/modules/Unity/Application/session.h'
What's the point of this entire class? Do you need to share a mir Session with multiple Applications??

=== added file 'src/unity-mir/promptsessionlistener.cpp'
+ * Copyright (C) 2013 Canonical, Ltd.
2014

+ DLOG("PromptSessionListener::prompt_provider_added (this=%p, prompt_session=%p, prompt_provider=%p)", this, &prompt_session, (void*)prompt_provider.get());
+ DLOG("PromptSessionListener::prompt_provider_removed (this=%p, prompt_session=%p, prompt_provider=%p)", this, &prompt_session, (void*)prompt_provider.get());
please wrap

Same for the header file, prompt_provider_{added,removed} should be wrapped

=== modified file 'src/unity-mir/qmirserver.cpp'
Unnecessary change, please revert

=== modified file 'src/unity-mir/sessionauthorizer.cpp'
Unnecessary change, please revert

=== modified file 'src/modules/Unity/Application/proc_info.h'
+ virtual quint64 ppid(quint64 pid);
what does that mean? Parent process id? Does process-cpp not have a method to get that?

=== modified file 'src/mo...

Read more...

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

=== modified file 'src/modules/Unity/Application/mirsurface.h'
- explicit MirSurface(std::shared_ptr<mir::scene::Surface> surface, Application* application, QQuickItem *parent = 0);
1069 + explicit MirSurface(std::shared_ptr<mir::scene::Surface> surface, QSharedPointer<Session> const& session, QQuickItem *parent = 0);

I object strongly, why create distinction between an Application and a Session? Why does a shell need to know about Sessions?

In my vocabulary, Applications have Surfaces, and that's all a shell needs to know to operate. Those Surfaces can have relationships and properties, which shell can use to treat them differently.

Why do you need this?

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal
Download full text (3.6 KiB)

> Taking the smaller bits first
>
>
>
> === added file 'src/modules/Unity/Application/promptsession.h'
> + // Qt
> +#include <QSharedPointer>
> not needed in header
>
> namespace mir
> +{
> +namespace scene
> +{
> +class Session;
> +class PromptSession;
> +class PromptSessionManager;
> please indent like in ApplicationManager
>
> In PromptSession constructor, line 45, please line up the arguments (space
> missing)
>
> + virtual ~PromptSession();
> Why virtual? Could use "= default" to have default deconstructor generated,
> saving you these few lines:
> +Session::~Session()
> +{
> +}
>
> + std::shared_ptr<mir::scene::Session> topProvider() const;
> I find the name confusing. What is a "provider"? It returns a Session. "top"
> also isn't useful, unless you happen to know the internals of unity-
> mir::PromptSession is a stack.
>
> + std::shared_ptr<mir::scene::PromptSession> mirPromptSession() const;
> shows that we can now easily confuse mir's PromptSession with unity-mir's
> PromptSession. Perhaps a slightly different class name? PromptSessionWrapper?
>
> +Q_DECLARE_METATYPE(unitymir::PromptSession*)
> Why do you need to register it as a type with MOC?
>
>
> === added file 'src/modules/Unity/Application/promptsession.cpp'
> +#include <QDebug>
> not used
>
> +PromptSession::PromptSession(const
> std::shared_ptr<mir::scene::PromptSession>& promptSession, const
> std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager)
> please wrap. I'm not strict, but 120 chars is reasonable.

removed unitymir::PromptSession

>
> + m_promptSessionManager->for_each_provider_in(m_promptSession,
> + [&child](std::shared_ptr<mir::scene::Session> const& provider) {
> + child = provider;
> + });
> Really? Is there no way to identify the "top" one other than iterating the
> whole list/stack?!

nope. but there won't be many (like only one/two...)

>
> + auto helper = m_promptSessionManager->helper_for(m_promptSession);
> I only like using auto if the type is really obvious. In this case it's not,
> I'd prefer you either declare the type, or use name "helperSession"
>
> + [&](std::shared_ptr<mir::scene::Session> const& provider) {
> You only need to capture "found" here, not all locals.
>
> + }
> please add comment to the namespace closing brace, it's a style I'm trying to
> maintain in this project.
>
>
>
>
> === added file 'src/modules/Unity/Application/session.h'
> What's the point of this entire class? Do you need to share a mir Session with
> multiple Applications??
>

removed unitymir::Session

>
> === added file 'src/unity-mir/promptsessionlistener.cpp'
> + * Copyright (C) 2013 Canonical, Ltd.
> 2014
>
> + DLOG("PromptSessionListener::prompt_provider_added (this=%p,
> prompt_session=%p, prompt_provider=%p)", this, &prompt_session,
> (void*)prompt_provider.get());
> + DLOG("PromptSessionListener::prompt_provider_removed (this=%p,
> prompt_session=%p, prompt_provider=%p)", this, &prompt_session,
> (void*)prompt_provider.get());
> please wrap
>
> Same for the header file, prompt_provider_{added,removed} should be wrapped
>

done

>
>
> === modified file 'src/unity-mir/qmirserver.cpp'
> Unnecessary change, please reve...

Read more...

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

Thanks for the design changes, I'm much happier with it now. I've mostly small annoying things to request. Taking everything except AppManager and the tests (will check them last):

=== modified file 'src/modules/Unity/Application/application.h'
+ std::shared_ptr<mir::scene::PromptSessionManager> const promptSessionManager,
Could pass by reference to save a copy?

Also, you've seen that the current variable declaration syntax mess that is the "const Type& name" and "Type const& name" confusion. I need to tidy it up, but I'm slowly standardizing everything to "const Type &name" - would you hate me if I asked you to do the same, just in the bits you added? It's ok to say no :)

+ std::shared_ptr<mir::scene::Session> effectiveSession() const;
I think "foregroundSession" is a clearer name than effectiveSession.

session() is also not a great name now, but changing it everywhere would be lots more work, so we can leave it for now.

std::shared_ptr<mir::scene::PromptSession> Application::promptSession() const;
There could be multiple such prompt sessions, but this returns only the most recently created one. Maybe better name is "foremostPromptSession" or "activePromptSession"?

+ mutable mir::scene::Session* m_lastTopSession;
"Top" -> "Foreground" please.

Note that ApplicationManager is a friend of Application, so all your additional public methods can be made private, as they're not useful to shell/QML.

+ void pushPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session);
+ void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session);
Could you rename the first to "append" - if I see "push" I expect a "pop", else "add/append" and "remove" pair nicely

=== modified file 'src/modules/Unity/Application/application.cpp'
+ mir::scene::PromptSession
please add "namespace ms = mir::scene" to the top of the file and write "ms::PromptSession" everywhere, helps to hide some of Mir's namespace verbosity.

+ std::shared_ptr<mir::scene::PromptSession> prompt_session
camelCase please.

+ std::shared_ptr<mir::scene::Session> child;
'child' could be declared outside the while loop, save create/destroy on each iteration.

+ if (m_pid == pid) {
2 spaces after m_pid. Braces not really needed either for this 1-liner (which is your usual style).

+void Application::pushPromptSession(const std::shared_ptr<mir::scene::PromptSession>& prompt_session)
camelCase please

+void Application::removePromptSession
A warning if no matching prompt session was found would not hurt, and might save future debugging pain.

=== modified file 'src/modules/Unity/Application/mirsurface.h'
Whitespace change, not needed in this MR.

Ok, last need to read AppMan, the tests, and do functional testing.

review: Needs Fixing
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

=== added file 'src/unity-mir/promptsessionlistener.cpp'
+#include <QThread>
needed?

Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

+void Application::removePromptSession
A warning if no matching prompt session was found would not hurt, and might save future debugging pain

It calls this on applications which may not necessarily have the prompt session (loops through all apps). More efficient than checking, then removing.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

Fixed others.

Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

ApplicationManager:

=== modified file 'src/modules/Unity/Application/application_manager.h'
+ std::shared_ptr<mir::shell::FocusController> const& focusController,
+ const std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager,
Consistency please

+ Application* findApplicationWithPid(const qint64 pid, bool checkSessions)
+ Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session, bool checkSessions);
+ Application* findApplicationWithSession(const mir::scene::Session *session, bool checkSessions);
"checkSessions" - better name would be more like "includeChildSessions" or something like that, WDYT?

+ void onApplicationEffectiveSessionChanged();
s/Effective/Foreground/

+ if (info->contains("trust-session-demo-trusted-helper") ||
+ info->contains("unity8") ||
+ (ppid != 0 && m_procInfo->commandLine(ppid)->contains("trust-session-demo-trusted-helper"))) {
That's pretty messy. Why considering an app with "unity8" in the process name as a trusted helper? So you're allowing any process directly spawned by the trusted helper. I guess that's all we can do, until our internal discussions conclude.

+ info->asStringList()[0].toLatin1().data());
qPrintable(info->asStringList().first()) an alternative, up to you

+ if (m_fencePIDs.contains(pid)) {
It looks like you've changed m_fencePIDs contains the PIDs of all whitelisted and trusted helpers while they are running. That's ok, but "fence" is not a good name now - perhaps "ignored" or "hidden" ?

+ if (!session) { return NULL; }
2 lines, no braces please. "nullptr" too.

Ok, just tests to go

Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

Tests
=== modified file 'tests/application_manager_test.cpp'

+ Application* startApplication(quint64 procId, QString const& appId)
Not a bad idea.

+ auto session1 = std::make_shared<MockSession>(appId.toStdString(), procId);
+ auto promptSession = std::make_shared<MockPromptSession>();

I don't see these being used anywhere though.

TEST_F(ApplicationManagerTests,onceAppAddedToApplicationLists_mirSurfaceCreatedEventHandled)
+ std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
+++
why did you move these lines before the focusSpy?

+ std::shared_ptr<mir::scene::Surface> providerSurface((mir::scene::Surface*)__LINE__, [](mir::scene::Surface*) {}); // use mock!
What does that do? Is that comment a TODO?

+ {
+ return 0;
strange indent

Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

Ah, can you re-propose against lp:unity-mir please?

lp:unity-mir/devel really only for Mir devel compatibility changes

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

> Tests
> === modified file 'tests/application_manager_test.cpp'
>
> + Application* startApplication(quint64 procId, QString const& appId)
> Not a bad idea.
>
> + auto session1 = std::make_shared<MockSession>(appId.toStdString(), procId);
> + auto promptSession = std::make_shared<MockPromptSession>();
>
> I don't see these being used anywhere though.
>

Moved AppMan.onSessionstart(session1) to startApplication.
Removed other.

>
>
> TEST_F(ApplicationManagerTests,onceAppAddedToApplicationLists_mirSurfaceCreate
> dEventHandled)
> + std::shared_ptr<mir::scene::Session> session =
> std::make_shared<MockSession>("", procId);
> +++
> why did you move these lines before the focusSpy?
>

This was because of the foregroundSessionChanged signal causing a screenshot dataChanged. However, there was a bit of code duplication in the AppMan which I removed. So I've changed it back.

>
> + std::shared_ptr<mir::scene::Surface>
> providerSurface((mir::scene::Surface*)__LINE__, [](mir::scene::Surface*) {});
> // use mock!
> What does that do? Is that comment a TODO?

Made comment a TODO
mmmm. that's a shared_ptr with a custom deleter (an empty deleter in this case. Ever seen mir::test::fake_shared?).
It's using the line number as a pointer address so that calling Session::default_surface does not return nullptr, which is a condition for a Application::foregroundSession sourced by a PromptSession.
Not ideal, but that's why the TODO is there.

>
> + {
> + return 0;
> strange indent

Done

228. By Nick Dedekind

removed whitespace

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:228
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nick-dedekind/unity-mir/trusted-sessions/+merge/224397/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-mir-devel-ci/31/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-amd64-ci/31/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-armhf-ci/31/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-devel-utopic-i386-ci/31/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-mir-devel-ci/31/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:227
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nick-dedekind/unity-mir/trusted-sessions/+merge/224397/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-mir-ci/383/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-amd64-ci/47
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-armhf-ci/47
        deb: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-armhf-ci/47/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-i386-ci/47

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-mir-ci/383/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:228
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~nick-dedekind/unity-mir/trusted-sessions/+merge/224397/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-mir-ci/386/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-amd64-ci/50/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-armhf-ci/50/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/unity-mir-utopic-i386-ci/50/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-mir-ci/386/rebuild

review: Needs Fixing (continuous-integration)
229. By Nick Dedekind

merged with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
230. By Nick Dedekind

fixed build

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

This needed?
+ info->contains("unity8") ||

Functional testing with your demo trust sessions app. For anyone else playing along at home, I did:
  bzr branch lp:~nick-dedekind/+junk/trusted_sessions_app
  sudo apt-get build-dep unity-mir
  mkdir BUILD && cd BUILD
  cmake .. -DCMAKE_INSTALL_PREFIX=/usr
  make -j4
On the phone I launched calculator & clock. Calculator in the foreground, I ran:
  ./trust-session-demo-trusted-helper -p `pgrep -f calculator`

Which worked fine.

Problem cases:
1. if calculator in the background (clock in foreground) and its trust helper opened, the trust helper appears on top of the clock app.
2. continuing problem 1, if you do a right-edge swipe to reveal spread, the preview for calculator is empty (just see a weird shadow). Tapping it brings back the trust helper screen though
3. if you open calculator's trust helper, then left-edge swipe, the trust helper closes. Intended?
4. strange things happen if I try to open 2 trust prompt sessions, one for 2 different apps. I guess that's kinda unlikely.
5. For 1 app, I opened 2 trust helpers running simultaneously. When I returned to Dash, then went back to the app, one trust helper had quit, but the other had not. Another odd situation I'm creating?
6. Clock in foreground, opened trust helper for it. Then in shell, caused app to die unexpectedly with "kill -9 `pgrep -f clock`" - shell crashed

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> This needed?
> + info->contains("unity8") ||

Yes for now. When we create new sockets for the providers, the mir authorizes with the server pid, which is unity8 (since there is nothing connected to the socket yet).
It's possible that this is not right in mir and the session needs auth only when the connection is made by a client...
This will go away when we start using the trust socket (which skips the auth), as children inherit their parent's permission.

>
> Functional testing with your demo trust sessions app. For anyone else playing
> along at home, I did:
> bzr branch lp:~nick-dedekind/+junk/trusted_sessions_app
> sudo apt-get build-dep unity-mir
> mkdir BUILD && cd BUILD
> cmake .. -DCMAKE_INSTALL_PREFIX=/usr
> make -j4
> On the phone I launched calculator & clock. Calculator in the foreground, I
> ran:
> ./trust-session-demo-trusted-helper -p `pgrep -f calculator`
>
> Which worked fine.
>
>
>
> Problem cases:
> 1. if calculator in the background (clock in foreground) and its trust helper
> opened, the trust helper appears on top of the clock app.

Will take a look.
Technically I think this is a mir issue. It shouldn't be focusing to newly created sessions; that should be focus policy controlled by shell... Bad Mir!
Will need to jiggery poke it.

> 2. continuing problem 1, if you do a right-edge swipe to reveal spread, the
> preview for calculator is empty (just see a weird shadow). Tapping it brings
> back the trust helper screen though

Hm. When we add a provider to a prompt session, I take a new application snapshot. This however does not guarantee that anything has yet been drawn on the surface of the prompt provider surface... Not sure how to fix this.

> 3. if you open calculator's trust helper, then left-edge swipe, the trust
> helper closes. Intended?

yes. at the moment, trust helpers do not survive context switches.

> 4. strange things happen if I try to open 2 trust prompt sessions, one for 2
> different apps. I guess that's kinda unlikely.

Mmm.. multiple prompt sessions are not yet supported.

> 5. For 1 app, I opened 2 trust helpers running simultaneously. When I returned
> to Dash, then went back to the app, one trust helper had quit, but the other
> had not. Another odd situation I'm creating?

As above

> 6. Clock in foreground, opened trust helper for it. Then in shell, caused app
> to die unexpectedly with "kill -9 `pgrep -f clock`" - shell crashed

I've taken a quick look and it seems to be crashing when taking a screenshot of a session which is being closed. Haven't dug into to it, but it doesn't seem related to trust sessions, only a result of their usage.

231. By Nick Dedekind

fixed dlog

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
232. By Nick Dedekind

merged with lp:~nick-dedekind/unity-mir/thready-screenshotting

233. By Nick Dedekind

remerged with thready branch

234. By Nick Dedekind

remove authorise dodgeys for prompt sessions

235. By Nick Dedekind

reverted changes to debian/control & debian/changelog

236. By Nick Dedekind

bumped to 0.5

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-07-01 14:19:04 +0000
3+++ debian/changelog 2014-07-10 11:50:19 +0000
4@@ -1,21 +1,3 @@
5-unity-mir (0.4+14.10.20140701.1-0ubuntu1) utopic; urgency=low
6-
7- [ Alexandros Frantzis ]
8- * Use surface relative coordinates when setting the input region for
9- the input area Mir changed at some point to use surface relative
10- coordinates for input regions. (LP: #1332624)
11-
12- [ Gerry Boland ]
13- * Bump Mir dependencies to 0.4.0.
14-
15- [ Cemil Azizoglu ]
16- * Bump Mir dependencies to 0.4.0.
17-
18- [ Alberto Aguirre ]
19- * Bump Mir dependencies to 0.4.0.
20-
21- -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 01 Jul 2014 14:19:04 +0000
22-
23 unity-mir (0.4+14.10.20140625.2-0ubuntu1) utopic; urgency=low
24
25 [ Ubuntu daily release ]
26
27=== modified file 'debian/control'
28--- debian/control 2014-06-27 01:05:20 +0000
29+++ debian/control 2014-07-10 11:50:19 +0000
30@@ -9,8 +9,8 @@
31 libboost-dev,
32 libboost-system-dev,
33 libubuntu-application-api-dev (>= 2.0.0),
34- libmirserver-dev (>= 0.4.0),
35- libmirclient-dev (>= 0.4.0),
36+ libmirserver-dev (>= 0.3.0),
37+ libmirclient-dev (>= 0.1.9),
38 libprocess-cpp-dev,
39 libunity-api-dev (>= 7.80.6),
40 libubuntu-app-launch2-dev,
41
42=== modified file 'src/modules/Unity/Application/application.cpp'
43--- src/modules/Unity/Application/application.cpp 2014-05-26 15:54:44 +0000
44+++ src/modules/Unity/Application/application.cpp 2014-07-10 11:50:19 +0000
45@@ -26,6 +26,15 @@
46 // mir
47 #include <mir/scene/session.h>
48 #include <mir/scene/snapshot.h>
49+#include <mir/scene/prompt_session.h>
50+#include <mir/scene/prompt_session_manager.h>
51+
52+namespace ms = mir::scene;
53+
54+// other
55+#include <mutex>
56+
57+std::mutex screenshotMutex;
58
59 namespace unitymir
60 {
61@@ -34,6 +43,7 @@
62 DesktopFileReader *desktopFileReader,
63 State state,
64 const QStringList &arguments,
65+ const std::shared_ptr<ms::PromptSessionManager>& promptSessionManager,
66 QObject *parent)
67 : ApplicationInfoInterface(desktopFileReader->appId(), parent)
68 , m_taskController(taskController)
69@@ -47,6 +57,8 @@
70 , m_visible(false)
71 , m_arguments(arguments)
72 , m_suspendTimer(new QTimer(this))
73+ , m_promptSessionManager(promptSessionManager)
74+ , m_screenShotGuard(std::make_shared<Guard>())
75 {
76 DLOG("Application::Application (this=%p, appId=%s, state=%d", this, qPrintable(desktopFileReader->appId()),
77 static_cast<int>(state));
78@@ -56,10 +68,17 @@
79
80 // FIXME(greyback) need to save long appId internally until upstart-app-launch can hide it from us
81 m_longAppId = desktopFileReader->file().remove(QRegExp(".desktop$")).split('/').last();
82+
83+ connect(this, &Application::foregroundSessionChanged, this, &Application::updateScreenshot);
84 }
85
86 Application::~Application()
87 {
88+ {
89+ std::lock_guard<std::mutex> lk(screenshotMutex);
90+ m_screenShotGuard.reset();
91+ }
92+
93 DLOG("Application::~Application (this=%p)", this);
94 delete m_desktopData;
95 }
96@@ -133,11 +152,66 @@
97 return m_fullscreen;
98 }
99
100-std::shared_ptr<mir::scene::Session> Application::session() const
101+std::shared_ptr<ms::Session> Application::session() const
102 {
103 return m_session;
104 }
105
106+std::shared_ptr<ms::Session> Application::foregroundSession() const
107+{
108+ std::shared_ptr<ms::Session> child;
109+
110+ QListIterator<std::shared_ptr<ms::PromptSession>> iter(m_promptSessions);
111+ iter.toBack();
112+ while (iter.hasPrevious()) {
113+ std::shared_ptr<ms::PromptSession> promptSession = iter.previous();
114+
115+ // get top session
116+ m_promptSessionManager->for_each_provider_in(promptSession,
117+ [&child](std::shared_ptr<ms::Session> const& provider) {
118+ if (provider->default_surface() != nullptr)
119+ child = provider;
120+ });
121+
122+ if (child)
123+ return child;
124+ }
125+
126+ return session();
127+}
128+
129+std::shared_ptr<ms::PromptSession> Application::activePromptSession() const
130+{
131+ if (m_promptSessions.count() > 0)
132+ return m_promptSessions.back();
133+ return nullptr;
134+}
135+
136+bool Application::containsProcess(pid_t pid) const
137+{
138+ if (m_pid == pid)
139+ return true;
140+
141+ QListIterator<std::shared_ptr<ms::PromptSession>> iter(m_promptSessions);
142+ while(iter.hasNext()) {
143+ std::shared_ptr<ms::PromptSession> promptSession = iter.next();
144+
145+ std::shared_ptr<ms::Session> helper = m_promptSessionManager->helper_for(promptSession);
146+ if (helper && helper->process_id() == pid)
147+ return true;
148+
149+ bool found = false;
150+ m_promptSessionManager->for_each_provider_in(promptSession,
151+ [&found, pid](std::shared_ptr<ms::Session> const& provider) {
152+ if (provider->process_id() == pid)
153+ found = true;
154+ });
155+ if (found)
156+ return true;
157+ }
158+ return false;
159+}
160+
161 bool Application::visible() const
162 {
163 return m_visible;
164@@ -163,13 +237,35 @@
165 m_pid = pid;
166 }
167
168-void Application::setSession(const std::shared_ptr<mir::scene::Session>& session)
169+void Application::setSession(const std::shared_ptr<ms::Session>& session)
170 {
171 DLOG("Application::setSession (this=%p, session=%p)", this, session.get());
172
173 // TODO(greyback) what if called with new surface?
174 m_session = session;
175 m_visible = true; // bit of an assumption that, but no other way to deduce an actual Surface has been created
176+ checkSessionChanges();
177+}
178+
179+void Application::appendPromptSession(const std::shared_ptr<ms::PromptSession>& promptSession)
180+{
181+ DLOG("Application::setPromptSession (this=%p, promptSession=%p)", this, promptSession ? promptSession.get() : nullptr);
182+
183+ m_promptSessions.append(promptSession);
184+ checkSessionChanges();
185+}
186+
187+void Application::removePromptSession(const std::shared_ptr<ms::PromptSession>& promptSession)
188+{
189+ DLOG("Application::setPromptSession (this=%p, promptSession=%p)", this, promptSession ? promptSession.get() : nullptr);
190+
191+ QMutableListIterator<std::shared_ptr<ms::PromptSession>> iter(m_promptSessions);
192+ while(iter.hasNext()) {
193+ if (iter.next() == promptSession) {
194+ iter.remove();
195+ checkSessionChanges();
196+ }
197+ }
198 }
199
200 void Application::setSessionName(const QString& name)
201@@ -198,9 +294,17 @@
202
203 void Application::updateScreenshot()
204 {
205- session()->take_snapshot(
206- [&](mir::scene::Snapshot const& snapshot)
207+ if (!foregroundSession())
208+ return;
209+ std::weak_ptr<Guard> wk(m_screenShotGuard);
210+
211+ foregroundSession()->take_snapshot(
212+ [&, wk](mir::scene::Snapshot const& snapshot)
213 {
214+ std::lock_guard<std::mutex> lk(screenshotMutex);
215+ if (!wk.lock())
216+ return;
217+
218 DLOG("ApplicationScreenshotProvider - Mir snapshot ready with size %d x %d",
219 snapshot.size.height.as_int(), snapshot.size.width.as_int());
220
221@@ -222,7 +326,8 @@
222 {
223 case Application::Suspended:
224 if (m_state == Application::Running) {
225- session()->set_lifecycle_state(mir_lifecycle_state_will_suspend);
226+ if (session())
227+ session()->set_lifecycle_state(mir_lifecycle_state_will_suspend);
228 m_suspendTimer->start(3000);
229 }
230 break;
231@@ -232,7 +337,8 @@
232
233 if (m_state == Application::Suspended) {
234 resume();
235- session()->set_lifecycle_state(mir_lifecycle_state_resumed);
236+ if (session())
237+ session()->set_lifecycle_state(mir_lifecycle_state_resumed);
238 } else if (m_state == Application::Stopped) {
239 respawn();
240 state = Application::Starting;
241@@ -272,7 +378,7 @@
242 {
243 DLOG("Application::setVisible (this=%p, visible=%s)", this, visible ? "yes" : "no");
244 // FIXME: this is bad, as should a MirSurface of this app exist, it won't be notified of the visiblity change.
245- if (visible != m_visible) {
246+ if (m_session && visible != m_visible) {
247 if (visible) {
248 m_session->show();
249 } else {
250@@ -306,4 +412,14 @@
251 return m_longAppId;
252 }
253
254+void Application::checkSessionChanges()
255+{
256+ ms::Session* lastTopSession = m_lastForegroundSession;
257+ ms::Session* currentTopSession = foregroundSession().get();
258+ m_lastForegroundSession = currentTopSession;
259+ if (currentTopSession && currentTopSession != lastTopSession) {
260+ Q_EMIT foregroundSessionChanged();
261+ }
262+}
263+
264 } // namespace unitymir
265
266=== modified file 'src/modules/Unity/Application/application.h'
267--- src/modules/Unity/Application/application.h 2014-05-16 15:40:00 +0000
268+++ src/modules/Unity/Application/application.h 2014-07-10 11:50:19 +0000
269@@ -29,7 +29,13 @@
270 #include <unity/shell/application/ApplicationInfoInterface.h>
271
272 class QImage;
273-namespace mir { namespace scene { class Session; }}
274+namespace mir {
275+ namespace scene {
276+ class Session;
277+ class PromptSession;
278+ class PromptSessionManager;
279+ }
280+}
281
282 namespace unitymir
283 {
284@@ -50,6 +56,7 @@
285 DesktopFileReader *desktopFileReader,
286 State state,
287 const QStringList &arguments,
288+ const std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager,
289 QObject *parent = 0);
290 virtual ~Application();
291
292@@ -69,7 +76,6 @@
293 void setVisible(const bool);
294
295 QImage screenshotImage() const;
296- void updateScreenshot();
297
298 bool canBeResumed() const;
299 void setCanBeResumed(const bool);
300@@ -78,17 +84,26 @@
301 QString desktopFile() const;
302 QString exec() const;
303 bool fullscreen() const;
304- std::shared_ptr<::mir::scene::Session> session() const;
305 pid_t pid() const;
306
307+ std::shared_ptr<mir::scene::Session> session() const;
308+ std::shared_ptr<mir::scene::Session> foregroundSession() const;
309+ std::shared_ptr<mir::scene::PromptSession> activePromptSession() const;
310+
311+ bool containsProcess(pid_t pid) const;
312+
313+ void checkSessionChanges();
314+
315 public Q_SLOTS:
316 void suspend();
317 void resume();
318 void respawn();
319+ void updateScreenshot();
320
321 Q_SIGNALS:
322 void fullscreenChanged();
323 void stageChanged(Stage stage);
324+ void foregroundSessionChanged();
325 void visibleChanged();
326
327 private:
328@@ -97,9 +112,12 @@
329 void setState(State state);
330 void setFocused(bool focus);
331 void setFullscreen(bool fullscreen);
332- void setSession(const std::shared_ptr<::mir::scene::Session>& session);
333 void setSessionName(const QString& name);
334
335+ void setSession(const std::shared_ptr<mir::scene::Session>& session);
336+ void appendPromptSession(const std::shared_ptr<mir::scene::PromptSession>& session);
337+ void removePromptSession(const std::shared_ptr<mir::scene::PromptSession>& session);
338+
339 QSharedPointer<TaskController> m_taskController;
340 DesktopFileReader* m_desktopData;
341 QString m_longAppId;
342@@ -111,11 +129,17 @@
343 QImage m_screenshotImage;
344 bool m_canBeResumed;
345 bool m_fullscreen;
346+ std::shared_ptr<mir::scene::Session> m_session;
347+ QList<std::shared_ptr<mir::scene::PromptSession>> m_promptSessions;
348 bool m_visible; // duplicating internal Mir data :(
349- std::shared_ptr<::mir::scene::Session> m_session;
350 QString m_sessionName;
351 QStringList m_arguments;
352 QTimer* m_suspendTimer;
353+ mutable mir::scene::Session* m_lastForegroundSession;
354+ std::shared_ptr<mir::scene::PromptSessionManager> const m_promptSessionManager;
355+
356+ class Guard {};
357+ std::shared_ptr<Guard> m_screenShotGuard;
358
359 friend class ApplicationManager;
360 friend class MirSurfaceManager;
361
362=== modified file 'src/modules/Unity/Application/application_manager.cpp'
363--- src/modules/Unity/Application/application_manager.cpp 2014-06-25 15:30:50 +0000
364+++ src/modules/Unity/Application/application_manager.cpp 2014-07-10 11:50:19 +0000
365@@ -31,18 +31,23 @@
366 #include "initialsurfaceplacementstrategy.h"
367 #include "taskcontroller.h"
368 #include "logging.h"
369+#include "promptsessionlistener.h"
370
371 // mir
372 #include <mir/scene/depth_id.h>
373 #include <mir/scene/session.h>
374 #include <mir/shell/focus_controller.h>
375 #include <mir/scene/surface.h>
376+#include <mir/scene/prompt_session.h>
377 #include <mir/graphics/display.h>
378 #include <mir/graphics/display_buffer.h>
379 #include <mircommon/mir/geometry/rectangles.h>
380+#include <mir/frontend/shell.h>
381+#include <mir/scene/prompt_session_manager.h>
382
383 // Qt
384 #include <QCoreApplication>
385+#include <QThread>
386
387 // std
388 #include <csignal>
389@@ -102,6 +107,20 @@
390 manager, &ApplicationManager::onSessionCreatedSurface);
391 }
392
393+void connectToPromptSessionListener(ApplicationManager * manager, PromptSessionListener * listener)
394+{
395+ QObject::connect(listener, &PromptSessionListener::promptSessionStarting,
396+ manager, &ApplicationManager::onPromptSessionStarting);
397+ QObject::connect(listener, &PromptSessionListener::promptSessionStopping,
398+ manager, &ApplicationManager::onPromptSessionStopping);
399+
400+ QObject::connect(listener, &PromptSessionListener::promptProviderAdded,
401+ manager, &ApplicationManager::onPromptProviderAdded);
402+ QObject::connect(listener, &PromptSessionListener::promptProviderRemoved,
403+ manager, &ApplicationManager::onPromptProviderRemoved);
404+
405+}
406+
407 void connectToSessionAuthorizer(ApplicationManager * manager, SessionAuthorizer * authorizer)
408 {
409 QObject::connect(authorizer, &SessionAuthorizer::requestAuthorizationForSession,
410@@ -151,17 +170,19 @@
411 // FIXME: We should use a QSharedPointer to wrap this ApplicationManager object, which requires us
412 // to use the data() method to pass the raw pointer to the QML engine. However the QML engine appears
413 // to take ownership of the object, and deletes it when it wants to. This conflicts with the purpose
414- // of the QSharedPointer, and a double-delete results. Trying QQmlEngine::setObjectOwnership on the
415+ // of the QSharedPointer, and a double-delete results. Trying QQmlEngine::setObjectOwnership on the
416 // object no effect, which it should. Need to investigate why.
417 ApplicationManager* appManager = new ApplicationManager(
418 taskController,
419 fileReaderFactory,
420 procInfo,
421 mirServer->the_focus_controller(),
422+ mirServer->the_prompt_session_manager(),
423 displaySize
424 );
425
426 connectToSessionListener(appManager, mirServer->sessionListener());
427+ connectToPromptSessionListener(appManager, mirServer->promptSessionListener());
428 connectToSessionAuthorizer(appManager, mirServer->sessionAuthorizer());
429 connectToPlacementStrategy(appManager, mirServer->placementStrategy());
430 connectToTaskController(appManager, taskController.data());
431@@ -183,7 +204,8 @@
432 const QSharedPointer<TaskController>& taskController,
433 const QSharedPointer<DesktopFileReader::Factory>& desktopFileReaderFactory,
434 const QSharedPointer<ProcInfo>& procInfo,
435- const std::shared_ptr<mir::shell::FocusController>& controller,
436+ const std::shared_ptr<mir::shell::FocusController>& focusController,
437+ const std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager,
438 const QSize& displaySize,
439 QObject *parent)
440 : ApplicationManagerInterface(parent)
441@@ -193,13 +215,13 @@
442 , m_msApplicationToBeFocused(nullptr)
443 , m_ssApplicationToBeFocused(nullptr)
444 , m_lifecycleExceptions(QStringList() << "com.ubuntu.music")
445- , m_focusController(controller)
446+ , m_focusController(focusController)
447+ , m_promptSessionManager(promptSessionManager)
448 , m_dbusWindowStack(new DBusWindowStack(this))
449 , m_taskController(taskController)
450 , m_desktopFileReaderFactory(desktopFileReaderFactory)
451 , m_procInfo(procInfo)
452 , m_gridUnitPx(8)
453- , m_fenceNext(false)
454 , m_displaySize(displaySize)
455 , m_panelHeight(54)
456 {
457@@ -385,15 +407,15 @@
458 DLOG("No such running application '%s'", qPrintable(appId));
459 return false;
460 }
461-
462+
463 if (application->stage() == Application::MainStage && m_sideStageApplication)
464 suspendApplication(m_sideStageApplication);
465-
466+
467 if (application->stage() == Application::MainStage)
468 m_msApplicationToBeFocused = application;
469 else
470 m_ssApplicationToBeFocused = application;
471-
472+
473 if (application->state() == Application::Stopped) {
474 // Respawning this app, move to end of application list so onSessionStarting works ok
475 // FIXME: this happens pretty late, shell could request respawn earlier
476@@ -401,8 +423,9 @@
477 int from = m_applications.indexOf(application);
478 move(from, m_applications.length()-1);
479 } else {
480- if (application->session()) {
481- m_focusController->set_focus_to(application->session());
482+ auto mirSession = application->foregroundSession();
483+ if (mirSession) {
484+ m_focusController->set_focus_to(mirSession);
485 int from = m_applications.indexOf(application);
486 move(from, 0);
487 }
488@@ -474,6 +497,7 @@
489 m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)),
490 Application::Starting,
491 arguments,
492+ m_promptSessionManager,
493 this);
494 if (!application->isValid()) {
495 DLOG("Unable to instantiate application with appId '%s'", qPrintable(appId));
496@@ -499,7 +523,9 @@
497 m_taskController,
498 m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)),
499 Application::Starting,
500- QStringList(), this);
501+ QStringList(),
502+ m_promptSessionManager,
503+ this);
504 if (!application->isValid()) {
505 DLOG("Unable to instantiate application with appId '%s'", qPrintable(appId));
506 return;
507@@ -703,14 +729,25 @@
508
509 if (info->startsWith("maliit-server") || info->contains("qt5/libexec/QtWebProcess")) {
510 authorized = true;
511- m_fenceNext = true;
512+ m_hiddenPIDs << pid;
513+ return;
514+ }
515+
516+ const quint64 ppid = m_procInfo->parentProcess(pid);
517+ if (info->contains("trust-session-demo-trusted-helper") ||
518+ info->contains("unity8") ||
519+ (ppid != 0 && m_procInfo->commandLine(ppid)->contains("trust-session-demo-trusted-helper"))) {
520+ DLOG("ApplicationManager ACCEPTED trust app %lld", pid);
521+ authorized = true;
522+ m_hiddenPIDs << pid;
523 return;
524 }
525
526 boost::optional<QString> desktopFileName{ info->getParameter("--desktop_file_hint=") };
527
528 if (!desktopFileName) {
529- LOG("ApplicationManager REJECTED connection from app with pid %lld as no desktop_file_hint specified", pid);
530+ LOG("ApplicationManager REJECTED connection from app with pid %lld as no desktop_file_hint specified (%s)", pid,
531+ qPrintable(info->asStringList().first()));
532 return;
533 }
534
535@@ -758,7 +795,13 @@
536 DLOG("Existing process with pid %lld appeared, adding '%s' to application lists", pid, desktopData->name().toLatin1().data());
537
538 QStringList arguments(info->asStringList());
539- application = new Application(m_taskController, desktopData, Application::Starting, arguments, this);
540+ application = new Application(
541+ m_taskController,
542+ desktopData,
543+ Application::Starting,
544+ arguments,
545+ m_promptSessionManager,
546+ this);
547 application->setPid(pid);
548 application->setStage(stage);
549 application->setCanBeResumed(false);
550@@ -768,11 +811,11 @@
551
552 void ApplicationManager::placeSession(ms::Session const* session, uint32_t &x, uint32_t &y)
553 {
554- Application* application = findApplicationWithSession(session);
555+ Application* application = findApplicationWithSession(session, true);
556 DLOG("ApplicationManager::placeSession (this=%p, application=%p, session=%p, name=%s)", this, application, session,
557 session?(session->name().c_str()):"null");
558
559- // Application defaults
560+ // Application defaults
561 x = 0;
562 y = m_panelHeight;
563
564@@ -789,7 +832,7 @@
565 // SideStage override
566 if (application && application->stage() == Application::SideStage)
567 x = m_displaySize.width() - (SIDE_STAGE_WIDTH_GU * m_gridUnitPx);
568-
569+
570 DLOG("ApplicationManager::placeSession (x=%d, y=%d)", x, y);
571 }
572
573@@ -797,12 +840,9 @@
574 {
575 DLOG("ApplicationManager::onSessionStarting (this=%p, application=%s)", this, session?session->name().c_str():"null");
576
577- if (m_fenceNext) {
578- m_fenceNext = false;
579- return;
580- }
581+ pid_t pid = session->process_id();
582
583- Application* application = findApplicationWithPid(session->process_id());
584+ Application* application = findApplicationWithPid(session->process_id(), false);
585 if (application && application->state() != Application::Running) {
586 application->setSession(session);
587 if (application->stage() == Application::MainStage)
588@@ -810,18 +850,18 @@
589 else
590 m_ssApplicationToBeFocused = application;
591 } else {
592+ if (m_hiddenPIDs.contains(pid)) {
593+ return;
594+ }
595 DLOG("ApplicationManager::onSessionStarting - unauthorized application!!");
596 }
597 }
598
599 void ApplicationManager::onSessionStopping(const std::shared_ptr<ms::Session>& session)
600 {
601- // in case application closed not by hand of shell, check again here:
602- Application* application = findApplicationWithSession(session);
603-
604- DLOG("ApplicationManager::onSessionStopping (this=%p, application=%p, appId=%s, session name=%s)", this, application,
605- application?qPrintable(application->appId()):"null", session?session->name().c_str():"null");
606-
607+ DLOG("ApplicationManager::onSessionStopping (this=%p, session name=%s)", this, session?session->name().c_str():"null");
608+
609+ Application* application = findApplicationWithSession(session, false); // only check app sessions
610 if (application) {
611 /* Can remove the application from the running apps list immediately in these curcumstances:
612 * 1. application is not managed by upstart (this message from Mir is only notice the app has stopped, must do
613@@ -844,17 +884,19 @@
614 application->setState(Application::Stopped);
615 }
616 }
617+
618+ m_hiddenPIDs.removeOne(session->process_id());
619 }
620
621 void ApplicationManager::onSessionFocused(const std::shared_ptr<ms::Session>& session)
622 {
623- Application* application = findApplicationWithSession(session);
624+ Application* application = findApplicationWithSession(session, true);
625 DLOG("ApplicationManager::onSessionFocused (this=%p, application=%p, appId=%s, session name=%s)", this, application,
626 application?qPrintable(application->appId()):"null", session?session->name().c_str():"null");
627
628 // Don't give application focus until it has created it's surface, when it is set as state "Running"
629 // and only notify shell of focus changes that it actually expects
630- if (application && application->state() != Application::Starting &&
631+ if (application && application->state() != Application::Starting &&
632 (application == m_msApplicationToBeFocused ||
633 application == m_ssApplicationToBeFocused)
634 && application != m_focusedApplication) {
635@@ -864,10 +906,14 @@
636 } else {
637 if (application == nullptr) {
638 DLOG("Invalid application focused, discarding the event");
639- if (nullptr != m_focusedApplication)
640+ if (nullptr != m_focusedApplication) {
641 focusApplication(m_focusedApplication->appId());
642- else
643+ } else {
644 m_focusController->set_focus_to(nullptr);
645+ }
646+ } else if (application == m_focusedApplication && session != application->foregroundSession()) {
647+ DLOG("Focused session is not on top. Resetting focus");
648+ focusApplication(application->appId());
649 }
650 }
651 }
652@@ -878,7 +924,8 @@
653 if (nullptr != m_focusedApplication) {
654 Q_ASSERT(m_focusedApplication->focused());
655 m_focusedApplication->setFocused(false);
656-
657+
658+ auto lastFocusedApp = m_focusedApplication;
659 suspendApplication(m_focusedApplication);
660
661 m_focusedApplication = nullptr;
662@@ -887,22 +934,87 @@
663
664 QModelIndex appIndex = findIndex(m_focusedApplication);
665 Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleFocused << RoleState);
666+
667+ if (lastFocusedApp && lastFocusedApp->activePromptSession()) {
668+ m_promptSessionManager->stop_prompt_session(lastFocusedApp->activePromptSession());
669+ }
670 }
671 }
672
673 void ApplicationManager::onSessionCreatedSurface(const ms::Session * session,
674 const std::shared_ptr<ms::Surface> & surface)
675 {
676- DLOG("ApplicationManager::onSessionCreatedSurface (this=%p)", this);
677+ DLOG("ApplicationManager::onSessionCreatedSurface (this=%p, appId=%s)", this, session->name().c_str());
678 Q_UNUSED(surface);
679
680- Application* application = findApplicationWithSession(session);
681- if (application && application->state() == Application::Starting) {
682- m_dbusWindowStack->WindowCreated(0, application->appId());
683- // only when Session creates a Surface will we actually mark it focused
684- setFocused(application);
685- QModelIndex appIndex = findIndex(application);
686- Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleFocused);
687+ Application* application = findApplicationWithSession(session, true);
688+ if (application) {
689+ if (application->state() == Application::Starting) {
690+ m_dbusWindowStack->WindowCreated(0, application->appId());
691+ // only when Session creates a Surface will we actually mark it focused
692+ setFocused(application);
693+ QModelIndex appIndex = findIndex(application);
694+ Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleFocused);
695+ }
696+
697+ application->checkSessionChanges();
698+ }
699+}
700+
701+void ApplicationManager::onPromptSessionStarting(const std::shared_ptr<ms::PromptSession>& promptSession)
702+{
703+ DLOG("ApplicationManager::onPromptSessionStarting (this=%p, prompt_session=%p)", this, promptSession.get());
704+
705+ Application* app = findApplicationWithSession(m_promptSessionManager->application_for(promptSession), false);
706+ if (app) {
707+ app->appendPromptSession(promptSession);
708+ } else {
709+ DLOG("ApplicationManager::onPromptSessionStarting - no app found (prompt_session=%p)", promptSession.get());
710+ }
711+}
712+
713+void ApplicationManager::onPromptSessionStopping(const std::shared_ptr<ms::PromptSession>& promptSession)
714+{
715+ DLOG("ApplicationManager::onPromptSessionStopping (this=%p, prompt_session=%p)", this, promptSession.get());
716+
717+ for (Application *app : m_applications) {
718+ app->removePromptSession(promptSession);
719+ }
720+}
721+
722+void ApplicationManager::onPromptProviderAdded(ms::PromptSession const* promptSession,
723+ const std::shared_ptr<ms::Session>& session)
724+{
725+ Q_UNUSED(promptSession);
726+ DLOG("ApplicationManager::onPromptProviderAdded (this=%p, prompt_session=%p, session=%s)", this, promptSession, session?session->name().c_str():"null");
727+
728+ Application* app = findApplicationWithSession(session, true);
729+ if (app) {
730+ app->checkSessionChanges();
731+
732+ if (app == m_focusedApplication) {
733+ focusApplication(app->appId());
734+ }
735+ } else {
736+ DLOG("ApplicationManager::onPromptProviderAdded - no app found (prompt_session=%p)", promptSession);
737+ }
738+}
739+
740+void ApplicationManager::onPromptProviderRemoved(ms::PromptSession const* promptSession,
741+ const std::shared_ptr<ms::Session>& session)
742+{
743+ Q_UNUSED(session);
744+ DLOG("ApplicationManager::onPromptProviderAdded (this=%p, prompt_session=%p, session=%s)", this, (void*)promptSession, session?session->name().c_str():"null");
745+
746+ // we need to update the focus if the app is in focus.
747+ for (Application *app : m_applications) {
748+ if (promptSession == app->activePromptSession().get()) {
749+ app->checkSessionChanges();
750+
751+ if (app == m_focusedApplication) {
752+ focusApplication(app->appId());
753+ }
754+ }
755 }
756 }
757
758@@ -925,6 +1037,7 @@
759 else
760 m_sideStageApplication = application;
761
762+ auto lastFocusedApp = m_focusedApplication;
763 m_focusedApplication = application;
764 m_focusedApplication->setFocused(true);
765 m_focusedApplication->setVisible(true);
766@@ -932,24 +1045,26 @@
767 move(m_applications.indexOf(application), 0);
768 Q_EMIT focusedApplicationIdChanged();
769 m_dbusWindowStack->FocusedWindowChanged(0, application->appId(), application->stage());
770-}
771-
772-Application* ApplicationManager::findApplicationWithSession(const std::shared_ptr<ms::Session> &session)
773-{
774- return findApplicationWithSession(session.get());
775-}
776-
777-Application* ApplicationManager::findApplicationWithSession(const ms::Session *session)
778-{
779- for (Application *app : m_applications) {
780- if (app->session().get() == session) {
781- return app;
782- }
783+
784+ // stop prompt session when focus changes.
785+ if (lastFocusedApp && lastFocusedApp->activePromptSession()) {
786+ m_promptSessionManager->stop_prompt_session(lastFocusedApp->activePromptSession());
787 }
788- return nullptr;
789-}
790-
791-Application* ApplicationManager::findApplicationWithPid(const qint64 pid)
792+}
793+
794+Application* ApplicationManager::findApplicationWithSession(const std::shared_ptr<ms::Session> &session, bool includeChildSessions)
795+{
796+ return findApplicationWithSession(session.get(), includeChildSessions);
797+}
798+
799+Application* ApplicationManager::findApplicationWithSession(const ms::Session *session, bool includeChildSessions)
800+{
801+ if (!session)
802+ return nullptr;
803+ return findApplicationWithPid(session->process_id(), includeChildSessions);
804+}
805+
806+Application* ApplicationManager::findApplicationWithPid(const qint64 pid, bool includeChildSessions)
807 {
808 if (pid <= 0)
809 return nullptr;
810@@ -958,6 +1073,10 @@
811 if (app->m_pid == pid) {
812 return app;
813 }
814+
815+ if (includeChildSessions && app->containsProcess(pid)) {
816+ return app;
817+ }
818 }
819 return nullptr;
820 }
821@@ -1006,7 +1125,8 @@
822 }
823 }
824
825-void ApplicationManager::move(int from, int to) {
826+void ApplicationManager::move(int from, int to)
827+{
828 DLOG("ApplicationManager::move (this=%p, from=%d, to=%d)", this, from, to);
829 if (from == to) return;
830
831@@ -1036,8 +1156,15 @@
832 {
833 if (application == m_focusedApplication) {
834 // TODO(greyback) What to do?? Focus next app, or unfocus everything??
835+ auto lastFocusedApp = m_focusedApplication;
836 m_focusedApplication = nullptr;
837 Q_EMIT focusedApplicationIdChanged();
838+
839+ // stop prompt session when focus changes.
840+ if (lastFocusedApp && lastFocusedApp->activePromptSession()) {
841+ m_promptSessionManager->stop_prompt_session(lastFocusedApp->activePromptSession());
842+ }
843+
844 return true;
845 }
846 return false;
847
848=== modified file 'src/modules/Unity/Application/application_manager.h'
849--- src/modules/Unity/Application/application_manager.h 2014-05-26 15:54:44 +0000
850+++ src/modules/Unity/Application/application_manager.h 2014-07-10 11:50:19 +0000
851@@ -41,6 +41,8 @@
852 namespace scene {
853 class Session;
854 class Surface;
855+ class PromptSession;
856+ class PromptSessionManager;
857 }
858 namespace shell {
859 class FocusController;
860@@ -79,8 +81,9 @@
861 explicit ApplicationManager(const QSharedPointer<TaskController>& taskController,
862 const QSharedPointer<DesktopFileReader::Factory>& desktopFileReaderFactory,
863 const QSharedPointer<ProcInfo>& processInfo,
864- std::shared_ptr<mir::shell::FocusController> const& controller,
865- QSize const& displaySize,
866+ const std::shared_ptr<mir::shell::FocusController>& focusController,
867+ const std::shared_ptr<mir::scene::PromptSessionManager>& promptSessionManager,
868+ const QSize& displaySize,
869 QObject *parent = 0);
870 virtual ~ApplicationManager();
871
872@@ -106,7 +109,7 @@
873 Q_INVOKABLE void move(int from, int to);
874
875 const QList<Application*> &list() const { return m_applications; }
876- unitymir::Application* findApplicationWithPid(const qint64 pid);
877+ Application* findApplicationWithPid(const qint64 pid, bool includeChildSessions);
878
879 // Internal helpers
880 bool suspendApplication(Application *application);
881@@ -117,13 +120,18 @@
882 public Q_SLOTS:
883 void authorizeSession(const quint64 pid, bool &authorized);
884 void placeSession(::mir::scene::Session const*, uint32_t &x, uint32_t &y);
885-
886- void onSessionStarting(std::shared_ptr<::mir::scene::Session> const& session);
887- void onSessionStopping(std::shared_ptr<::mir::scene::Session> const& session);
888- void onSessionFocused(std::shared_ptr<::mir::scene::Session> const& session);
889+
890+ void onSessionStarting(const std::shared_ptr<::mir::scene::Session>& session);
891+ void onSessionStopping(const std::shared_ptr<::mir::scene::Session>& session);
892+ void onSessionFocused(const std::shared_ptr<::mir::scene::Session>& session);
893 void onSessionUnfocused();
894
895- void onSessionCreatedSurface(::mir::scene::Session const*, std::shared_ptr<::mir::scene::Surface> const&);
896+ void onPromptSessionStarting(const std::shared_ptr<mir::scene::PromptSession>& promptSession);
897+ void onPromptSessionStopping(const std::shared_ptr<mir::scene::PromptSession>& promptSession);
898+ void onPromptProviderAdded(mir::scene::PromptSession const* promptSession, const std::shared_ptr<mir::scene::Session>& session);
899+ void onPromptProviderRemoved(mir::scene::PromptSession const* promptSession, const std::shared_ptr<mir::scene::Session>& session);
900+
901+ void onSessionCreatedSurface(::mir::scene::Session const*, const std::shared_ptr<::mir::scene::Surface>&);
902
903 void onProcessFailed(const QString& appId, const bool duringStartup);
904 void onProcessStarting(const QString& appId);
905@@ -141,8 +149,8 @@
906 void setFocused(Application *application);
907 void add(Application *application);
908 void remove(Application* application);
909- Application* findApplicationWithSession(const std::shared_ptr<::mir::scene::Session> &session);
910- Application* findApplicationWithSession(const ::mir::scene::Session *session);
911+ Application* findApplicationWithSession(const std::shared_ptr<mir::scene::Session> &session, bool includeChildSessions);
912+ Application* findApplicationWithSession(const mir::scene::Session *session, bool includeChildSessions);
913 Application* applicationForStage(Application::Stage stage);
914 QModelIndex findIndex(Application* application);
915 bool isFocused(Application* application);
916@@ -155,13 +163,14 @@
917 Application* m_msApplicationToBeFocused; // placeholder store for async focusing
918 Application* m_ssApplicationToBeFocused; // placeholder store for async focusing
919 QStringList m_lifecycleExceptions;
920- std::shared_ptr<mir::shell::FocusController> m_focusController;
921+ std::shared_ptr<mir::shell::FocusController> const m_focusController;
922+ std::shared_ptr<mir::scene::PromptSessionManager> const m_promptSessionManager;
923 DBusWindowStack* m_dbusWindowStack;
924 QSharedPointer<TaskController> m_taskController;
925 QSharedPointer<DesktopFileReader::Factory> m_desktopFileReaderFactory;
926 QSharedPointer<ProcInfo> m_procInfo;
927 int m_gridUnitPx;
928- bool m_fenceNext;
929+ QList<pid_t> m_hiddenPIDs;
930 QString m_nextFocusedAppId;
931 QSize m_displaySize;
932 int m_panelHeight;
933
934=== modified file 'src/modules/Unity/Application/applicationscreenshotprovider.cpp'
935--- src/modules/Unity/Application/applicationscreenshotprovider.cpp 2014-04-15 14:31:02 +0000
936+++ src/modules/Unity/Application/applicationscreenshotprovider.cpp 2014-07-10 11:50:19 +0000
937@@ -52,7 +52,8 @@
938
939 // TODO: if app not ready, return an app-provided splash image. If app has been stopped with saved state
940 // return the screenshot that was saved to disk.
941- if (!app->session() || !app->session()->default_surface()) {
942+ auto mirSession = app->foregroundSession();
943+ if (!mirSession || !mirSession->default_surface()) {
944 LOG("ApplicationScreenshotProvider - app session not found - asking for screenshot too early");
945 return QImage();
946 }
947
948=== modified file 'src/modules/Unity/Application/dbuswindowstack.cpp'
949--- src/modules/Unity/Application/dbuswindowstack.cpp 2014-03-11 03:40:49 +0000
950+++ src/modules/Unity/Application/dbuswindowstack.cpp 2014-07-10 11:50:19 +0000
951@@ -47,7 +47,7 @@
952 {
953 AppIdDesktopFile res;
954 ApplicationManager *appMgr = static_cast<ApplicationManager*>(parent());
955- const Application* app = static_cast<Application*>(appMgr->findApplicationWithPid(pid));
956+ const Application* app = static_cast<Application*>(appMgr->findApplicationWithPid(pid, false));
957 if (app) {
958 res.app_id = app->appId();
959 res.desktop_file = app->desktopFile();
960
961=== modified file 'src/modules/Unity/Application/inputarea.cpp'
962--- src/modules/Unity/Application/inputarea.cpp 2014-06-27 08:36:07 +0000
963+++ src/modules/Unity/Application/inputarea.cpp 2014-07-10 11:50:19 +0000
964@@ -178,11 +178,12 @@
965 {
966 DLOG("InputArea::setMirInputArea (this=%p, x=%lf, y=%lf, width=%lf, height=%lf)", this, relativeGeometry.x(), relativeGeometry.y(), relativeGeometry.width(), relativeGeometry.height());
967 using namespace mir::geometry;
968+ const QRect rect = parentItem()->mapRectToScene(relativeGeometry).toRect();
969
970- m_mirInputArea.top_left.x = X{relativeGeometry.x()};
971- m_mirInputArea.top_left.y = Y{relativeGeometry.y()};
972- m_mirInputArea.size.width = Width{relativeGeometry.width()};
973- m_mirInputArea.size.height = Height{relativeGeometry.height()};
974+ m_mirInputArea.top_left.x = X{rect.x()};
975+ m_mirInputArea.top_left.y = Y{rect.y()};
976+ m_mirInputArea.size.width = Width{rect.width()};
977+ m_mirInputArea.size.height = Height{rect.height()};
978
979 if (m_surface) {
980 m_surface->installInputArea(this);
981
982=== modified file 'src/modules/Unity/Application/mirsurfacemanager.cpp'
983--- src/modules/Unity/Application/mirsurfacemanager.cpp 2014-04-15 14:31:02 +0000
984+++ src/modules/Unity/Application/mirsurfacemanager.cpp 2014-07-10 11:50:19 +0000
985@@ -106,8 +106,8 @@
986 {
987 DLOG("MirSurfaceManager::sessionCreatedSurface (this=%p) with surface name '%s'", this, surface->name().c_str());
988 ApplicationManager* appMgr = static_cast<ApplicationManager*>(ApplicationManager::singleton());
989- Application* application = appMgr->findApplicationWithSession(session);
990-
991+ Application* application = appMgr->findApplicationWithSession(session, false);
992+
993 auto qmlSurface = new MirSurface(surface, application);
994 m_surfaces.insert(surface.get(), qmlSurface);
995 Q_EMIT surfaceCreated(qmlSurface);
996@@ -137,7 +137,7 @@
997 if (fs) {
998 fs->set_default_keyboard_target(surface);
999 }
1000-
1001+
1002 Q_EMIT shellSurfaceChanged(m_shellSurface);
1003 }
1004
1005
1006=== modified file 'src/modules/Unity/Application/proc_info.cpp'
1007--- src/modules/Unity/Application/proc_info.cpp 2014-03-11 19:11:00 +0000
1008+++ src/modules/Unity/Application/proc_info.cpp 2014-07-10 11:50:19 +0000
1009@@ -19,6 +19,9 @@
1010 #include <QFile>
1011 #include <QRegularExpression>
1012
1013+#include <core/posix/process.h>
1014+#include <core/posix/linux/proc/process/stat.h>
1015+
1016 namespace unitymir
1017 {
1018
1019@@ -33,6 +36,16 @@
1020
1021 return std::unique_ptr<CommandLine>(new CommandLine{ cmdline.readLine().replace('\0', ' ') });
1022 }
1023+
1024+quint64 ProcInfo::parentProcess(quint64 pid)
1025+{
1026+ core::posix::Process process(pid);
1027+ core::posix::linux::proc::process::Stat stat;
1028+ process >> stat;
1029+
1030+ return stat.parent;
1031+}
1032+
1033 QStringList ProcInfo::CommandLine::asStringList() const {
1034 return QString(m_command.data()).split(' ');
1035 }
1036
1037=== modified file 'src/modules/Unity/Application/proc_info.h'
1038--- src/modules/Unity/Application/proc_info.h 2014-03-11 19:11:00 +0000
1039+++ src/modules/Unity/Application/proc_info.h 2014-07-10 11:50:19 +0000
1040@@ -45,6 +45,9 @@
1041 QStringList asStringList() const;
1042 };
1043 virtual std::unique_ptr<CommandLine> commandLine(quint64 pid);
1044+
1045+ virtual quint64 parentProcess(quint64 pid);
1046+
1047 virtual ~ProcInfo();
1048 };
1049
1050
1051=== modified file 'src/unity-mir/CMakeLists.txt'
1052--- src/unity-mir/CMakeLists.txt 2014-05-22 21:37:02 +0000
1053+++ src/unity-mir/CMakeLists.txt 2014-07-10 11:50:19 +0000
1054@@ -28,6 +28,7 @@
1055 logging.h
1056 focussetter.h
1057 serverstatuslistener.h
1058+ promptsessionlistener.h
1059 ${GENERATED_PROTOBUF_HDRS}
1060 )
1061
1062@@ -47,6 +48,7 @@
1063 unityprotobufservice.cpp
1064 focussetter.cpp
1065 serverstatuslistener.cpp
1066+ promptsessionlistener.cpp
1067
1068 ${UNITY_MIR_HEADERS}
1069 ${GENERATED_PROTOBUF_SRCS}
1070
1071=== modified file 'src/unity-mir/focussetter.cpp'
1072--- src/unity-mir/focussetter.cpp 2014-04-15 14:31:02 +0000
1073+++ src/unity-mir/focussetter.cpp 2014-07-10 11:50:19 +0000
1074@@ -15,6 +15,7 @@
1075 */
1076
1077 #include <mir/scene/surface.h>
1078+#include <mir/scene/session.h>
1079
1080 #include "focussetter.h"
1081 #include "logging.h"
1082@@ -35,7 +36,7 @@
1083
1084 void FocusSetter::set_focus_to(std::shared_ptr<ms::Session> const& session)
1085 {
1086- DLOG("FocusSetter::set_focus_to(session=%p):%d", session.get(), __LINE__);
1087+ DLOG("FocusSetter::set_focus_to(session=%p, session name=%s):%d", session.get(), session?session->name().c_str():"null", __LINE__);
1088 // Ensure we always call the underlying setter to dispatch focus/unfocus notifications.
1089 underlying_setter->set_focus_to(session);
1090 if (session == nullptr)
1091@@ -53,6 +54,6 @@
1092 assert(t);
1093
1094 default_keyboard_target = default_target;
1095-
1096+
1097 t->take_input_focus(keyboard_input_targeter);
1098 }
1099
1100=== added file 'src/unity-mir/promptsessionlistener.cpp'
1101--- src/unity-mir/promptsessionlistener.cpp 1970-01-01 00:00:00 +0000
1102+++ src/unity-mir/promptsessionlistener.cpp 2014-07-10 11:50:19 +0000
1103@@ -0,0 +1,62 @@
1104+/*
1105+ * Copyright (C) 2014 Canonical, Ltd.
1106+ *
1107+ * This program is free software: you can redistribute it and/or modify it under
1108+ * the terms of the GNU Lesser General Public License version 3, as published by
1109+ * the Free Software Foundation.
1110+ *
1111+ * This program is distributed in the hope that it will be useful, but WITHOUT
1112+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1113+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1114+ * Lesser General Public License for more details.
1115+ *
1116+ * You should have received a copy of the GNU Lesser General Public License
1117+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1118+ */
1119+
1120+#include "promptsessionlistener.h"
1121+#include "logging.h"
1122+
1123+namespace ms = mir::scene;
1124+
1125+Q_DECLARE_METATYPE(std::shared_ptr<ms::PromptSession>)
1126+
1127+PromptSessionListener::PromptSessionListener(QObject *parent) :
1128+ QObject(parent)
1129+{
1130+ DLOG("PromptSessionListener::PromptSessionListener (this=%p)", this);
1131+ qRegisterMetaType<std::shared_ptr<ms::PromptSession>>("std::shared_ptr<mir::scene::PromptSession>");
1132+}
1133+
1134+PromptSessionListener::~PromptSessionListener()
1135+{
1136+ DLOG("PromptSessionListener::~PromptSessionListener (this=%p)", this);
1137+}
1138+
1139+void PromptSessionListener::starting(std::shared_ptr<ms::PromptSession> const& prompt_session)
1140+{
1141+ DLOG("PromptSessionListener::starting (this=%p, prompt_session=%p)", this, (void*)prompt_session.get());
1142+ Q_EMIT promptSessionStarting(prompt_session);
1143+}
1144+
1145+void PromptSessionListener::stopping(std::shared_ptr<ms::PromptSession> const& prompt_session)
1146+{
1147+ DLOG("PromptSessionListener::stopping (this=%p, prompt_session=%p)", this, (void*)prompt_session.get());
1148+ Q_EMIT promptSessionStopping(prompt_session);
1149+}
1150+
1151+void PromptSessionListener::prompt_provider_added(ms::PromptSession const& prompt_session,
1152+ std::shared_ptr<ms::Session> const& prompt_provider)
1153+{
1154+ DLOG("PromptSessionListener::prompt_provider_added (this=%p, prompt_session=%p, prompt_provider=%p)",
1155+ this, &prompt_session, (void*)prompt_provider.get());
1156+ Q_EMIT promptProviderAdded(&prompt_session, prompt_provider);
1157+}
1158+
1159+void PromptSessionListener::prompt_provider_removed(ms::PromptSession const& prompt_session,
1160+ std::shared_ptr<ms::Session> const& prompt_provider)
1161+{
1162+ DLOG("PromptSessionListener::prompt_provider_removed (this=%p, prompt_session=%p, prompt_provider=%p)",
1163+ this, &prompt_session, (void*)prompt_provider.get());
1164+ Q_EMIT promptProviderRemoved(&prompt_session, prompt_provider);
1165+}
1166
1167=== added file 'src/unity-mir/promptsessionlistener.h'
1168--- src/unity-mir/promptsessionlistener.h 1970-01-01 00:00:00 +0000
1169+++ src/unity-mir/promptsessionlistener.h 2014-07-10 11:50:19 +0000
1170@@ -0,0 +1,47 @@
1171+/*
1172+ * Copyright (C) 2014 Canonical, Ltd.
1173+ *
1174+ * This program is free software: you can redistribute it and/or modify it under
1175+ * the terms of the GNU Lesser General Public License version 3, as published by
1176+ * the Free Software Foundation.
1177+ *
1178+ * This program is distributed in the hope that it will be useful, but WITHOUT
1179+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1180+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1181+ * Lesser General Public License for more details.
1182+ *
1183+ * You should have received a copy of the GNU Lesser General Public License
1184+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1185+ */
1186+
1187+#ifndef PROMPTSESSIONLISTENER_H
1188+#define PROMPTSESSIONLISTENER_H
1189+
1190+#include <QObject>
1191+
1192+#include "mir/scene/prompt_session_listener.h"
1193+
1194+class PromptSessionListener : public QObject, public mir::scene::PromptSessionListener
1195+{
1196+ Q_OBJECT
1197+public:
1198+ explicit PromptSessionListener(QObject *parent = 0);
1199+ ~PromptSessionListener();
1200+
1201+ void starting(std::shared_ptr<mir::scene::PromptSession> const& prompt_session) override;
1202+ void stopping(std::shared_ptr<mir::scene::PromptSession> const& prompt_session) override;
1203+
1204+ void prompt_provider_added(mir::scene::PromptSession const& prompt_session,
1205+ std::shared_ptr<mir::scene::Session> const& prompt_provider) override;
1206+ void prompt_provider_removed(mir::scene::PromptSession const& prompt_session,
1207+ std::shared_ptr<mir::scene::Session> const& prompt_provider) override;
1208+
1209+Q_SIGNALS:
1210+ void promptSessionStarting(std::shared_ptr<mir::scene::PromptSession> const& session);
1211+ void promptSessionStopping(std::shared_ptr<mir::scene::PromptSession> const& session);
1212+
1213+ void promptProviderAdded(mir::scene::PromptSession const*, std::shared_ptr<mir::scene::Session> const&);
1214+ void promptProviderRemoved(mir::scene::PromptSession const*, std::shared_ptr<mir::scene::Session> const&);
1215+};
1216+
1217+#endif // SESSIONLISTENER_H
1218
1219=== modified file 'src/unity-mir/shellserverconfiguration.cpp'
1220--- src/unity-mir/shellserverconfiguration.cpp 2014-05-08 03:50:31 +0000
1221+++ src/unity-mir/shellserverconfiguration.cpp 2014-07-10 11:50:19 +0000
1222@@ -24,6 +24,7 @@
1223 #include "sessionlistener.h"
1224 #include "surfaceconfigurator.h"
1225 #include "sessionauthorizer.h"
1226+#include "promptsessionlistener.h"
1227 #include "focussetter.h"
1228 #include "logging.h"
1229
1230@@ -117,6 +118,16 @@
1231 });
1232 }
1233
1234+std::shared_ptr<ms::PromptSessionListener>
1235+ShellServerConfiguration::the_prompt_session_listener()
1236+{
1237+ return prompt_session_listener(
1238+ [this]
1239+ {
1240+ return std::make_shared<PromptSessionListener>();
1241+ });
1242+}
1243+
1244 std::shared_ptr<mir::ServerStatusListener>
1245 ShellServerConfiguration::the_server_status_listener()
1246 {
1247@@ -136,7 +147,7 @@
1248 // The rationale is that if when you do
1249 // the_session_authorizer()
1250 // get a pointer that is unique means that Mir is not
1251-// holding the pointer and thus when we return from the
1252+// holding the pointer and thus when we return from the
1253 // sessionAuthorizer()
1254 // scope the unique pointer will be destroyed so we return 0
1255 //
1256@@ -165,6 +176,14 @@
1257 return static_cast<SessionListener*>(sharedPtr.get());
1258 }
1259
1260+PromptSessionListener *ShellServerConfiguration::promptSessionListener()
1261+{
1262+ auto sharedPtr = the_prompt_session_listener();
1263+ if (sharedPtr.unique()) return 0;
1264+
1265+ return static_cast<PromptSessionListener*>(sharedPtr.get());
1266+}
1267+
1268 SurfaceConfigurator *ShellServerConfiguration::surfaceConfigurator()
1269 {
1270 auto sharedPtr = the_surface_configurator();
1271
1272=== modified file 'src/unity-mir/shellserverconfiguration.h'
1273--- src/unity-mir/shellserverconfiguration.h 2014-05-08 03:50:31 +0000
1274+++ src/unity-mir/shellserverconfiguration.h 2014-07-10 11:50:19 +0000
1275@@ -28,6 +28,7 @@
1276
1277 class FocusSetter;
1278 class SessionListener;
1279+class PromptSessionListener;
1280 class SessionAuthorizer;
1281 class SurfaceConfigurator;
1282 class InitialSurfacePlacementStrategy;
1283@@ -38,6 +39,7 @@
1284
1285 Q_PROPERTY(SessionAuthorizer* sessionAuthorizer READ sessionAuthorizer CONSTANT)
1286 Q_PROPERTY(SessionListener* sessionListener READ sessionListener CONSTANT)
1287+ Q_PROPERTY(PromptSessionListener* promptSessionListener READ promptSessionListener CONSTANT)
1288 Q_PROPERTY(SurfaceConfigurator* surfaceConfigurator READ surfaceConfigurator CONSTANT)
1289
1290 public:
1291@@ -50,6 +52,7 @@
1292 std::shared_ptr<mir::scene::SessionListener> the_session_listener() override;
1293 std::shared_ptr<mir::scene::SurfaceConfigurator> the_surface_configurator() override;
1294 std::shared_ptr<mir::shell::FocusSetter> the_shell_focus_setter() override;
1295+ std::shared_ptr<mir::scene::PromptSessionListener> the_prompt_session_listener() override;
1296 std::shared_ptr<mir::ServerStatusListener> the_server_status_listener() override;
1297 std::shared_ptr<mir::frontend::SessionAuthorizer> the_session_authorizer() override;
1298 std::shared_ptr<mir::frontend::ConnectionCreator> the_connection_creator() override;
1299@@ -59,6 +62,7 @@
1300 InitialSurfacePlacementStrategy *placementStrategy();
1301 SessionAuthorizer *sessionAuthorizer();
1302 SessionListener *sessionListener();
1303+ PromptSessionListener *promptSessionListener();
1304 SurfaceConfigurator *surfaceConfigurator();
1305 FocusSetter *focusSetter();
1306
1307
1308=== modified file 'tests/CMakeLists.txt'
1309--- tests/CMakeLists.txt 2014-05-19 12:13:58 +0000
1310+++ tests/CMakeLists.txt 2014-07-10 11:50:19 +0000
1311@@ -33,6 +33,7 @@
1312 mock_process_controller.h
1313 mock_proc_info.h
1314 mock_session.h
1315+ mock_prompt_session_manager.h
1316 )
1317
1318 add_executable(
1319
1320=== modified file 'tests/application_manager_test.cpp'
1321--- tests/application_manager_test.cpp 2014-06-25 15:30:50 +0000
1322+++ tests/application_manager_test.cpp 2014-07-10 11:50:19 +0000
1323@@ -25,6 +25,8 @@
1324
1325 #include <gmock/gmock.h>
1326 #include <gtest/gtest.h>
1327+#include <thread>
1328+#include <condition_variable>
1329 #include <QSignalSpy>
1330
1331 #include "mock_application_controller.h"
1332@@ -34,6 +36,8 @@
1333 #include "mock_proc_info.h"
1334 #include "mock_session.h"
1335 #include "mock_focus_controller.h"
1336+#include "mock_prompt_session_manager.h"
1337+#include "mock_prompt_session.h"
1338
1339 using namespace unitymir;
1340
1341@@ -66,16 +70,49 @@
1342 [](DesktopFileReader::Factory*){}),
1343 QSharedPointer<ProcInfo>(&procInfo,[](ProcInfo *){}),
1344 std::shared_ptr<mir::shell::FocusController>(&focusController, [](void*){}),
1345+ std::shared_ptr<mir::scene::PromptSessionManager>(&promptSessionManager, [](void*){}),
1346 QSize(400,400)
1347 }
1348 {
1349 }
1350+
1351+ Application* startApplication(quint64 procId, QString const& appId)
1352+ {
1353+ using namespace testing;
1354+
1355+ ON_CALL(appController,appIdHasProcessId(procId, appId)).WillByDefault(Return(true));
1356+
1357+ // Set up Mocks & signal watcher
1358+ auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
1359+ ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
1360+ ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
1361+
1362+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
1363+
1364+ EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
1365+ .Times(1)
1366+ .WillOnce(Return(true));
1367+
1368+ auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
1369+ applicationManager.onProcessStarting(appId);
1370+
1371+ bool authed = false;
1372+ applicationManager.authorizeSession(procId, authed);
1373+ EXPECT_EQ(authed, true);
1374+
1375+ auto appSession = std::make_shared<MockSession>(appId.toStdString(), procId);
1376+
1377+ applicationManager.onSessionStarting(appSession);
1378+ return application;
1379+ }
1380+
1381 testing::NiceMock<testing::MockOomController> oomController;
1382 testing::NiceMock<testing::MockProcessController> processController;
1383 testing::NiceMock<testing::MockApplicationController> appController;
1384 testing::NiceMock<testing::MockProcInfo> procInfo;
1385 testing::NiceMock<testing::MockDesktopFileReaderFactory> desktopFileReaderFactory;
1386 testing::NiceMock<testing::MockFocusController> focusController;
1387+ testing::NiceMock<testing::MockPromptSessionManager> promptSessionManager;
1388 QSharedPointer<TaskController> taskController;
1389 ApplicationManager applicationManager;
1390 };
1391@@ -1879,3 +1916,153 @@
1392 EXPECT_EQ(countSpy.count(), 0);
1393 EXPECT_EQ(removedSpy.count(), 0);
1394 }
1395+
1396+/*
1397+ * Test that screenshotting callback works cross thread.
1398+ */
1399+TEST_F(ApplicationManagerTests, threadedScreenshot)
1400+{
1401+ using namespace testing;
1402+ quint64 procId1 = 5551;
1403+
1404+ std::mutex mutex;
1405+ std::condition_variable cv;
1406+ bool done = false;
1407+
1408+ auto application = startApplication(procId1, "webapp");
1409+ auto session = std::dynamic_pointer_cast<MockSession>(application->session());
1410+ ON_CALL(*session, take_snapshot(_)).WillByDefault(Invoke(
1411+ [&](mir::scene::SnapshotCallback const& callback)
1412+ {
1413+ std::thread ([&, callback]() {
1414+ std::unique_lock<std::mutex> lk(mutex);
1415+
1416+ mir::scene::Snapshot snapshot{mir::geometry::Size{0,0},
1417+ mir::geometry::Stride{0},
1418+ NULL};
1419+
1420+ callback(snapshot);
1421+
1422+ done = true;
1423+ lk.unlock();
1424+ cv.notify_one();
1425+ }).detach();
1426+ }));
1427+
1428+ application->updateScreenshot();
1429+
1430+ {
1431+ std::unique_lock<decltype(mutex)> lk(mutex);
1432+ cv.wait(lk, [&] { return done; } );
1433+ EXPECT_TRUE(done);
1434+ }
1435+
1436+ applicationManager.stopApplication(application->appId());
1437+}
1438+
1439+/*
1440+ * Test that screenshotting callback works when application has been deleted
1441+ */
1442+TEST_F(ApplicationManagerTests, threadedScreenshotAfterAppDelete)
1443+{
1444+ using namespace testing;
1445+ quint64 procId1 = 5551;
1446+
1447+ std::mutex mutex;
1448+ std::condition_variable cv;
1449+ bool ready = false;
1450+ bool done = false;
1451+
1452+ auto application = startApplication(procId1, "webapp");
1453+ auto session = std::dynamic_pointer_cast<MockSession>(application->session());
1454+ ON_CALL(*session, take_snapshot(_)).WillByDefault(Invoke(
1455+ [&](mir::scene::SnapshotCallback const& callback)
1456+ {
1457+ std::thread ([&, callback]() {
1458+
1459+ std::unique_lock<std::mutex> lk(mutex);
1460+ cv.wait(lk, [&]{ return ready; } );
1461+
1462+ mir::scene::Snapshot snapshot{mir::geometry::Size{0,0},
1463+ mir::geometry::Stride{0},
1464+ NULL};
1465+
1466+ callback(snapshot);
1467+
1468+ done = true;
1469+ lk.unlock();
1470+ cv.notify_one();
1471+ }).detach();
1472+ }));
1473+ application->updateScreenshot();
1474+
1475+ {
1476+ std::lock_guard<decltype(mutex)> lk(mutex);
1477+ applicationManager.stopApplication(application->appId());
1478+ ready = true;
1479+ }
1480+ cv.notify_one();
1481+
1482+ {
1483+ std::unique_lock<decltype(mutex)> lk(mutex);
1484+ cv.wait(lk, [&] { return done; } );
1485+ }
1486+}
1487+
1488+TEST_F(ApplicationManagerTests, applicationTracksPromptSession)
1489+{
1490+ using namespace testing;
1491+ quint64 procId1 = 5551;
1492+
1493+ auto application = startApplication(procId1, "webapp");
1494+ auto promptSession = std::make_shared<MockPromptSession>();
1495+
1496+ ON_CALL(promptSessionManager, application_for(_)).WillByDefault(Return(application->session()));
1497+
1498+ applicationManager.onPromptSessionStarting(promptSession);
1499+
1500+ EXPECT_EQ(application->activePromptSession(), promptSession);
1501+
1502+ applicationManager.onPromptSessionStopping(promptSession);
1503+
1504+ EXPECT_EQ(application->activePromptSession(), nullptr);
1505+}
1506+
1507+TEST_F(ApplicationManagerTests, applicationFocusesPromptSessionProviders)
1508+{
1509+ using namespace testing;
1510+ quint64 procId1 = 5551;
1511+ quint64 procId2 = 5552;
1512+
1513+ auto application = startApplication(procId1, "webapp");
1514+
1515+ std::shared_ptr<mir::scene::PromptSession> promptSession = std::make_shared<MockPromptSession>();
1516+
1517+ ON_CALL(promptSessionManager, application_for(promptSession)).WillByDefault(Return(application->session()));
1518+ ON_CALL(promptSessionManager, helper_for(promptSession)).WillByDefault(Return(std::shared_ptr<mir::scene::Session>()));
1519+
1520+ std::shared_ptr<mir::scene::Surface> aSurface(nullptr);
1521+ applicationManager.onSessionCreatedSurface(application->session().get(), aSurface);
1522+
1523+ std::shared_ptr<testing::MockSession> providerSession = std::make_shared<MockSession>("", procId2);
1524+ // TODO: Use mock!
1525+ std::shared_ptr<mir::scene::Surface> providerSurface((mir::scene::Surface*)__LINE__, [](mir::scene::Surface*) {});
1526+ ON_CALL(*providerSession, default_surface()).WillByDefault(Return(providerSurface));
1527+
1528+ applicationManager.onSessionStarting(providerSession);
1529+ EXPECT_EQ(application->foregroundSession(), application->session());
1530+
1531+ InSequence s;
1532+ EXPECT_CALL(focusController, set_focus_to(std::static_pointer_cast<mir::scene::Session>(providerSession))).Times(1);
1533+ EXPECT_CALL(focusController, set_focus_to(application->session())).Times(1);
1534+
1535+ applicationManager.onPromptSessionStarting(promptSession);
1536+
1537+ ON_CALL(promptSessionManager, for_each_provider_in(promptSession,_)).WillByDefault(InvokeArgument<1>(providerSession));
1538+ applicationManager.onPromptProviderAdded(promptSession.get(), providerSession);
1539+ EXPECT_EQ(application->foregroundSession(), providerSession);
1540+
1541+ ON_CALL(promptSessionManager, for_each_provider_in(promptSession,_)).WillByDefault(Return());
1542+ applicationManager.onPromptProviderRemoved(promptSession.get(), providerSession);
1543+ EXPECT_EQ(application->foregroundSession(), application->session());
1544+}
1545
1546=== modified file 'tests/mock_proc_info.h'
1547--- tests/mock_proc_info.h 2014-02-28 17:42:43 +0000
1548+++ tests/mock_proc_info.h 2014-07-10 11:50:19 +0000
1549@@ -27,9 +27,14 @@
1550 struct MockProcInfo : public unitymir::ProcInfo
1551 {
1552 MOCK_METHOD1(command_line, QByteArray(quint64));
1553- std::unique_ptr<CommandLine> commandLine(quint64 pid)
1554- {
1555- return std::unique_ptr<CommandLine>(new CommandLine{command_line(pid)});
1556+ std::unique_ptr<CommandLine> commandLine(quint64 pid) override
1557+ {
1558+ return std::unique_ptr<CommandLine>(new CommandLine{command_line(pid)});
1559+ }
1560+
1561+ quint64 parentProcess(quint64 /* pid */) override
1562+ {
1563+ return 0;
1564 }
1565 };
1566 }
1567
1568=== added file 'tests/mock_prompt_session.h'
1569--- tests/mock_prompt_session.h 1970-01-01 00:00:00 +0000
1570+++ tests/mock_prompt_session.h 2014-07-10 11:50:19 +0000
1571@@ -0,0 +1,31 @@
1572+/*
1573+ * Copyright (C) 2014 Canonical, Ltd.
1574+ *
1575+ * This program is free software: you can redistribute it and/or modify it under
1576+ * the terms of the GNU Lesser General Public License version 3, as published by
1577+ * the Free Software Foundation.
1578+ *
1579+ * This program is distributed in the hope that it will be useful, but WITHOUT
1580+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1581+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1582+ * Lesser General Public License for more details.
1583+ *
1584+ * You should have received a copy of the GNU Lesser General Public License
1585+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1586+ *
1587+ */
1588+
1589+#ifndef MOCK_MIR_PROMPT_SESSION_H
1590+#define MOCK_MIR_PROMPT_SESSION_H
1591+
1592+#include <mir/scene/prompt_session.h>
1593+#include <gmock/gmock.h>
1594+
1595+namespace testing
1596+{
1597+struct MockPromptSession : public mir::scene::PromptSession
1598+{
1599+};
1600+}
1601+
1602+#endif // MOCK_MIR_PROMPT_SESSION_H
1603
1604=== added file 'tests/mock_prompt_session_manager.h'
1605--- tests/mock_prompt_session_manager.h 1970-01-01 00:00:00 +0000
1606+++ tests/mock_prompt_session_manager.h 2014-07-10 11:50:19 +0000
1607@@ -0,0 +1,57 @@
1608+/*
1609+ * Copyright (C) 2014 Canonical, Ltd.
1610+ *
1611+ * This program is free software: you can redistribute it and/or modify it under
1612+ * the terms of the GNU Lesser General Public License version 3, as published by
1613+ * the Free Software Foundation.
1614+ *
1615+ * This program is distributed in the hope that it will be useful, but WITHOUT
1616+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1617+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1618+ * Lesser General Public License for more details.
1619+ *
1620+ * You should have received a copy of the GNU Lesser General Public License
1621+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1622+ *
1623+ */
1624+
1625+#ifndef MOCK_MIR_SCENE_PROMPT_SESSION_MANAGER_H_
1626+#define MOCK_MIR_SCENE_PROMPT_SESSION_MANAGER_H_
1627+
1628+#include "mir/scene/prompt_session_manager.h"
1629+#include "mir/scene/prompt_session_creation_parameters.h"
1630+
1631+#include <gmock/gmock.h>
1632+
1633+namespace testing
1634+{
1635+
1636+class MockPromptSessionManager: public mir::scene::PromptSessionManager
1637+{
1638+public:
1639+ MOCK_CONST_METHOD2(start_prompt_session_for, std::shared_ptr<mir::scene::PromptSession>(std::shared_ptr<mir::scene::Session> const&,
1640+ mir::scene::PromptSessionCreationParameters const&));
1641+
1642+ MOCK_CONST_METHOD1(stop_prompt_session, void(std::shared_ptr<mir::scene::PromptSession> const&));
1643+
1644+ MOCK_CONST_METHOD2(add_prompt_provider, void(std::shared_ptr<mir::scene::PromptSession> const&,
1645+ std::shared_ptr<mir::scene::Session> const&));
1646+
1647+ MOCK_CONST_METHOD2(add_prompt_provider_by_pid, void(std::shared_ptr<mir::scene::PromptSession> const&,
1648+ pid_t));
1649+
1650+ MOCK_CONST_METHOD1(add_expected_session, void(std::shared_ptr<mir::scene::Session> const&));
1651+
1652+ MOCK_CONST_METHOD1(remove_session, void(std::shared_ptr<mir::scene::Session> const&));
1653+
1654+ MOCK_CONST_METHOD1(application_for, std::shared_ptr<mir::scene::Session>(std::shared_ptr<mir::scene::PromptSession> const&));
1655+
1656+ MOCK_CONST_METHOD1(helper_for, std::shared_ptr<mir::scene::Session>(std::shared_ptr<mir::scene::PromptSession> const&));
1657+
1658+ MOCK_CONST_METHOD2(for_each_provider_in, void(std::shared_ptr<mir::scene::PromptSession> const&,
1659+ std::function<void(std::shared_ptr<mir::scene::Session> const&)> const&));
1660+};
1661+
1662+} // namespace testing
1663+
1664+#endif // MOCK_MIR_SCENE_PROMPT_SESSION_MANAGER_H_
1665
1666=== modified file 'tests/mock_session.h'
1667--- tests/mock_session.h 2014-06-18 15:15:39 +0000
1668+++ tests/mock_session.h 2014-07-10 11:50:19 +0000
1669@@ -30,7 +30,7 @@
1670 struct MockSession : public mir::scene::Session
1671 {
1672 MockSession() {}
1673- MockSession(std::string const& sessionName, pid_t processId)
1674+ MockSession(std::string const& sessionName, pid_t processId)
1675 : m_sessionName(sessionName), m_sessionId(processId)
1676 {}
1677

Subscribers

People subscribed via source and target branches