Merge lp:~afrantzis/mir/fix-1511798-alternative into lp:mir
- fix-1511798-alternative
- Merge into development-branch
Status: | Rejected |
---|---|
Rejected by: | Alexandros Frantzis |
Proposed branch: | lp:~afrantzis/mir/fix-1511798-alternative |
Merge into: | lp:mir |
Diff against target: |
280 lines (+156/-18) 5 files modified
src/server/scene/mediating_display_changer.cpp (+1/-1) src/server/shell/abstract_shell.cpp (+20/-11) tests/acceptance-tests/test_display_configuration.cpp (+3/-3) tests/acceptance-tests/test_nested_mir.cpp (+82/-0) tests/unit-tests/scene/test_abstract_shell.cpp (+50/-3) |
To merge this branch: | bzr merge lp:~afrantzis/mir/fix-1511798-alternative |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Needs Fixing | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+276852@code.launchpad.net |
Commit message
shell: fix updating of display configuration when applications and nested servers exit
Description of the change
shell: fix updating of display configuration when applications and nested servers exit
The tests for nested mir behavior were cherrypicked from Alan's original proposal.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:3093
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alan Griffiths (alan-griffiths) wrote : | # |
> I'm confused.
>
> When I try the scenario in lp:1511798 I don't see an attempt to restore the
> host config after exiting the client. (But that's what
> display_
>
> I need to check what is different between the automated and manual test
> scenarios.
I understand the difference - AbstractShell:
I have to think about the right solution here.
Alan Griffiths (alan-griffiths) wrote : | # |
I think the right solution is to move the "session-
It seems like a PITA, but this allows the window management policy control over the point at which the surface and decorations are destroyed.
Alan Griffiths (alan-griffiths) wrote : | # |
Alexandros Frantzis (afrantzis) wrote : | # |
Rejected in favor of the other alternative.
Preview Diff
1 | === modified file 'src/server/scene/mediating_display_changer.cpp' |
2 | --- src/server/scene/mediating_display_changer.cpp 2015-11-05 12:54:02 +0000 |
3 | +++ src/server/scene/mediating_display_changer.cpp 2015-11-06 10:57:51 +0000 |
4 | @@ -148,7 +148,7 @@ |
5 | { |
6 | std::lock_guard<std::mutex> lg{configuration_mutex}; |
7 | |
8 | - return base_configuration_; |
9 | + return base_configuration_->clone(); |
10 | } |
11 | |
12 | void ms::MediatingDisplayChanger::configure_for_hardware_change( |
13 | |
14 | === modified file 'src/server/shell/abstract_shell.cpp' |
15 | --- src/server/shell/abstract_shell.cpp 2015-11-04 07:43:28 +0000 |
16 | +++ src/server/shell/abstract_shell.cpp 2015-11-06 10:57:51 +0000 |
17 | @@ -107,8 +107,11 @@ |
18 | mf::SurfaceId surface) |
19 | { |
20 | report->destroying_surface(*session, surface); |
21 | - window_manager->remove_surface(session, session->surface(surface)); |
22 | + // Order matters. The surface needs to be destroyed before calling the WM, |
23 | + // so the WM and its tools can make decisions based on up-to-date information. |
24 | + auto weak_surface = std::weak_ptr<ms::Surface>{session->surface(surface)}; |
25 | session->destroy_surface(surface); |
26 | + window_manager->remove_surface(session, weak_surface); |
27 | } |
28 | |
29 | std::shared_ptr<ms::PromptSession> msh::AbstractShell::start_prompt_session_for( |
30 | @@ -163,16 +166,22 @@ |
31 | void msh::AbstractShell::focus_next_session() |
32 | { |
33 | std::unique_lock<std::mutex> lock(focus_mutex); |
34 | - auto session = focus_session.lock(); |
35 | - |
36 | - session = session_coordinator->successor_of(session); |
37 | - |
38 | - std::shared_ptr<ms::Surface> surface; |
39 | - |
40 | - if (session) |
41 | - surface = session->default_surface(); |
42 | - |
43 | - set_focus_to_locked(lock, session, surface); |
44 | + auto const focused_session = focus_session.lock(); |
45 | + auto successor = session_coordinator->successor_of(focused_session); |
46 | + |
47 | + while (successor != nullptr && |
48 | + successor != focused_session && |
49 | + successor->default_surface() == nullptr) |
50 | + { |
51 | + successor = session_coordinator->successor_of(successor); |
52 | + } |
53 | + |
54 | + auto const surface = successor ? successor->default_surface() : nullptr; |
55 | + |
56 | + if (!surface) |
57 | + successor = nullptr; |
58 | + |
59 | + set_focus_to_locked(lock, successor, surface); |
60 | } |
61 | |
62 | std::shared_ptr<ms::Session> msh::AbstractShell::focused_session() const |
63 | |
64 | === modified file 'tests/acceptance-tests/test_display_configuration.cpp' |
65 | --- tests/acceptance-tests/test_display_configuration.cpp 2015-10-26 03:33:22 +0000 |
66 | +++ tests/acceptance-tests/test_display_configuration.cpp 2015-11-06 10:57:51 +0000 |
67 | @@ -22,7 +22,7 @@ |
68 | #include "mir/graphics/event_handler_register.h" |
69 | #include "mir/shell/display_configuration_controller.h" |
70 | |
71 | -#include "mir_test_framework/connected_client_headless_server.h" |
72 | +#include "mir_test_framework/connected_client_with_a_surface.h" |
73 | #include "mir/test/doubles/null_platform.h" |
74 | #include "mir/test/doubles/null_display.h" |
75 | #include "mir/test/doubles/null_display_sync_group.h" |
76 | @@ -143,13 +143,13 @@ |
77 | } |
78 | } |
79 | |
80 | -struct DisplayConfigurationTest : mtf::ConnectedClientHeadlessServer |
81 | +struct DisplayConfigurationTest : mtf::ConnectedClientWithASurface |
82 | { |
83 | void SetUp() override |
84 | { |
85 | server.override_the_session_authorizer([this] { return mt::fake_shared(stub_authorizer); }); |
86 | preset_display(mt::fake_shared(mock_display)); |
87 | - mtf::ConnectedClientHeadlessServer::SetUp(); |
88 | + mtf::ConnectedClientWithASurface::SetUp(); |
89 | } |
90 | |
91 | testing::NiceMock<MockDisplay> mock_display; |
92 | |
93 | === modified file 'tests/acceptance-tests/test_nested_mir.cpp' |
94 | --- tests/acceptance-tests/test_nested_mir.cpp 2015-11-04 17:59:20 +0000 |
95 | +++ tests/acceptance-tests/test_nested_mir.cpp 2015-11-06 10:57:51 +0000 |
96 | @@ -714,3 +714,85 @@ |
97 | mir_surface_release_sync(surface); |
98 | mir_connection_release(connection); |
99 | } |
100 | + |
101 | +// lp:1511798 |
102 | +TEST_F(NestedServer, display_configuration_reset_when_application_exits) |
103 | +{ |
104 | + NestedMirRunner nested_mir{new_connection()}; |
105 | + ignore_rebuild_of_egl_context(); |
106 | + |
107 | + auto const connection = mir_connect_sync(nested_mir.new_connection().c_str(), __PRETTY_FUNCTION__); |
108 | + |
109 | + // Need a painted surface to have focus |
110 | + auto const painted_surface = make_and_paint_surface(connection); |
111 | + |
112 | + auto const configuration = mir_connection_create_display_config(connection); |
113 | + |
114 | + configuration->outputs->used = false; |
115 | + |
116 | + mt::WaitCondition initial_condition; |
117 | + |
118 | + EXPECT_CALL(*the_mock_display_configuration_report(), new_configuration(_)) |
119 | + .WillRepeatedly(InvokeWithoutArgs([&] { initial_condition.wake_up_everyone(); })); |
120 | + |
121 | + mir_wait_for(mir_connection_apply_display_config(connection, configuration)); |
122 | + |
123 | + mir_display_config_destroy(configuration); |
124 | + mir_surface_release_sync(painted_surface); |
125 | + |
126 | + // Wait for initial config to be applied |
127 | + initial_condition.wait_for_at_most_seconds(1); |
128 | + Mock::VerifyAndClearExpectations(the_mock_display_configuration_report().get()); |
129 | + ASSERT_TRUE(initial_condition.woken()); |
130 | + |
131 | + mt::WaitCondition condition; |
132 | + EXPECT_CALL(*the_mock_display_configuration_report(), new_configuration(_)) |
133 | + .WillRepeatedly(InvokeWithoutArgs([&] { condition.wake_up_everyone(); })); |
134 | + |
135 | + mir_connection_release(connection); |
136 | + |
137 | + condition.wait_for_at_most_seconds(1); |
138 | + EXPECT_TRUE(condition.woken()); |
139 | + Mock::VerifyAndClearExpectations(the_mock_display_configuration_report().get()); |
140 | +} |
141 | + |
142 | +// lp:1511798 |
143 | +TEST_F(NestedServer, display_configuration_reset_when_nested_server_exits) |
144 | +{ |
145 | + mt::WaitCondition condition; |
146 | + |
147 | + { |
148 | + NestedMirRunner nested_mir{new_connection()}; |
149 | + ignore_rebuild_of_egl_context(); |
150 | + |
151 | + auto const connection = mir_connect_sync(nested_mir.new_connection().c_str(), __PRETTY_FUNCTION__); |
152 | + |
153 | + // Need a painted surface to have focus |
154 | + auto const painted_surface = make_and_paint_surface(connection); |
155 | + |
156 | + std::shared_ptr<mg::DisplayConfiguration> const new_config{nested_mir.server.the_display()->configuration()}; |
157 | + new_config->for_each_output([](mg::UserDisplayConfigurationOutput& output) |
158 | + { output.orientation = mir_orientation_inverted;}); |
159 | + |
160 | + mt::WaitCondition initial_condition; |
161 | + |
162 | + EXPECT_CALL(*the_mock_display_configuration_report(), new_configuration(_)) |
163 | + .WillRepeatedly(InvokeWithoutArgs([&] { initial_condition.wake_up_everyone(); })); |
164 | + |
165 | + nested_mir.server.the_display_configuration_controller()->set_base_configuration(new_config); |
166 | + |
167 | + // Wait for initial config to be applied |
168 | + initial_condition.wait_for_at_most_seconds(1); |
169 | + Mock::VerifyAndClearExpectations(the_mock_display_configuration_report().get()); |
170 | + ASSERT_TRUE(initial_condition.woken()); |
171 | + |
172 | + EXPECT_CALL(*the_mock_display_configuration_report(), new_configuration(_)) |
173 | + .WillRepeatedly(InvokeWithoutArgs([&] { condition.wake_up_everyone(); })); |
174 | + |
175 | + mir_surface_release_sync(painted_surface); |
176 | + mir_connection_release(connection); |
177 | + } |
178 | + |
179 | + condition.wait_for_at_most_seconds(1); |
180 | + EXPECT_TRUE(condition.woken()); |
181 | +} |
182 | |
183 | === modified file 'tests/unit-tests/scene/test_abstract_shell.cpp' |
184 | --- tests/unit-tests/scene/test_abstract_shell.cpp 2015-11-04 07:43:28 +0000 |
185 | +++ tests/unit-tests/scene/test_abstract_shell.cpp 2015-11-06 10:57:51 +0000 |
186 | @@ -31,7 +31,6 @@ |
187 | |
188 | #include "mir/test/doubles/mock_window_manager.h" |
189 | #include "mir/test/doubles/mock_surface_coordinator.h" |
190 | -#include "mir/test/doubles/mock_session_listener.h" |
191 | #include "mir/test/doubles/mock_surface.h" |
192 | #include "mir/test/doubles/null_event_sink.h" |
193 | #include "mir/test/doubles/null_snapshot_strategy.h" |
194 | @@ -107,7 +106,6 @@ |
195 | NiceMock<mtd::MockSurfaceCoordinator> surface_coordinator; |
196 | NiceMock<MockSessionContainer> session_container; |
197 | NiceMock<MockSessionEventSink> session_event_sink; |
198 | - NiceMock<mtd::MockSessionListener> session_listener; |
199 | NiceMock<MockSurfaceFactory> surface_factory; |
200 | mtd::StubDisplay display{3}; |
201 | |
202 | @@ -118,7 +116,7 @@ |
203 | mt::fake_shared(session_container), |
204 | std::make_shared<mtd::NullSnapshotStrategy>(), |
205 | mt::fake_shared(session_event_sink), |
206 | - mt::fake_shared(session_listener), |
207 | + std::make_shared<ms::NullSessionListener>(), |
208 | mt::fake_shared(display), |
209 | std::make_shared<mtd::NullANRDetector>()}; |
210 | |
211 | @@ -367,6 +365,9 @@ |
212 | msh::FocusController& focus_controller = shell; |
213 | auto session = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>()); |
214 | auto session1 = shell.open_session(__LINE__, "Bla", std::shared_ptr<mf::EventSink>()); |
215 | + shell.create_surface(session, ms::a_surface(), nullptr); |
216 | + shell.create_surface(session1, ms::a_surface(), nullptr); |
217 | + |
218 | focus_controller.set_focus_to(session, {}); |
219 | |
220 | EXPECT_CALL(session_container, successor_of(session)). |
221 | @@ -381,6 +382,9 @@ |
222 | { |
223 | auto session = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>()); |
224 | auto session1 = shell.open_session(__LINE__, "Bla", std::shared_ptr<mf::EventSink>()); |
225 | + shell.create_surface(session, ms::a_surface(), nullptr); |
226 | + shell.create_surface(session1, ms::a_surface(), nullptr); |
227 | + |
228 | EXPECT_CALL(session_container, successor_of(session1)). |
229 | WillOnce(Return(session)); |
230 | |
231 | @@ -440,6 +444,49 @@ |
232 | EXPECT_THAT(focus_controller.surface_at(cursor), Eq(surface)); |
233 | } |
234 | |
235 | +TEST_F(AbstractShell, as_focus_controller_focus_next_session_skips_surfaceless_sessions) |
236 | +{ |
237 | + msh::FocusController& focus_controller = shell; |
238 | + auto session = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>()); |
239 | + auto session1 = shell.open_session(__LINE__, "Surfaceless", std::shared_ptr<mf::EventSink>()); |
240 | + auto session2 = shell.open_session(__LINE__, "Bla", std::shared_ptr<mf::EventSink>()); |
241 | + auto surface_id = shell.create_surface(session, ms::a_surface(), nullptr); |
242 | + shell.create_surface(session2, ms::a_surface(), nullptr); |
243 | + |
244 | + focus_controller.set_focus_to(session, session->surface(surface_id)); |
245 | + |
246 | + EXPECT_CALL(session_container, successor_of(session)). |
247 | + WillOnce(Return(session1)); |
248 | + EXPECT_CALL(session_container, successor_of(session1)). |
249 | + WillOnce(Return(session2)); |
250 | + |
251 | + EXPECT_CALL(session_event_sink, handle_focus_change(session2)); |
252 | + |
253 | + focus_controller.focus_next_session(); |
254 | +} |
255 | + |
256 | +TEST_F(AbstractShell, |
257 | + as_focus_controller_focus_next_session_does_not_focus_any_session_if_no_session_has_surfaces) |
258 | +{ |
259 | + msh::FocusController& focus_controller = shell; |
260 | + auto session = shell.open_session(__LINE__, "XPlane", std::shared_ptr<mf::EventSink>()); |
261 | + auto session1 = shell.open_session(__LINE__, "Surfaceless", std::shared_ptr<mf::EventSink>()); |
262 | + auto surface_id = shell.create_surface(session, ms::a_surface(), nullptr); |
263 | + |
264 | + focus_controller.set_focus_to(session, session->surface(surface_id)); |
265 | + |
266 | + shell.destroy_surface(session, surface_id); |
267 | + |
268 | + EXPECT_CALL(session_container, successor_of(session)). |
269 | + WillOnce(Return(session1)); |
270 | + EXPECT_CALL(session_container, successor_of(session1)). |
271 | + WillOnce(Return(session)); |
272 | + |
273 | + EXPECT_CALL(session_event_sink, handle_no_focus()); |
274 | + |
275 | + focus_controller.focus_next_session(); |
276 | +} |
277 | + |
278 | TEST_F(AbstractShell, modify_surface_with_only_streams_doesnt_call_into_wm) |
279 | { |
280 | std::shared_ptr<ms::Session> session = |
I'm confused.
When I try the scenario in lp:1511798 I don't see an attempt to restore the host config after exiting the client. (But that's what display_ configuration_ reset_when_ application_ exits is supposed to test.)
I need to check what is different between the automated and manual test scenarios.