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