Mir

Merge lp:~robertcarr/mir/prepare-session-manager-for-input-focus into lp:~mir-team/mir/trunk

Proposed by Robert Carr
Status: Superseded
Proposed branch: lp:~robertcarr/mir/prepare-session-manager-for-input-focus
Merge into: lp:~mir-team/mir/trunk
Prerequisite: lp:~robertcarr/mir/reduce-coupling-in-application-mediator-tests
Diff against target: 854 lines (+328/-73)
20 files modified
include/mir/shell/application_session.h (+6/-1)
include/mir/shell/focus_arbitrator.h (+47/-0)
include/mir/shell/session.h (+3/-1)
include/mir/shell/session_manager.h (+2/-0)
include/mir/shell/session_store.h (+5/-1)
include/mir_test_doubles/mock_session.h (+2/-0)
include/mir_test_doubles/mock_session_store.h (+2/-0)
include/mir_test_doubles/stub_session.h (+4/-0)
include/mir_test_doubles/stub_session_store.h (+4/-0)
src/shell/application_session.cpp (+13/-0)
src/shell/session_manager.cpp (+10/-1)
tests/acceptance-tests/test_focus_management_api.cpp (+5/-0)
tests/integration-tests/CMakeLists.txt (+1/-0)
tests/integration-tests/frontend/CMakeLists.txt (+0/-1)
tests/integration-tests/shell/CMakeLists.txt (+9/-0)
tests/integration-tests/shell/test_session_manager.cpp (+64/-0)
tests/unit-tests/shell/test_application_session.cpp (+95/-23)
tests/unit-tests/shell/test_registration_order_focus_sequence.cpp (+18/-26)
tests/unit-tests/shell/test_session_manager.cpp (+22/-2)
tests/unit-tests/shell/test_the_session_container_implementation.cpp (+16/-17)
To merge this branch: bzr merge lp:~robertcarr/mir/prepare-session-manager-for-input-focus
Reviewer Review Type Date Requested Status
Alan Griffiths Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+152806@code.launchpad.net

This proposal has been superseded by a proposal from 2013-03-14.

Commit message

Prepare the session manager for setting input focus through setting focus on creation of a sessions first surface.

Description of the change

This branch works to prepare the session manager for setting input focus.

The driving integration test is tests/integration-tests/shell/test_session_manager.cpp : TestSessionManagerAndSession, sessions_creating_first_surface_receive_focus.

The issue, is in order for the focus setter to set input focus in addition to visible focus, it will have to see the session at surface creation time (not just at session creation time).

===
To go a little deeper in to the motivation (to give context to the chosen interfaces), the input manager (or owner of the droidinput::InputDispatcher) needs to call (paraphrased from a list based API)

InputDispatcher::setInputFocus(droidinput::InputApplicationHandle, droidinput::InputWindowHandle)

where InputApplicationHandle is analogous to msh::Session and InputWindowHandle is analagous to msh::Surface. So mi::InputManager gains an interface:

InputFocusSelector::set_input_focus_to(std::shared_ptr<msh::Session> const& session, std::shared_ptr<msh::Surface> const& surface)

Now, the focus mechanism in shell may be modified to use the InputFocusSelector, to request focus for a session and it's default surface (a notion which will be added in the branch wiring this up).

This branch is just to allow msh::FocusSetter::set_focus_to be invoked when a session has created it's surface.
===

This branch is backed up by the design discussions so far but the full semantics for application focus v. window focus are still in progress in cucumber definition, so rather than try and sort all of that I am just trying to unblock input in a way that will also move us forward in a self contained view.

I think it's a little strange how the FocusArbitrator (session manager) is passed to the ApplicationSession by reference through usage of *this, but the ApplicationSession is passed to the FocusArbitrator (for request_focus) through std::enable_shared_from_this. I think this is justifiable though, as it is clear that an ApplicationSession must be owned by a shared_ptr (as they are only created by the session manager, who internally holds them with shared_ptrs).

There is some incidental cleanup to test_registration_order_focus_sequence.cpp and test_the_session_container_implementation.cpp to remove dependency on ApplicationSession implementation.

This branch depends on: https://code.launchpad.net/~robertcarr/mir/reduce-coupling-in-application-mediator-tests/+merge/152304 as without it there was much cumbersome test refactoring

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:485
http://jenkins.qa.ubuntu.com/job/mir-ci/49/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-quantal-amd64-ci/50//console

Click here to trigger a rebuild:
http://jenkins.qa.ubuntu.com/job/mir-ci/49//rebuild/?

review: Approve (continuous-integration)
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

First let me say I like the style of most of this MP - it cleans up a lot of existing untidyness,

But I don't like the bit you felt uncomfortable enough to write about regarding ApplicationSession::focus_arbitrator& and enable_shared_from_this. (You should listen to the code telling you this isn't the right approach.)

I think what is actually needed is a function in shell (not sure which object yet) with the signature:

std::shared_ptr<shell::Surface>
create_surface_for(std::shared_ptr<Session> const& session, SurfaceCreationParameters const& params);

This can be called naturally from ApplicationMediator and has context for the call to request_focus() without the need for the above explanation.

Logically, it belongs with (or instead of) SessionStore::request_focus() - but SessionStore is growing functions that contradict its current name. Should shell::SessionStore become frontend::Shell?

review: Needs Fixing

Unmerged revisions

485. By Robert Carr

Reduce obtusity of test name

484. By Robert Carr

test_session_manager.cpp: Replace a should be stub mock with a stub

483. By Robert Carr

Remove overzealous whitespace deletion

482. By Robert Carr

Merge reduce-coupling-in-application-mediator-test

481. By Robert Carr

focus_arbitrator.h: Fix misnamed header guard comment

480. By Robert Carr

Implement request_focus, allowing the integration test to pass

479. By Robert Carr

Failing unit test to define SessionManager::request_focus

478. By Robert Carr

Pass application session to focus arbitrator through std::enable_shared_from_this

477. By Robert Carr

Define new msh::Session attribute has_appeared (see, ApplicationSession, session_has_appeared_after_creating_surface)

476. By Robert Carr

Hook the session manager up to the session via focus arbitrator

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/mir/shell/application_session.h'
2--- include/mir/shell/application_session.h 2013-03-06 12:25:34 +0000
3+++ include/mir/shell/application_session.h 2013-03-12 00:40:38 +0000
4@@ -29,11 +29,12 @@
5 namespace shell
6 {
7 class SurfaceFactory;
8+class FocusArbitrator;
9
10 class ApplicationSession : public Session
11 {
12 public:
13- explicit ApplicationSession(std::shared_ptr<SurfaceFactory> const& surface_factory, std::string const& session_name);
14+ explicit ApplicationSession(std::shared_ptr<SurfaceFactory> const& surface_factory, FocusArbitrator& focus_arbitrator, std::string const& session_name);
15 ~ApplicationSession();
16
17 SurfaceId create_surface(SurfaceCreationParameters const& params);
18@@ -45,6 +46,8 @@
19
20 void hide();
21 void show();
22+
23+ bool has_appeared() const;
24
25 protected:
26 ApplicationSession(ApplicationSession const&) = delete;
27@@ -52,6 +55,8 @@
28
29 private:
30 std::shared_ptr<SurfaceFactory> const surface_factory;
31+ FocusArbitrator &focus_arbitrator;
32+
33 std::string const session_name;
34
35 SurfaceId next_id();
36
37=== added file 'include/mir/shell/focus_arbitrator.h'
38--- include/mir/shell/focus_arbitrator.h 1970-01-01 00:00:00 +0000
39+++ include/mir/shell/focus_arbitrator.h 2013-03-12 00:40:38 +0000
40@@ -0,0 +1,47 @@
41+/*
42+ * Copyright © 2013 Canonical Ltd.
43+ *
44+ * This program is free software: you can redistribute it and/or modify it
45+ * under the terms of the GNU Lesser General Public License version 3,
46+ * as published by the Free Software Foundation.
47+ *
48+ * This program is distributed in the hope that it will be useful,
49+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
50+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51+ * GNU General Public License for more details.
52+ *
53+ * You should have received a copy of the GNU Lesser General Public License
54+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
55+ *
56+ * Authored by: Robert Carr <robert.carr@canonical.com>
57+ */
58+
59+#ifndef MIR_SHELL_FOCUS_ARBITRATOR_H_
60+#define MIR_SHELL_FOCUS_ARBITRATOR_H_
61+
62+#include <memory>
63+
64+namespace mir
65+{
66+namespace shell
67+{
68+class Session;
69+
70+class FocusArbitrator
71+{
72+public:
73+ virtual ~FocusArbitrator() {}
74+
75+ virtual bool request_focus(std::shared_ptr<Session> const& session) = 0;
76+
77+protected:
78+ FocusArbitrator() = default;
79+ FocusArbitrator(const FocusArbitrator&) = delete;
80+ FocusArbitrator& operator=(const FocusArbitrator&) = delete;
81+};
82+
83+}
84+}
85+
86+
87+#endif // MIR_SHELL_FOCUS_ARBITRATOR_H_
88
89=== modified file 'include/mir/shell/session.h'
90--- include/mir/shell/session.h 2013-03-06 12:25:34 +0000
91+++ include/mir/shell/session.h 2013-03-12 00:40:38 +0000
92@@ -35,7 +35,7 @@
93 class Surface;
94 class SurfaceCreationParameters;
95
96-class Session
97+class Session : public std::enable_shared_from_this<Session>
98 {
99 public:
100 virtual ~Session() {}
101@@ -49,6 +49,8 @@
102
103 virtual void hide() = 0;
104 virtual void show() = 0;
105+
106+ virtual bool has_appeared() const = 0;
107
108 protected:
109 Session() = default;
110
111=== modified file 'include/mir/shell/session_manager.h'
112--- include/mir/shell/session_manager.h 2013-03-06 12:25:34 +0000
113+++ include/mir/shell/session_manager.h 2013-03-12 00:40:38 +0000
114@@ -51,6 +51,8 @@
115
116 virtual void tag_session_with_lightdm_id(std::shared_ptr<Session> const& session, int id);
117 virtual void focus_session_with_lightdm_id(int id);
118+
119+ bool request_focus(std::shared_ptr<Session> const& session);
120
121 void focus_next();
122
123
124=== modified file 'include/mir/shell/session_store.h'
125--- include/mir/shell/session_store.h 2013-03-06 12:25:34 +0000
126+++ include/mir/shell/session_store.h 2013-03-12 00:40:38 +0000
127@@ -19,6 +19,8 @@
128 #ifndef MIR_SHELL_SESSION_STORE_H_
129 #define MIR_SHELL_SESSION_STORE_H_
130
131+#include "mir/shell/focus_arbitrator.h"
132+
133 #include <memory>
134
135 namespace mir
136@@ -29,7 +31,7 @@
137
138 class Session;
139
140-class SessionStore
141+class SessionStore : public FocusArbitrator
142 {
143 public:
144 virtual ~SessionStore() {}
145@@ -40,6 +42,8 @@
146 virtual void tag_session_with_lightdm_id(std::shared_ptr<Session> const& session, int id) = 0;
147 virtual void focus_session_with_lightdm_id(int id) = 0;
148
149+ virtual bool request_focus(std::shared_ptr<Session> const& session) = 0;
150+
151 virtual void shutdown() = 0;
152
153 protected:
154
155=== modified file 'include/mir_test_doubles/mock_session.h'
156--- include/mir_test_doubles/mock_session.h 2013-03-12 00:40:38 +0000
157+++ include/mir_test_doubles/mock_session.h 2013-03-12 00:40:38 +0000
158@@ -41,6 +41,8 @@
159
160 MOCK_METHOD0(hide, void());
161 MOCK_METHOD0(show, void());
162+
163+ MOCK_CONST_METHOD0(has_appeared, bool());
164 };
165
166 }
167
168=== modified file 'include/mir_test_doubles/mock_session_store.h'
169--- include/mir_test_doubles/mock_session_store.h 2013-03-12 00:40:38 +0000
170+++ include/mir_test_doubles/mock_session_store.h 2013-03-12 00:40:38 +0000
171@@ -37,6 +37,8 @@
172
173 MOCK_METHOD2(tag_session_with_lightdm_id, void(std::shared_ptr<shell::Session> const&, int));
174 MOCK_METHOD1(focus_session_with_lightdm_id, void(int));
175+
176+ MOCK_METHOD1(request_focus, bool(std::shared_ptr<shell::Session> const&));
177
178 MOCK_METHOD0(shutdown, void());
179 };
180
181=== modified file 'include/mir_test_doubles/stub_session.h'
182--- include/mir_test_doubles/stub_session.h 2013-03-12 00:40:38 +0000
183+++ include/mir_test_doubles/stub_session.h 2013-03-12 00:40:38 +0000
184@@ -54,6 +54,10 @@
185 void show()
186 {
187 }
188+ bool has_appeared() const
189+ {
190+ return false;
191+ }
192 };
193
194 }
195
196=== modified file 'include/mir_test_doubles/stub_session_store.h'
197--- include/mir_test_doubles/stub_session_store.h 2013-03-12 00:40:38 +0000
198+++ include/mir_test_doubles/stub_session_store.h 2013-03-12 00:40:38 +0000
199@@ -44,6 +44,10 @@
200 void focus_session_with_lightdm_id(int /* id */)
201 {
202 }
203+ bool request_focus(std::shared_ptr<shell::Session> const& /* session */)
204+ {
205+ return false;
206+ }
207 void shutdown()
208 {
209 }
210
211=== modified file 'src/shell/application_session.cpp'
212--- src/shell/application_session.cpp 2013-03-06 12:54:33 +0000
213+++ src/shell/application_session.cpp 2013-03-12 00:40:38 +0000
214@@ -18,6 +18,7 @@
215
216 #include "mir/shell/application_session.h"
217 #include "mir/shell/surface.h"
218+#include "mir/shell/focus_arbitrator.h"
219
220 #include "mir/surfaces/surface_controller.h"
221
222@@ -33,8 +34,10 @@
223
224 msh::ApplicationSession::ApplicationSession(
225 std::shared_ptr<msh::SurfaceFactory> const& surface_factory,
226+ msh::FocusArbitrator &focus_arbitrator,
227 std::string const& session_name) :
228 surface_factory(surface_factory),
229+ focus_arbitrator(focus_arbitrator),
230 session_name(session_name),
231 next_surface_id(0)
232 {
233@@ -60,8 +63,12 @@
234 auto surf = surface_factory->create_surface(params);
235 auto const id = next_id();
236
237+ // Careful of ordering with respect to the focus arbitrators invocation of has_appeared()
238+ focus_arbitrator.request_focus(shared_from_this());
239+
240 std::unique_lock<std::mutex> lock(surfaces_mutex);
241 surfaces[id] = surf;
242+
243 return id;
244 }
245
246@@ -122,3 +129,9 @@
247 id_s.second->show();
248 }
249 }
250+
251+bool msh::ApplicationSession::has_appeared() const
252+{
253+ std::unique_lock<std::mutex> lock(surfaces_mutex);
254+ return surfaces.size() > 0 ;
255+}
256
257=== modified file 'src/shell/session_manager.cpp'
258--- src/shell/session_manager.cpp 2013-03-06 12:54:33 +0000
259+++ src/shell/session_manager.cpp 2013-03-12 00:40:38 +0000
260@@ -51,7 +51,7 @@
261
262 std::shared_ptr<msh::Session> msh::SessionManager::open_session(std::string const& name)
263 {
264- auto new_session = std::make_shared<msh::ApplicationSession>(surface_factory, name);
265+ auto new_session = std::make_shared<msh::ApplicationSession>(surface_factory, *this, name);
266
267 app_container->insert_session(new_session);
268
269@@ -134,3 +134,12 @@
270 set_focus_to(match->second);
271 }
272 }
273+
274+bool msh::SessionManager::request_focus(std::shared_ptr<msh::Session> const& session)
275+{
276+ if (session->has_appeared())
277+ return false;
278+
279+ set_focus_to(session);
280+ return true;
281+}
282
283=== modified file 'tests/acceptance-tests/test_focus_management_api.cpp'
284--- tests/acceptance-tests/test_focus_management_api.cpp 2013-03-06 12:25:34 +0000
285+++ tests/acceptance-tests/test_focus_management_api.cpp 2013-03-12 00:40:38 +0000
286@@ -19,6 +19,7 @@
287 #include "mir_toolkit/mir_client_library_lightdm.h"
288
289 #include "mir/shell/session_store.h"
290+#include "mir/shell/session.h"
291
292 #include "mir_test_doubles/mock_display.h"
293 #include "mir_test_framework/display_server_test_fixture.h"
294@@ -132,6 +133,8 @@
295
296 ON_CALL(*this, tag_session_with_lightdm_id(_, _)).WillByDefault(Invoke(impl.get(), &SessionStore::tag_session_with_lightdm_id));
297 ON_CALL(*this, focus_session_with_lightdm_id(_)).WillByDefault(Invoke(impl.get(), &SessionStore::focus_session_with_lightdm_id));
298+
299+ ON_CALL(*this, request_focus(_)).WillByDefault(Invoke(impl.get(), &SessionStore::request_focus));
300
301 ON_CALL(*this, shutdown()).WillByDefault(Invoke(impl.get(), &SessionStore::shutdown));
302 }
303@@ -141,6 +144,8 @@
304
305 MOCK_METHOD2(tag_session_with_lightdm_id, void (std::shared_ptr<shell::Session> const& session, int id));
306 MOCK_METHOD1(focus_session_with_lightdm_id, void (int id));
307+
308+ MOCK_METHOD1(request_focus, bool (std::shared_ptr<shell::Session> const&));
309
310 MOCK_METHOD0(shutdown, void ());
311
312
313=== modified file 'tests/integration-tests/CMakeLists.txt'
314--- tests/integration-tests/CMakeLists.txt 2013-03-07 10:50:43 +0000
315+++ tests/integration-tests/CMakeLists.txt 2013-03-12 00:40:38 +0000
316@@ -12,6 +12,7 @@
317 add_subdirectory(client/)
318 add_subdirectory(compositor/)
319 add_subdirectory(frontend/)
320+add_subdirectory(shell/)
321 add_subdirectory(process/)
322 if (NOT MIR_DISABLE_INPUT)
323 add_subdirectory(input/)
324
325=== modified file 'tests/integration-tests/frontend/CMakeLists.txt'
326--- tests/integration-tests/frontend/CMakeLists.txt 2013-03-04 15:54:45 +0000
327+++ tests/integration-tests/frontend/CMakeLists.txt 2013-03-12 00:40:38 +0000
328@@ -1,7 +1,6 @@
329 list(
330 APPEND INTEGRATION_TESTS_SRCS
331 ${CMAKE_CURRENT_SOURCE_DIR}/test_application_mediator_report.cpp
332- ${CMAKE_CURRENT_SOURCE_DIR}/test_session_manager.cpp
333 )
334
335 set(
336
337=== added directory 'tests/integration-tests/shell'
338=== added file 'tests/integration-tests/shell/CMakeLists.txt'
339--- tests/integration-tests/shell/CMakeLists.txt 1970-01-01 00:00:00 +0000
340+++ tests/integration-tests/shell/CMakeLists.txt 2013-03-12 00:40:38 +0000
341@@ -0,0 +1,9 @@
342+list(
343+ APPEND INTEGRATION_TESTS_SRCS
344+ ${CMAKE_CURRENT_SOURCE_DIR}/test_session_manager.cpp
345+)
346+
347+set(
348+ INTEGRATION_TESTS_SRCS
349+ ${INTEGRATION_TESTS_SRCS}
350+ PARENT_SCOPE)
351
352=== renamed file 'tests/integration-tests/frontend/test_session_manager.cpp' => 'tests/integration-tests/shell/test_session_manager.cpp'
353--- tests/integration-tests/frontend/test_session_manager.cpp 2013-03-06 12:54:33 +0000
354+++ tests/integration-tests/shell/test_session_manager.cpp 2013-03-12 00:40:38 +0000
355@@ -24,6 +24,8 @@
356 #include "mir/compositor/buffer_swapper.h"
357 #include "mir/shell/focus_sequence.h"
358 #include "mir/shell/focus_setter.h"
359+#include "mir/shell/session.h"
360+#include "mir/shell/surface.h"
361 #include "mir/shell/registration_order_focus_sequence.h"
362 #include "mir/shell/session_container.h"
363 #include "mir/shell/surface_creation_parameters.h"
364@@ -37,6 +39,7 @@
365 namespace mc = mir::compositor;
366 namespace msh = mir::shell;
367 namespace ms = mir::surfaces;
368+namespace geom = mir::geometry;
369 namespace mt = mir::test;
370 namespace mtd = mir::test::doubles;
371
372@@ -48,6 +51,37 @@
373 MOCK_METHOD1(set_focus_to, void(std::shared_ptr<msh::Session> const&));
374 };
375
376+struct StubSurface : public msh::Surface
377+{
378+ void hide()
379+ {
380+ }
381+ void show()
382+ {
383+ }
384+ void destroy()
385+ {
386+ }
387+ void shutdown()
388+ {
389+ }
390+ geom::Size size() const
391+ {
392+ return geom::Size();
393+ }
394+ geom::PixelFormat pixel_format() const
395+ {
396+ return geom::PixelFormat();
397+ }
398+ void advance_client_buffer()
399+ {
400+ }
401+ std::shared_ptr<mc::Buffer> client_buffer() const
402+ {
403+ return std::shared_ptr<mc::Buffer>();
404+ }
405+};
406+
407 }
408
409 TEST(TestSessionManagerAndFocusSelectionStrategy, cycle_focus)
410@@ -113,3 +147,33 @@
411 session_manager.close_session(session3);
412 session_manager.close_session(session2);
413 }
414+
415+TEST(TestSessionManagerAndSession, sessions_creating_first_surface_receive_focus)
416+{
417+ using namespace ::testing;
418+
419+ StubSurface stub_surface;
420+ mtd::MockSurfaceFactory surface_factory;
421+ std::shared_ptr<msh::SessionContainer> model(new msh::SessionContainer());
422+ msh::RegistrationOrderFocusSequence sequence(model);
423+ MockFocusSetter focus_changer;
424+ std::shared_ptr<msh::Session> new_session;
425+
426+ EXPECT_CALL(surface_factory, create_surface(_)).Times(2).WillRepeatedly(Return(mt::fake_shared(stub_surface)));
427+
428+ msh::SessionManager session_manager(
429+ mt::fake_shared(surface_factory),
430+ model,
431+ mt::fake_shared(sequence),
432+ mt::fake_shared(focus_changer));
433+
434+ // Once for creating the session and a second time at surface creation
435+ EXPECT_CALL(focus_changer, set_focus_to(_)).Times(2);
436+
437+ // Triggers a focus set
438+ auto session1 = session_manager.open_session("Yesterday");
439+ // Also triggers a focus change
440+ session1->create_surface(msh::a_surface());
441+ // Should not trigger a focus change
442+ session1->create_surface(msh::a_surface());
443+}
444
445=== modified file 'tests/unit-tests/shell/test_application_session.cpp'
446--- tests/unit-tests/shell/test_application_session.cpp 2013-03-12 00:40:38 +0000
447+++ tests/unit-tests/shell/test_application_session.cpp 2013-03-12 00:40:38 +0000
448@@ -19,6 +19,7 @@
449 #include "mir/shell/application_session.h"
450 #include "mir/compositor/buffer.h"
451 #include "mir/shell/surface_creation_parameters.h"
452+#include "mir/shell/focus_arbitrator.h"
453 #include "mir_test/fake_shared.h"
454 #include "mir_test_doubles/mock_surface_factory.h"
455 #include "mir_test_doubles/mock_surface.h"
456@@ -34,23 +35,59 @@
457 namespace mt = mir::test;
458 namespace mtd = mir::test::doubles;
459
460+namespace
461+{
462+
463+struct MockFocusArbitrator : public msh::FocusArbitrator
464+{
465+ MOCK_METHOD1(request_focus, bool(std::shared_ptr<msh::Session> const&));
466+};
467+
468+}
469+
470 TEST(ApplicationSession, create_and_destroy_surface)
471 {
472 using namespace ::testing;
473
474 auto const mock_surface = std::make_shared<mtd::MockSurface>();
475 mtd::MockSurfaceFactory surface_factory;
476+ NiceMock<MockFocusArbitrator> focus_arbitrator;
477+
478 ON_CALL(surface_factory, create_surface(_)).WillByDefault(Return(mock_surface));
479
480 EXPECT_CALL(surface_factory, create_surface(_));
481 EXPECT_CALL(*mock_surface, destroy());
482
483- msh::ApplicationSession session(mt::fake_shared(surface_factory), "Foo");
484+ auto session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
485
486 msh::SurfaceCreationParameters params;
487- auto surf = session.create_surface(params);
488-
489- session.destroy_surface(surf);
490+ auto surf = session->create_surface(params);
491+
492+ session->destroy_surface(surf);
493+}
494+
495+TEST(ApplicationSession, must_be_managed_by_shared_ptr_to_create_surface)
496+{
497+ using namespace ::testing;
498+
499+ auto const mock_surface = std::make_shared<NiceMock<mtd::MockSurface>>();
500+ NiceMock<mtd::MockSurfaceFactory> surface_factory;
501+ NiceMock<MockFocusArbitrator> focus_arbitrator;
502+
503+ ON_CALL(surface_factory, create_surface(_)).WillByDefault(Return(mock_surface));
504+
505+ auto session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
506+ msh::ApplicationSession unmanaged_session(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
507+
508+ EXPECT_NO_THROW({
509+ session->create_surface(msh::a_surface());
510+ });
511+
512+ // Since create surface uses std::enable_shared_from this to request focus from the focus arbitrator
513+ // creating a surface from an unmanaged session will throw
514+ EXPECT_THROW({
515+ unmanaged_session.create_surface(msh::a_surface());
516+ }, std::bad_weak_ptr);
517 }
518
519
520@@ -60,9 +97,11 @@
521
522 auto const mock_surface = std::make_shared<mtd::MockSurface>();
523 mtd::MockSurfaceFactory surface_factory;
524+ NiceMock<MockFocusArbitrator> focus_arbitrator;
525+
526 ON_CALL(surface_factory, create_surface(_)).WillByDefault(Return(mock_surface));
527
528- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
529+ auto app_session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
530
531 EXPECT_CALL(surface_factory, create_surface(_));
532
533@@ -74,36 +113,69 @@
534 }
535
536 msh::SurfaceCreationParameters params;
537- auto surf = app_session.create_surface(params);
538-
539- app_session.hide();
540- app_session.show();
541-
542- app_session.destroy_surface(surf);
543-}
544-
545-TEST(Session, get_invalid_surface_throw_behavior)
546-{
547- using namespace ::testing;
548-
549- mtd::MockSurfaceFactory surface_factory;
550- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
551+ auto surf = app_session->create_surface(params);
552+
553+ app_session->hide();
554+ app_session->show();
555+
556+ app_session->destroy_surface(surf);
557+}
558+
559+TEST(ApplicationSession, creating_suface_requests_focus)
560+{
561+ using namespace ::testing;
562+
563+ mtd::MockSurfaceFactory surface_factory;
564+ mtd::MockSurface mock_surface;
565+ MockFocusArbitrator focus_arbitrator;
566+
567+ ON_CALL(surface_factory, create_surface(_)).WillByDefault(Return(mt::fake_shared(mock_surface)));
568+ EXPECT_CALL(focus_arbitrator, request_focus(_)).Times(1).WillOnce(Return(true));
569+
570+ auto app_session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
571+ app_session->create_surface(msh::a_surface());
572+}
573+
574+TEST(ApplicationSession, session_has_appeared_after_creating_surface)
575+{
576+ using namespace ::testing;
577+
578+ mtd::MockSurfaceFactory surface_factory;
579+ mtd::MockSurface mock_surface;
580+ NiceMock<MockFocusArbitrator> focus_arbitrator;
581+
582+ ON_CALL(surface_factory, create_surface(_)).WillByDefault(Return(mt::fake_shared(mock_surface)));
583+
584+ auto app_session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
585+ EXPECT_FALSE(app_session->has_appeared());
586+ app_session->create_surface(msh::a_surface());
587+ EXPECT_TRUE(app_session->has_appeared());
588+}
589+
590+TEST(ApplicationSession, get_invalid_surface_throw_behavior)
591+{
592+ using namespace ::testing;
593+
594+ mtd::MockSurfaceFactory surface_factory;
595+ NiceMock<MockFocusArbitrator> focus_arbitrator;
596+ auto app_session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
597 msh::SurfaceId invalid_surface_id = msh::SurfaceId{1};
598
599 EXPECT_THROW({
600- app_session.get_surface(invalid_surface_id);
601+ app_session->get_surface(invalid_surface_id);
602 }, std::runtime_error);
603 }
604
605-TEST(Session, destroy_invalid_surface_throw_behavior)
606+TEST(ApplicationSession, destroy_invalid_surface_throw_behavior)
607 {
608 using namespace ::testing;
609
610 mtd::MockSurfaceFactory surface_factory;
611- msh::ApplicationSession app_session(mt::fake_shared(surface_factory), "Foo");
612+ NiceMock<MockFocusArbitrator> focus_arbitrator;
613+ auto app_session = std::make_shared<msh::ApplicationSession>(mt::fake_shared(surface_factory), focus_arbitrator, "Foo");
614 msh::SurfaceId invalid_surface_id = msh::SurfaceId{1};
615
616 EXPECT_THROW({
617- app_session.destroy_surface(invalid_surface_id);
618+ app_session->destroy_surface(invalid_surface_id);
619 }, std::runtime_error);
620 }
621
622=== modified file 'tests/unit-tests/shell/test_registration_order_focus_sequence.cpp'
623--- tests/unit-tests/shell/test_registration_order_focus_sequence.cpp 2013-03-06 12:54:33 +0000
624+++ tests/unit-tests/shell/test_registration_order_focus_sequence.cpp 2013-03-12 00:40:38 +0000
625@@ -17,13 +17,15 @@
626 */
627
628 #include "mir/surfaces/buffer_bundle.h"
629-#include "mir/shell/application_session.h"
630+#include "mir/shell/session.h"
631 #include "mir/shell/session_container.h"
632 #include "mir/shell/registration_order_focus_sequence.h"
633 #include "mir/shell/surface_creation_parameters.h"
634 #include "mir/surfaces/surface.h"
635+
636+#include "mir_test/fake_shared.h"
637 #include "mir_test_doubles/mock_buffer_bundle.h"
638-#include "mir_test_doubles/mock_surface_factory.h"
639+#include "mir_test_doubles/stub_session.h"
640
641 #include <gmock/gmock.h>
642 #include <gtest/gtest.h>
643@@ -32,7 +34,8 @@
644 namespace mc = mir::compositor;
645 namespace msh = mir::shell;
646 namespace ms = mir::surfaces;
647-namespace mtd = mir::test::doubles;
648+namespace mt = mir::test;
649+namespace mtd = mt::doubles;
650
651 namespace
652 {
653@@ -40,30 +43,19 @@
654 {
655 void SetUp()
656 {
657- factory = std::make_shared<mtd::MockSurfaceFactory>();
658 container = std::make_shared<msh::SessionContainer>();
659 }
660- std::shared_ptr<mtd::MockSurfaceFactory> factory;
661 std::shared_ptr<msh::SessionContainer> container;
662-
663- static std::string const testing_app_name1;
664- static std::string const testing_app_name2;
665- static std::string const testing_app_name3;
666 };
667-
668-std::string const RegistrationOrderFocusSequenceSetup::testing_app_name1{"Visual Studio 7"};
669-std::string const RegistrationOrderFocusSequenceSetup::testing_app_name2{"Visual Studio 8"};
670-std::string const RegistrationOrderFocusSequenceSetup::testing_app_name3{"Visual Studio 9"};
671 }
672
673 TEST_F(RegistrationOrderFocusSequenceSetup, focus_order)
674 {
675 using namespace ::testing;
676
677- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
678- auto app2 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name2);
679- auto app3 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name3);
680-
681+ auto app1 = std::make_shared<mtd::StubSession>();
682+ auto app2 = std::make_shared<mtd::StubSession>();
683+ auto app3 = std::make_shared<mtd::StubSession>();
684 container->insert_session(app1);
685 container->insert_session(app2);
686 container->insert_session(app3);
687@@ -78,9 +70,9 @@
688 {
689 using namespace ::testing;
690
691- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
692- auto app2 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name2);
693- auto app3 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name3);
694+ auto app1 = std::make_shared<mtd::StubSession>();
695+ auto app2 = std::make_shared<mtd::StubSession>();
696+ auto app3 = std::make_shared<mtd::StubSession>();
697 container->insert_session(app1);
698 container->insert_session(app2);
699 container->insert_session(app3);
700@@ -95,7 +87,7 @@
701 {
702 using namespace ::testing;
703
704- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
705+ auto app1 = std::make_shared<mtd::StubSession>();
706 container->insert_session(app1);
707
708 msh::RegistrationOrderFocusSequence focus_sequence(container);
709@@ -107,9 +99,9 @@
710 {
711 using namespace ::testing;
712
713- auto app1 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
714- auto app2 = std::make_shared<msh::ApplicationSession>(factory, testing_app_name2);
715- auto null_session = std::shared_ptr<msh::ApplicationSession>();
716+ auto app1 = std::make_shared<mtd::StubSession>();
717+ auto app2 = std::make_shared<mtd::StubSession>();
718+ auto null_session = std::shared_ptr<msh::Session>();
719
720 msh::RegistrationOrderFocusSequence focus_sequence(container);
721
722@@ -124,8 +116,8 @@
723 {
724 using namespace ::testing;
725
726- auto invalid_session = std::make_shared<msh::ApplicationSession>(factory, testing_app_name1);
727- auto null_session = std::shared_ptr<msh::ApplicationSession>();
728+ auto invalid_session = std::make_shared<mtd::StubSession>();
729+ auto null_session = std::shared_ptr<msh::Session>();
730
731 msh::RegistrationOrderFocusSequence focus_sequence(container);
732
733
734=== modified file 'tests/unit-tests/shell/test_session_manager.cpp'
735--- tests/unit-tests/shell/test_session_manager.cpp 2013-03-06 18:12:43 +0000
736+++ tests/unit-tests/shell/test_session_manager.cpp 2013-03-12 00:40:38 +0000
737@@ -28,6 +28,7 @@
738 #include "mir_test/fake_shared.h"
739 #include "mir_test_doubles/mock_surface_factory.h"
740 #include "mir_test_doubles/null_buffer_bundle.h"
741+#include "mir_test_doubles/mock_session.h"
742
743 #include "src/surfaces/proxy_surface.h"
744
745@@ -114,8 +115,9 @@
746
747 EXPECT_CALL(container, insert_session(_)).Times(1);
748 EXPECT_CALL(container, remove_session(_)).Times(1);
749-
750- EXPECT_CALL(focus_setter, set_focus_to(_)).Times(1);
751+
752+ // Once for session creation and once for surface creation
753+ EXPECT_CALL(focus_setter, set_focus_to(_)).Times(2);
754 EXPECT_CALL(focus_setter, set_focus_to(std::shared_ptr<msh::Session>())).Times(1);
755
756 EXPECT_CALL(sequence, default_focus()).WillOnce(Return((std::shared_ptr<msh::Session>())));
757@@ -166,3 +168,21 @@
758
759 session_manager.close_session(session1);
760 }
761+
762+
763+TEST_F(SessionManagerSetup, request_focus_sets_focus_for_sessions_which_have_not_appeared)
764+{
765+ using namespace ::testing;
766+ // It is ok to use a session not managed by the session manager as the exceptional behavior is defined in the real focus setter
767+ mtd::MockSession session;
768+
769+ {
770+ InSequence seq;
771+ EXPECT_CALL(session, has_appeared()).Times(1).WillOnce(Return(false));
772+ EXPECT_CALL(session, has_appeared()).Times(1).WillOnce(Return(true));
773+ }
774+ EXPECT_CALL(focus_setter, set_focus_to(_)).Times(1);
775+
776+ EXPECT_TRUE(session_manager.request_focus(mt::fake_shared(session)));
777+ EXPECT_FALSE(session_manager.request_focus(mt::fake_shared(session)));
778+}
779
780=== modified file 'tests/unit-tests/shell/test_the_session_container_implementation.cpp'
781--- tests/unit-tests/shell/test_the_session_container_implementation.cpp 2013-03-06 12:54:33 +0000
782+++ tests/unit-tests/shell/test_the_session_container_implementation.cpp 2013-03-12 00:40:38 +0000
783@@ -17,42 +17,43 @@
784 */
785
786 #include "mir/surfaces/buffer_bundle.h"
787-#include "mir/shell/application_session.h"
788+#include "mir/shell/session.h"
789 #include "mir/shell/session_container.h"
790 #include "mir/shell/surface_creation_parameters.h"
791 #include "mir/surfaces/surface.h"
792-#include "mir_test_doubles/mock_buffer_bundle.h"
793-#include "mir_test_doubles/mock_surface_factory.h"
794+
795+#include "mir_test/fake_shared.h"
796+#include "mir_test_doubles/mock_session.h"
797
798 #include <gmock/gmock.h>
799 #include <gtest/gtest.h>
800 #include <string>
801
802 namespace msh = mir::shell;
803-namespace mtd = mir::test::doubles;
804+namespace mt = mir::test;
805+namespace mtd = mt::doubles;
806
807 TEST(SessionContainer, for_each)
808 {
809 using namespace ::testing;
810- auto factory = std::make_shared<mtd::MockSurfaceFactory>();
811 msh::SessionContainer container;
812
813- container.insert_session(std::make_shared<msh::ApplicationSession>(factory, "Visual Studio 7"));
814- container.insert_session(std::make_shared<msh::ApplicationSession>(factory, "Visual Studio 8"));
815+ mtd::MockSession session1;
816+ mtd::MockSession session2;
817+
818+ container.insert_session(mt::fake_shared(session1));
819+ container.insert_session(mt::fake_shared(session2));
820
821 struct local
822 {
823- MOCK_METHOD1(check_name, void (std::string const&));
824-
825 void operator()(std::shared_ptr<msh::Session> const& session)
826 {
827- check_name(session->name());
828+ session->name();
829 }
830 } functor;
831
832- InSequence seq;
833- EXPECT_CALL(functor, check_name("Visual Studio 7"));
834- EXPECT_CALL(functor, check_name("Visual Studio 8"));
835+ EXPECT_CALL(session1, name()).WillOnce(Return("VS 7"));
836+ EXPECT_CALL(session2, name()).WillOnce(Return("VS 8"));
837
838 container.for_each(std::ref(functor));
839 }
840@@ -60,12 +61,10 @@
841 TEST(SessionContainer, invalid_session_throw_behavior)
842 {
843 using namespace ::testing;
844- auto factory = std::make_shared<mtd::MockSurfaceFactory>();
845 msh::SessionContainer container;
846+ mtd::MockSession invalid_session;
847
848- auto session = std::make_shared<msh::ApplicationSession>(factory,
849- "Visual Studio 7");
850 EXPECT_THROW({
851- container.remove_session(session);
852+ container.remove_session(mt::fake_shared(invalid_session));
853 }, std::logic_error);
854 }

Subscribers

People subscribed via source and target branches