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
=== modified file 'include/server/mir/shell/display_configuration_controller.h'
--- include/server/mir/shell/display_configuration_controller.h 2016-01-29 08:18:22 +0000
+++ include/server/mir/shell/display_configuration_controller.h 2016-09-08 08:25:23 +0000
@@ -49,6 +49,23 @@
49 */49 */
50 virtual void set_base_configuration(50 virtual void set_base_configuration(
51 std::shared_ptr<graphics::DisplayConfiguration> const& conf) = 0;51 std::shared_ptr<graphics::DisplayConfiguration> const& conf) = 0;
52
53 /**
54 * Set the display configuration notification delegate
55 *
56 * This function is called immediately after a display configuration change has
57 * completed. This is called for any configuration change, from whatever source.
58 * This includes configuration changes from the shell, from changes in client
59 * focus where a client has a display configuration set, and client changes to the base
60 * display configuration.
61 *
62 *
63 * \param [in] delegate Functor to call after every display configuration change. This
64 * function is called with a reference to the just-applied display
65 * configuration.
66 */
67 virtual void set_configured_callback(
68 std::function<void(graphics::DisplayConfiguration const&)> const& delegate) = 0;
52};69};
53}70}
54}71}
5572
=== modified file 'src/server/scene/mediating_display_changer.cpp'
--- src/server/scene/mediating_display_changer.cpp 2016-08-18 07:30:18 +0000
+++ src/server/scene/mediating_display_changer.cpp 2016-09-08 08:25:23 +0000
@@ -124,7 +124,8 @@
124 base_configuration_{display->configuration()},124 base_configuration_{display->configuration()},
125 base_configuration_applied{true},125 base_configuration_applied{true},
126 region{region},126 region{region},
127 alarm_factory{alarm_factory}127 alarm_factory{alarm_factory},
128 configured_callback{std::make_shared<decltype(configured_callback)::element_type>([](auto&){})}
128{129{
129 session_event_handler_register->register_focus_change_handler(130 session_event_handler_register->register_focus_change_handler(
130 [this](std::shared_ptr<ms::Session> const& session)131 [this](std::shared_ptr<ms::Session> const& session)
@@ -350,6 +351,13 @@
350 }351 }
351 update_input_rectangles(*conf);352 update_input_rectangles(*conf);
352353
354 decltype(configured_callback) configured_callback_copy;
355 {
356 std::lock_guard<std::mutex> lock{configured_callback_mutex};
357 configured_callback_copy = configured_callback;
358 }
359 (*configured_callback_copy)(*conf);
360
353 base_configuration_applied = false;361 base_configuration_applied = false;
354}362}
355363
@@ -438,3 +446,10 @@
438 });446 });
439 region->set_input_rectangles(rectangles);447 region->set_input_rectangles(rectangles);
440}448}
449
450void ms::MediatingDisplayChanger::set_configured_callback(
451 std::function<void(mg::DisplayConfiguration const&)> const& delegate)
452{
453 std::lock_guard<std::mutex> lock{configured_callback_mutex};
454 configured_callback = std::make_shared<decltype(configured_callback)::element_type>(delegate);
455}
441456
=== modified file 'src/server/scene/mediating_display_changer.h'
--- src/server/scene/mediating_display_changer.h 2016-08-18 07:30:18 +0000
+++ src/server/scene/mediating_display_changer.h 2016-09-08 08:25:23 +0000
@@ -96,6 +96,8 @@
9696
97 /* From shell::DisplayConfigurationController */97 /* From shell::DisplayConfigurationController */
98 void set_base_configuration(std::shared_ptr<graphics::DisplayConfiguration> const &conf) override;98 void set_base_configuration(std::shared_ptr<graphics::DisplayConfiguration> const &conf) override;
99 void set_configured_callback(
100 std::function<void(graphics::DisplayConfiguration const&)> const& delegate) override;
99101
100private:102private:
101 void focus_change_handler(std::shared_ptr<Session> const& session);103 void focus_change_handler(std::shared_ptr<Session> const& session);
@@ -127,6 +129,9 @@
127 std::shared_ptr<time::AlarmFactory> const alarm_factory;129 std::shared_ptr<time::AlarmFactory> const alarm_factory;
128 std::unique_ptr<time::Alarm> preview_configuration_timeout;130 std::unique_ptr<time::Alarm> preview_configuration_timeout;
129 std::weak_ptr<frontend::Session> currently_previewing_session;131 std::weak_ptr<frontend::Session> currently_previewing_session;
132
133 std::mutex configured_callback_mutex;
134 std::shared_ptr<std::function<void(graphics::DisplayConfiguration const&)>> configured_callback;
130};135};
131136
132}137}
133138
=== modified file 'tests/unit-tests/scene/test_mediating_display_changer.cpp'
--- tests/unit-tests/scene/test_mediating_display_changer.cpp 2016-08-29 23:00:22 +0000
+++ tests/unit-tests/scene/test_mediating_display_changer.cpp 2016-09-08 08:25:23 +0000
@@ -34,6 +34,7 @@
34#include "mir/test/fake_shared.h"34#include "mir/test/fake_shared.h"
35#include "mir/test/display_config_matchers.h"35#include "mir/test/display_config_matchers.h"
36#include "mir/test/doubles/fake_alarm_factory.h"36#include "mir/test/doubles/fake_alarm_factory.h"
37#include "mir/test/signal.h"
3738
38#include <mutex>39#include <mutex>
3940
@@ -950,3 +951,143 @@
950 changer->configure(session,951 changer->configure(session,
951 mt::fake_shared(conf));952 mt::fake_shared(conf));
952}953}
954
955TEST_F(MediatingDisplayChangerTest, configured_callback_is_triggered_on_base_configuration_change)
956{
957 using namespace testing;
958 using namespace std::chrono_literals;
959
960 auto config = changer->base_configuration();
961 config->for_each_output(
962 [](mg::UserDisplayConfigurationOutput& output)
963 {
964 output.used = !output.used;
965 });
966
967 bool callback_triggered{false};
968 changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
969
970 changer->set_base_configuration(config);
971
972 EXPECT_TRUE(callback_triggered);
973}
974
975TEST_F(MediatingDisplayChangerTest, configured_callback_is_triggered_on_preview_base_configuration)
976{
977 using namespace testing;
978 using namespace std::chrono_literals;
979
980 auto config =
981 changer->base_configuration();
982 config->for_each_output(
983 [](mg::UserDisplayConfigurationOutput& output)
984 {
985 output.used = !output.used;
986 });
987
988 bool callback_triggered{false};
989 changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
990
991 auto session = std::make_shared<mtd::StubSession>();
992 changer->preview_base_configuration(session, config, 10s);
993
994 EXPECT_TRUE(callback_triggered);
995}
996
997TEST_F(MediatingDisplayChangerTest, configured_callback_is_triggered_on_cancel_base_configuration)
998{
999 using namespace testing;
1000 using namespace std::chrono_literals;
1001
1002 auto config =
1003 changer->base_configuration();
1004 config->for_each_output(
1005 [](mg::UserDisplayConfigurationOutput& output)
1006 {
1007 output.used = !output.used;
1008 });
1009
1010 int callback_count{0};
1011 changer->set_configured_callback([&callback_count](auto const&) { callback_count++; });
1012
1013 auto session = std::make_shared<mtd::StubSession>();
1014 changer->preview_base_configuration(session, config, 10min);
1015
1016 EXPECT_THAT(callback_count, Eq(1));
1017
1018 changer->cancel_base_configuration_preview(session);
1019 EXPECT_THAT(callback_count, Eq(2));
1020}
1021
1022TEST_F(MediatingDisplayChangerTest, configured_callback_is_called_when_focusing_a_session_with_attached_config)
1023{
1024 using namespace testing;
1025 auto config =
1026 changer->base_configuration();
1027 config->for_each_output(
1028 [](mg::UserDisplayConfigurationOutput& output)
1029 {
1030 output.used = !output.used;
1031 });
1032
1033 bool callback_triggered{false};
1034 changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
1035
1036 auto session = std::make_shared<mtd::StubSession>();
1037
1038 stub_session_container.insert_session(session);
1039 changer->configure(session, config);
1040
1041 EXPECT_FALSE(callback_triggered);
1042
1043 session_event_sink.handle_focus_change(session);
1044
1045 EXPECT_TRUE(callback_triggered);
1046}
1047
1048TEST_F(MediatingDisplayChangerTest, configured_callback_is_called_when_a_focused_session_changes_config)
1049{
1050 using namespace testing;
1051 auto config =
1052 changer->base_configuration();
1053 config->for_each_output(
1054 [](mg::UserDisplayConfigurationOutput& output)
1055 {
1056 output.used = !output.used;
1057 });
1058
1059 bool callback_triggered{false};
1060 changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
1061
1062 auto session = std::make_shared<mtd::StubSession>();
1063
1064 stub_session_container.insert_session(session);
1065 session_event_sink.handle_focus_change(session);
1066
1067 changer->configure(session, config);
1068
1069 EXPECT_TRUE(callback_triggered);
1070}
1071
1072TEST_F(MediatingDisplayChangerTest, configured_callback_is_not_called_when_an_unfocused_session_changes_config)
1073{
1074 using namespace testing;
1075 auto config =
1076 changer->base_configuration();
1077 config->for_each_output(
1078 [](mg::UserDisplayConfigurationOutput& output)
1079 {
1080 output.used = !output.used;
1081 });
1082
1083 bool callback_triggered{false};
1084 changer->set_configured_callback([&callback_triggered](auto const&) { callback_triggered = true; });
1085
1086 auto session = std::make_shared<mtd::StubSession>();
1087
1088 stub_session_container.insert_session(session);
1089
1090 changer->configure(session, config);
1091
1092 EXPECT_FALSE(callback_triggered);
1093}

Subscribers

People subscribed via source and target branches