Mir

Merge lp:~afrantzis/mir/fix-1511798-alternative into lp:mir

Proposed by Alexandros Frantzis
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
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.

To post a comment you must log in.
Revision history for this message
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_configuration_reset_when_application_exits is supposed to test.)

I need to check what is different between the automated and manual test scenarios.

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
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_configuration_reset_when_application_exits is supposed to test.)
>
> I need to check what is different between the automated and manual test
> scenarios.

I understand the difference - AbstractShell::focus_next_session() is selecting the dying surface's titlebar. (And that doesn't exist in the core WM that gets tested.)

I have to think about the right solution here.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

I think the right solution is to move the "session->destroy_surface(surface);" call from AbstractShell::destroy_surface() to <Policy>::handle_delete_surface(). (There are four of these, plus DefaultWindowManager::remove_surface() in playground.)

It seems like a PITA, but this allows the window management policy control over the point at which the surface and decorations are destroyed.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Rejected in favor of the other alternative.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 =

Subscribers

People subscribed via source and target branches