2
* Copyright © 2015 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: ALan Griffiths <alan.griffiths@canonical.com>
19
#include "src/server/shell/default_shell.h"
21
#include "mir/scene/session.h"
22
#include "mir/scene/null_session_listener.h"
23
#include "mir/scene/placement_strategy.h"
24
#include "mir/scene/prompt_session.h"
25
#include "mir/scene/prompt_session_creation_parameters.h"
26
#include "mir/scene/surface_creation_parameters.h"
28
#include "src/server/scene/default_session_container.h"
29
#include "src/server/scene/session_event_sink.h"
30
#include "src/server/scene/session_manager.h"
32
#include "mir_test_doubles/mock_surface_coordinator.h"
33
#include "mir_test_doubles/mock_session_listener.h"
34
#include "mir_test_doubles/mock_surface.h"
35
#include "mir_test_doubles/null_snapshot_strategy.h"
36
#include "mir_test_doubles/null_prompt_session_manager.h"
37
#include "mir_test_doubles/stub_input_targeter.h"
39
#include "mir_test/fake_shared.h"
41
#include <gmock/gmock.h>
42
#include <gtest/gtest.h>
44
namespace mc = mir::compositor;
45
namespace mf = mir::frontend;
46
namespace mi = mir::input;
47
namespace ms = mir::scene;
48
namespace mg = mir::graphics;
49
namespace geom = mir::geometry;
50
namespace mt = mir::test;
51
namespace mtd = mir::test::doubles;
52
namespace msh = mir::shell;
53
using namespace ::testing;
57
struct MockSessionContainer : public ms::SessionContainer
59
MOCK_METHOD1(insert_session, void(std::shared_ptr<ms::Session> const&));
60
MOCK_METHOD1(remove_session, void(std::shared_ptr<ms::Session> const&));
61
MOCK_CONST_METHOD1(successor_of, std::shared_ptr<ms::Session>(std::shared_ptr<ms::Session> const&));
62
MOCK_CONST_METHOD1(for_each, void(std::function<void(std::shared_ptr<ms::Session> const&)>));
63
MOCK_METHOD0(lock, void());
64
MOCK_METHOD0(unlock, void());
65
~MockSessionContainer() noexcept {}
68
struct MockSessionEventSink : public ms::SessionEventSink
70
MOCK_METHOD1(handle_focus_change, void(std::shared_ptr<ms::Session> const& session));
71
MOCK_METHOD0(handle_no_focus, void());
72
MOCK_METHOD1(handle_session_stopping, void(std::shared_ptr<ms::Session> const& session));
79
struct MockPlacementStrategy : public ms::PlacementStrategy
81
MockPlacementStrategy()
83
ON_CALL(*this, place(_, _)).WillByDefault(ReturnArg<1>());
86
MOCK_METHOD2(place, ms::SurfaceCreationParameters(ms::Session const&, ms::SurfaceCreationParameters const&));
89
struct MockSessionManager : ms::SessionManager
91
using ms::SessionManager::SessionManager;
93
MOCK_METHOD1(set_focus_to, void (std::shared_ptr<ms::Session> const& focus));
95
void unmocked_set_focus_to(std::shared_ptr<ms::Session> const& focus)
96
{ ms::SessionManager::set_focus_to(focus); }
99
struct DefaultShell : Test
101
NiceMock<mtd::MockSurface> mock_surface;
102
MockPlacementStrategy placement_strategy;
103
NiceMock<mtd::MockSurfaceCoordinator> surface_coordinator;
104
NiceMock<MockSessionContainer> container;
105
NiceMock<MockSessionEventSink> session_event_sink;
106
NiceMock<mtd::MockSessionListener> session_listener;
108
NiceMock<MockSessionManager> session_manager{
109
mt::fake_shared(surface_coordinator),
110
mt::fake_shared(container),
111
std::make_shared<mtd::NullSnapshotStrategy>(),
112
mt::fake_shared(session_event_sink),
113
mt::fake_shared(session_listener)};
115
mtd::StubInputTargeter input_targeter;
116
msh::DefaultShell shell{
117
mt::fake_shared(input_targeter),
118
mt::fake_shared(surface_coordinator),
119
mt::fake_shared(session_manager),
120
std::make_shared<mtd::NullPromptSessionManager>(),
121
mt::fake_shared(placement_strategy)};
123
void SetUp() override
125
ON_CALL(container, successor_of(_)).WillByDefault(Return((std::shared_ptr<ms::Session>())));
126
ON_CALL(session_manager, set_focus_to(_)).
127
WillByDefault(Invoke(&session_manager, &MockSessionManager::unmocked_set_focus_to));
128
ON_CALL(surface_coordinator, add_surface(_,_))
129
.WillByDefault(Return(mt::fake_shared(mock_surface)));
134
TEST_F(DefaultShell, new_applications_receive_focus)
136
std::shared_ptr<ms::Session> new_session;
138
EXPECT_CALL(container, insert_session(_)).Times(1);
139
EXPECT_CALL(session_manager, set_focus_to(_)).WillOnce(SaveArg<0>(&new_session));
141
auto session = shell.open_session(__LINE__, "Visual Basic Studio", std::shared_ptr<mf::EventSink>());
142
EXPECT_EQ(session, new_session);
145
TEST_F(DefaultShell, session_listener_is_notified_of_focus)
147
EXPECT_CALL(session_listener, focused(_)).Times(1);
148
EXPECT_CALL(session_listener, unfocused()).Times(1);
150
auto session = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>());
151
shell.close_session(session);
154
TEST_F(DefaultShell, session_event_sink_is_notified_of_focus)
156
EXPECT_CALL(session_event_sink, handle_focus_change(_)).Times(2);
158
auto session = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>());
159
auto session1 = shell.open_session(__LINE__, "Bla", std::shared_ptr<mf::EventSink>());
161
Mock::VerifyAndClearExpectations(&session_event_sink);
164
EXPECT_CALL(session_event_sink, handle_session_stopping(_)).Times(1);
165
EXPECT_CALL(container, successor_of(_)).
166
WillOnce(Return(std::dynamic_pointer_cast<ms::Session>(session)));
167
EXPECT_CALL(session_event_sink, handle_focus_change(_)).Times(1);
168
EXPECT_CALL(session_event_sink, handle_session_stopping(_)).Times(1);
169
EXPECT_CALL(container, successor_of(_)).
170
WillOnce(Return(std::shared_ptr<ms::Session>()));
171
EXPECT_CALL(session_event_sink, handle_no_focus()).Times(1);
173
shell.close_session(session1);
174
shell.close_session(session);
177
TEST_F(DefaultShell, offers_create_surface_parameters_to_placement_strategy)
179
std::shared_ptr<ms::Session> session;
180
EXPECT_CALL(session_manager, set_focus_to(_)).WillOnce(SaveArg<0>(&session));
181
shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>());
183
auto params = ms::a_surface();
184
EXPECT_CALL(placement_strategy, place(Ref(*session), Ref(params)));
186
shell.create_surface(session, params);
189
TEST_F(DefaultShell, forwards_create_surface_parameters_from_placement_strategy_to_model)
191
std::shared_ptr<ms::Session> session;
192
EXPECT_CALL(session_manager, set_focus_to(_)).WillOnce(SaveArg<0>(&session));
193
shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>());
195
auto params = ms::a_surface();
196
auto placed_params = params;
197
placed_params.size.width = geom::Width{100};
199
EXPECT_CALL(placement_strategy, place(_, Ref(params))).Times(1)
200
.WillOnce(Return(placed_params));
201
EXPECT_CALL(surface_coordinator, add_surface(placed_params, _));
203
shell.create_surface(session, params);