Mir

Merge lp:~raof/mir/notify-shell-of-display-configuration into lp:mir

Proposed by Chris Halse Rogers
Status: Rejected
Rejected by: Chris Halse Rogers
Proposed branch: lp:~raof/mir/notify-shell-of-display-configuration
Merge into: lp:mir
Diff against target: 245 lines (+179/-1)
4 files modified
include/server/mir/shell/display_configuration_controller.h (+17/-0)
src/server/scene/mediating_display_changer.cpp (+16/-1)
src/server/scene/mediating_display_changer.h (+5/-0)
tests/unit-tests/scene/test_mediating_display_changer.cpp (+141/-0)
To merge this branch: bzr merge lp:~raof/mir/notify-shell-of-display-configuration
Reviewer Review Type Date Requested Status
Alan Griffiths Disapprove
Cemil Azizoglu (community) Approve
Daniel van Vugt Abstain
Mir CI Bot continuous-integration Approve
Review via email: mp+305189@code.launchpad.net

Commit message

Add a notification mechanism for display configuration changes.

I noticed that we don't currently have any way to get notified when the display configuration has changed; this is one of the major pieces of awkwardness in our display configuration tests.

This is also going to be awkward for shells. Indeed, adding this is a prerequisite for fixing LP: 1556142.

To post a comment you must log in.
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

"I noticed that we don't currently have any way to get notified when the display configuration has changed; this is one of the major pieces of awkwardness in our display configuration tests."

Not entirely true: I have successfully implemented miral::ActiveOutputsMonitor to provide notifications when the display configuration changes.

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

Apart from the sequencing[*] in MediatingDisplayChanger::apply_config(), how does this improve on implementing DisplayConfigurationReport::new_configuration()?

[*] which is dubious at present and I prefer where you've put it. But that is a different change.

review: Needs Information
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3695
https://mir-jenkins.ubuntu.com/job/mir-ci/1669/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/2090
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/2152
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/2143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial+overlay/2143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=yakkety/2143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=yakkety/2118
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=yakkety/2118/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/2118
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial+overlay/2118/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=yakkety/2118
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=yakkety/2118/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/2118
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/2118/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/2118
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial+overlay/2118/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1669/rebuild

review: Approve (continuous-integration)
Revision history for this message
Chris Halse Rogers (raof) wrote :

Huh. I *guess* you could use the logging interface for detecting display configuration changes.

But I interpret the various mir::report::* interfaces we have as fundamentally debugging aids. In turn, that means that I think we should be able to remove all calls to anything under mir::report:: and still have correct system behaviour.

So I think this improves on implementing DisplayConfigurationReport::new_configuration() in discoverability (Gerry has also been looking for a way to do this, and didn't think to do that), and explicitness.

It's also likely to help preserve the utility of the Reports - if users of Mir start using reports to introspect state like this they need to ensure they wrap the existing report otherwise it becomes useless for reporting.

(I would not object to calling DisplayConfigurationReport::new_configuration() in a wrapper *from* the configured_callback).

Revision history for this message
Chris Halse Rogers (raof) wrote :

I guess that also means that I don't think that reports should be visible to the shell *at all*. If shells want to pipe debug logs elsewhere they can replace the Logger.

Revision history for this message
Chris Halse Rogers (raof) wrote :

Hm.

That being said, since MirAL is the future of the shell-visible Mir API if you've already implemented notification there it may not be worthwhile adding this?

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

The shell (Unity8) is just a client. Why don't we do this via an event using the client API?

There are use cases for normal clients too, like telling a game that its secondary monitor was unplugged.

review: Needs Information
Revision history for this message
Chris Halse Rogers (raof) wrote :

We have existing client API for this, but Unity8 is not a client. It
doesn't have a(n accessible) MirConnection.

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

> Huh. I *guess* you could use the logging interface for detecting display
> configuration changes.

You have that backwards. The reason we have the report interfaces is that there are things that need reports from Mir that are not logging.

I remember long discussions when we introduced reports about why we didn't just log directly. This is an example of something that isn't logging or lttng.

> But I interpret the various mir::report::* interfaces we have as fundamentally
> debugging aids.

While the integrated log/lttng reports are all about recording stuff for later human analysis that isn't the whole of the purpose of providing a way to monitor the system state.

> In turn, that means that I think we should be able to remove
> all calls to anything under mir::report:: and still have correct system
> behaviour.

*mirserver* should behave correctly.

> So I think this improves on implementing
> DisplayConfigurationReport::new_configuration() in discoverability (Gerry has
> also been looking for a way to do this, and didn't think to do that), and
> explicitness.
>
> It's also likely to help preserve the utility of the Reports - if users of Mir
> start using reports to introspect state like this they need to ensure they
> wrap the existing report otherwise it becomes useless for reporting.

That's on my list of things to improve after working downstream for a while. My intention is to provide "add report" - which would also allow both logging and lttng reports to be used.

> (I would not object to calling DisplayConfigurationReport::new_configuration()
> in a wrapper *from* the configured_callback).

I don't see the need to add another layer of indirection.

review: Disapprove
Revision history for this message
Daniel van Vugt (vanvugt) :
review: Abstain
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

I don't really think reports are a good way to monitor system behaviour. But I guess it's pre-existing. I still don't mind landing this and doing away with "reports-as-observers".

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

> I don't really think reports are a good way to monitor system behaviour. But I
> guess it's pre-existing. I still don't mind landing this and doing away with
> "reports-as-observers".

I disapprove of having two ways to do the same job.

I won't block renaming the "report" to an "observer".

review: Disapprove
Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I hear RAOF is working on the alternative approach. Is this branch formally rejected now?

Revision history for this message
Chris Halse Rogers (raof) wrote :

Yeah, let's call it rejected.

Unmerged revisions

3695. By Chris Halse Rogers

...and moke set_configured_callback threadsafe.

3694. By Chris Halse Rogers

More complete and correct set_configured_callback()

3693. By Chris Halse Rogers

Add (start of) a configured-notification to msh::DisplayConfigurationController().

There are all sorts of times that it'd be useful in our test code to know when a configuration
change had occurred, and I'm sure that shells will find it equally useful.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/server/mir/shell/display_configuration_controller.h'
2--- include/server/mir/shell/display_configuration_controller.h 2016-01-29 08:18:22 +0000
3+++ include/server/mir/shell/display_configuration_controller.h 2016-09-08 08:25:23 +0000
4@@ -49,6 +49,23 @@
5 */
6 virtual void set_base_configuration(
7 std::shared_ptr<graphics::DisplayConfiguration> const& conf) = 0;
8+
9+ /**
10+ * Set the display configuration notification delegate
11+ *
12+ * This function is called immediately after a display configuration change has
13+ * completed. This is called for any configuration change, from whatever source.
14+ * This includes configuration changes from the shell, from changes in client
15+ * focus where a client has a display configuration set, and client changes to the base
16+ * display configuration.
17+ *
18+ *
19+ * \param [in] delegate Functor to call after every display configuration change. This
20+ * function is called with a reference to the just-applied display
21+ * configuration.
22+ */
23+ virtual void set_configured_callback(
24+ std::function<void(graphics::DisplayConfiguration const&)> const& delegate) = 0;
25 };
26 }
27 }
28
29=== modified file 'src/server/scene/mediating_display_changer.cpp'
30--- src/server/scene/mediating_display_changer.cpp 2016-08-18 07:30:18 +0000
31+++ src/server/scene/mediating_display_changer.cpp 2016-09-08 08:25:23 +0000
32@@ -124,7 +124,8 @@
33 base_configuration_{display->configuration()},
34 base_configuration_applied{true},
35 region{region},
36- alarm_factory{alarm_factory}
37+ alarm_factory{alarm_factory},
38+ configured_callback{std::make_shared<decltype(configured_callback)::element_type>([](auto&){})}
39 {
40 session_event_handler_register->register_focus_change_handler(
41 [this](std::shared_ptr<ms::Session> const& session)
42@@ -350,6 +351,13 @@
43 }
44 update_input_rectangles(*conf);
45
46+ decltype(configured_callback) configured_callback_copy;
47+ {
48+ std::lock_guard<std::mutex> lock{configured_callback_mutex};
49+ configured_callback_copy = configured_callback;
50+ }
51+ (*configured_callback_copy)(*conf);
52+
53 base_configuration_applied = false;
54 }
55
56@@ -438,3 +446,10 @@
57 });
58 region->set_input_rectangles(rectangles);
59 }
60+
61+void ms::MediatingDisplayChanger::set_configured_callback(
62+ std::function<void(mg::DisplayConfiguration const&)> const& delegate)
63+{
64+ std::lock_guard<std::mutex> lock{configured_callback_mutex};
65+ configured_callback = std::make_shared<decltype(configured_callback)::element_type>(delegate);
66+}
67
68=== modified file 'src/server/scene/mediating_display_changer.h'
69--- src/server/scene/mediating_display_changer.h 2016-08-18 07:30:18 +0000
70+++ src/server/scene/mediating_display_changer.h 2016-09-08 08:25:23 +0000
71@@ -96,6 +96,8 @@
72
73 /* From shell::DisplayConfigurationController */
74 void set_base_configuration(std::shared_ptr<graphics::DisplayConfiguration> const &conf) override;
75+ void set_configured_callback(
76+ std::function<void(graphics::DisplayConfiguration const&)> const& delegate) override;
77
78 private:
79 void focus_change_handler(std::shared_ptr<Session> const& session);
80@@ -127,6 +129,9 @@
81 std::shared_ptr<time::AlarmFactory> const alarm_factory;
82 std::unique_ptr<time::Alarm> preview_configuration_timeout;
83 std::weak_ptr<frontend::Session> currently_previewing_session;
84+
85+ std::mutex configured_callback_mutex;
86+ std::shared_ptr<std::function<void(graphics::DisplayConfiguration const&)>> configured_callback;
87 };
88
89 }
90
91=== modified file 'tests/unit-tests/scene/test_mediating_display_changer.cpp'
92--- tests/unit-tests/scene/test_mediating_display_changer.cpp 2016-08-29 23:00:22 +0000
93+++ tests/unit-tests/scene/test_mediating_display_changer.cpp 2016-09-08 08:25:23 +0000
94@@ -34,6 +34,7 @@
95 #include "mir/test/fake_shared.h"
96 #include "mir/test/display_config_matchers.h"
97 #include "mir/test/doubles/fake_alarm_factory.h"
98+#include "mir/test/signal.h"
99
100 #include <mutex>
101
102@@ -950,3 +951,143 @@
103 changer->configure(session,
104 mt::fake_shared(conf));
105 }
106+
107+TEST_F(MediatingDisplayChangerTest, configured_callback_is_triggered_on_base_configuration_change)
108+{
109+ using namespace testing;
110+ using namespace std::chrono_literals;
111+
112+ auto config = changer->base_configuration();
113+ config->for_each_output(
114+ [](mg::UserDisplayConfigurationOutput& output)
115+ {
116+ output.used = !output.used;
117+ });
118+
119+ bool callback_triggered{false};
120+ changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
121+
122+ changer->set_base_configuration(config);
123+
124+ EXPECT_TRUE(callback_triggered);
125+}
126+
127+TEST_F(MediatingDisplayChangerTest, configured_callback_is_triggered_on_preview_base_configuration)
128+{
129+ using namespace testing;
130+ using namespace std::chrono_literals;
131+
132+ auto config =
133+ changer->base_configuration();
134+ config->for_each_output(
135+ [](mg::UserDisplayConfigurationOutput& output)
136+ {
137+ output.used = !output.used;
138+ });
139+
140+ bool callback_triggered{false};
141+ changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
142+
143+ auto session = std::make_shared<mtd::StubSession>();
144+ changer->preview_base_configuration(session, config, 10s);
145+
146+ EXPECT_TRUE(callback_triggered);
147+}
148+
149+TEST_F(MediatingDisplayChangerTest, configured_callback_is_triggered_on_cancel_base_configuration)
150+{
151+ using namespace testing;
152+ using namespace std::chrono_literals;
153+
154+ auto config =
155+ changer->base_configuration();
156+ config->for_each_output(
157+ [](mg::UserDisplayConfigurationOutput& output)
158+ {
159+ output.used = !output.used;
160+ });
161+
162+ int callback_count{0};
163+ changer->set_configured_callback([&callback_count](auto const&) { callback_count++; });
164+
165+ auto session = std::make_shared<mtd::StubSession>();
166+ changer->preview_base_configuration(session, config, 10min);
167+
168+ EXPECT_THAT(callback_count, Eq(1));
169+
170+ changer->cancel_base_configuration_preview(session);
171+ EXPECT_THAT(callback_count, Eq(2));
172+}
173+
174+TEST_F(MediatingDisplayChangerTest, configured_callback_is_called_when_focusing_a_session_with_attached_config)
175+{
176+ using namespace testing;
177+ auto config =
178+ changer->base_configuration();
179+ config->for_each_output(
180+ [](mg::UserDisplayConfigurationOutput& output)
181+ {
182+ output.used = !output.used;
183+ });
184+
185+ bool callback_triggered{false};
186+ changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
187+
188+ auto session = std::make_shared<mtd::StubSession>();
189+
190+ stub_session_container.insert_session(session);
191+ changer->configure(session, config);
192+
193+ EXPECT_FALSE(callback_triggered);
194+
195+ session_event_sink.handle_focus_change(session);
196+
197+ EXPECT_TRUE(callback_triggered);
198+}
199+
200+TEST_F(MediatingDisplayChangerTest, configured_callback_is_called_when_a_focused_session_changes_config)
201+{
202+ using namespace testing;
203+ auto config =
204+ changer->base_configuration();
205+ config->for_each_output(
206+ [](mg::UserDisplayConfigurationOutput& output)
207+ {
208+ output.used = !output.used;
209+ });
210+
211+ bool callback_triggered{false};
212+ changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
213+
214+ auto session = std::make_shared<mtd::StubSession>();
215+
216+ stub_session_container.insert_session(session);
217+ session_event_sink.handle_focus_change(session);
218+
219+ changer->configure(session, config);
220+
221+ EXPECT_TRUE(callback_triggered);
222+}
223+
224+TEST_F(MediatingDisplayChangerTest, configured_callback_is_not_called_when_an_unfocused_session_changes_config)
225+{
226+ using namespace testing;
227+ auto config =
228+ changer->base_configuration();
229+ config->for_each_output(
230+ [](mg::UserDisplayConfigurationOutput& output)
231+ {
232+ output.used = !output.used;
233+ });
234+
235+ bool callback_triggered{false};
236+ changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
237+
238+ auto session = std::make_shared<mtd::StubSession>();
239+
240+ stub_session_container.insert_session(session);
241+
242+ changer->configure(session, config);
243+
244+ EXPECT_FALSE(callback_triggered);
245+}

Subscribers

People subscribed via source and target branches