Merge lp:~nick-dedekind/qtmir/miral-DisplayConfigurationStorage into lp:qtmir

Proposed by Nick Dedekind
Status: Needs review
Proposed branch: lp:~nick-dedekind/qtmir/miral-DisplayConfigurationStorage
Merge into: lp:qtmir
Prerequisite: lp:~gerboland/qtmir/miral-1.3.1-compat
Diff against target: 377 lines (+182/-33)
6 files modified
src/platforms/mirserver/miral/CMakeLists.txt (+1/-0)
src/platforms/mirserver/miral/display_configuration_storage.h (+59/-0)
src/platforms/mirserver/miral/edid.cpp (+1/-1)
src/platforms/mirserver/miral/persist_display_config.cpp (+101/-29)
src/platforms/mirserver/miral/persist_display_config.h (+7/-2)
src/platforms/mirserver/qmirserver_p.cpp (+13/-1)
To merge this branch: bzr merge lp:~nick-dedekind/qtmir/miral-DisplayConfigurationStorage
Reviewer Review Type Date Requested Status
Unity8 CI Bot (community) continuous-integration Approve
Gerry Boland (community) Needs Fixing
Albert Astals Cid (community) Abstain
Alan Griffiths Pending
Review via email: mp+320368@code.launchpad.net

This proposal supersedes a proposal from 2017-01-25.

Commit message

Added interface for saving/loading display configuration output options.

Description of the change

Pass responsibility for display configuration storage to an overridable interface.

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

+ conf.for_each_output([this, &conf](mg::UserDisplayConfigurationOutput& output) {
...
default_policy.apply_to(conf);

First apply any saved configuration and then overwrite that with the default policy. Is this the right behaviour?

review: Needs Information
Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

- miral::Application applicationFor(qtmir::PromptSession const &promptSession) const;
+ ::miral::Application applicationFor(qtmir::PromptSession const &promptSession) const;

This (and similar changes elsewhere) shouldn't be needed now.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

The target branch has landed, the pre-requisite has been rebased.

review: Needs Resubmitting
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

+++ src/platforms/mirserver/miral/display_configuration_storage.h
Copyright 2017 now

+struct DisplayOutputOptions
To be clear, this struct is filled in to save a subset of options for the display. So one could set the display to not be used, or used, or else leave unset to allow shell to decide?

+++ src/platforms/mirserver/miral/persist_display_config.cpp
+ for(auto iter = output.modes.cbegin(); iter != output.modes.cend(); ++iter, i++) {
+ if ((*iter).size == config.size.value()) {
+ mode_index = i;
break?

+ if (output_index == config.clone_output_index.value()) {
+ output.top_left = find_output.top_left;
break again?

+ if (config.orientation.is_set()) {output.orientation = config.orientation.value(); }
+ if (config.used.is_set()) {output.used = config.used.value(); }
+ if (config.form_factor.is_set()) {output.form_factor = config.form_factor.value(); }
+ if (config.scale.is_set()) {output.scale = config.scale.value(); }

What if these values were set, and then we want to unset them? Does that make sense?

This is all wrapped in a giant try/catch block, why?

void PersistDisplayConfigPolicy::save_config(mg::DisplayConfiguration const& conf)
{
+ if (!storage) return;
better to throw really

Big try/catch block again? Why?

+ // FIXME - output.edid should be std::vector<uint8_t>, not std::vector<uint8_t const>
+ edid.parse_data(reinterpret_cast<std::vector<uint8_t> const&>(output.edid));
IMO std::vector<uint8_t const> is more correct, why would we want the vector contents to be editable? miral::Edid should take the const one instead.

Another break makes sense when you find the clone output indev.

review: Needs Fixing
Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

> +++ src/platforms/mirserver/miral/display_configuration_storage.h
> Copyright 2017 now

Done

>
> +struct DisplayOutputOptions
> To be clear, this struct is filled in to save a subset of options for the
> display. So one could set the display to not be used, or used, or else leave
> unset to allow shell to decide?
>
> +++ src/platforms/mirserver/miral/persist_display_config.cpp
> + for(auto iter = output.modes.cbegin(); iter != output.modes.cend(); ++iter,
> i++) {
> + if ((*iter).size == config.size.value()) {
> + mode_index = i;
> break?
>
> + if (output_index == config.clone_output_index.value()) {
> + output.top_left = find_output.top_left;
> break again?
>
> + if (config.orientation.is_set()) {output.orientation =
> config.orientation.value(); }
> + if (config.used.is_set()) {output.used = config.used.value();
> }
> + if (config.form_factor.is_set()) {output.form_factor =
> config.form_factor.value(); }
> + if (config.scale.is_set()) {output.scale = config.scale.value(); }
>
> What if these values were set, and then we want to unset them? Does that make
> sense?
>
> This is all wrapped in a giant try/catch block, why?
>
>
> void PersistDisplayConfigPolicy::save_config(mg::DisplayConfiguration const&
> conf)
> {
> + if (!storage) return;
> better to throw really
>
> Big try/catch block again? Why?
>
> + // FIXME - output.edid should be std::vector<uint8_t>, not
> std::vector<uint8_t const>
> + edid.parse_data(reinterpret_cast<std::vector<uint8_t> const&>(output.edid));
> IMO std::vector<uint8_t const> is more correct, why would we want the vector
> contents to be editable? miral::Edid should take the const one instead.
>
> Another break makes sense when you find the clone output indev.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

> +++ src/platforms/mirserver/miral/display_configuration_storage.h
> Copyright 2017 now

Done

>
> +struct DisplayOutputOptions
> To be clear, this struct is filled in to save a subset of options for the
> display. So one could set the display to not be used, or used, or else leave
> unset to allow shell to decide?

This is used for both saving & loading options which the shell will need.
For saving, all the options will be set by qtmir from the mir display config and passed to the shell. The shell can decide what it want's to save.
For loading, the shell loads and sets whatever value is found in the saved config (if any). Qtmir will apply everything that has been set to the mir display config.

>
> +++ src/platforms/mirserver/miral/persist_display_config.cpp
> + for(auto iter = output.modes.cbegin(); iter != output.modes.cend(); ++iter,
> i++) {
> + if ((*iter).size == config.size.value()) {
> + mode_index = i;
> break?

Done.

>
> + if (output_index == config.clone_output_index.value()) {
> + output.top_left = find_output.top_left;
> break again?

Can't break out of a for_each_output callback

>
> + if (config.orientation.is_set()) {output.orientation =
> config.orientation.value(); }
> + if (config.used.is_set()) {output.used = config.used.value();
> }
> + if (config.form_factor.is_set()) {output.form_factor =
> config.form_factor.value(); }
> + if (config.scale.is_set()) {output.scale = config.scale.value(); }
>
> What if these values were set, and then we want to unset them? Does that make
> sense?
>
> This is all wrapped in a giant try/catch block, why?

edid.parse_data throws an exception if it encounters bad data.
Would log out something, but this is qtmir::miral so wasn't sure what we do.

>
>
> void PersistDisplayConfigPolicy::save_config(mg::DisplayConfiguration const&
> conf)
> {
> + if (!storage) return;
> better to throw really

done.

>
> Big try/catch block again? Why?

Same again.

>
> + // FIXME - output.edid should be std::vector<uint8_t>, not
> std::vector<uint8_t const>
> + edid.parse_data(reinterpret_cast<std::vector<uint8_t> const&>(output.edid));
> IMO std::vector<uint8_t const> is more correct, why would we want the vector
> contents to be editable? miral::Edid should take the const one instead.

Apparently vector elements can't be const :/ not sure why it's constructable, but it's not usable. Get a compiler error. something to do with the allocator.

>
> Another break makes sense when you find the clone output indev.

Can't break out of a for_each_output callback

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:612
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/501/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/4099/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4127
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3967
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3967/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3967
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3967/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3967
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3967/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3967/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3967
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3967/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3967/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/501/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

> > + if (output_index == config.clone_output_index.value()) {
> > + output.top_left = find_output.top_left;
> > break again?
> Can't break out of a for_each_output callback

You're right, you're in a lambda. You could "return" instead, but that does look confusing in code. Best to leave it.

> > + if (config.orientation.is_set()) {output.orientation =
> > config.orientation.value(); }
> > + if (config.used.is_set()) {output.used =
> config.used.value();
> > }
> > + if (config.form_factor.is_set()) {output.form_factor =
> > config.form_factor.value(); }
> > + if (config.scale.is_set()) {output.scale = config.scale.value(); }
> >
> > What if these values were set, and then we want to unset them? Does that
> make
> > sense?
> >
> > This is all wrapped in a giant try/catch block, why?
>
> edid.parse_data throws an exception if it encounters bad data.
> Would log out something, but this is qtmir::miral so wasn't sure what we do.

Ok, my first instinct is to only to wrap parse_data call. But if the exception throws, then you naturally skip all the config saving bits, which is clean. So ok.

> > + // FIXME - output.edid should be std::vector<uint8_t>, not
> > std::vector<uint8_t const>
> > + edid.parse_data(reinterpret_cast<std::vector<uint8_t>
> const&>(output.edid));
> > IMO std::vector<uint8_t const> is more correct, why would we want the vector
> > contents to be editable? miral::Edid should take the const one instead.
>
> Apparently vector elements can't be const :/ not sure why it's constructable,
> but it's not usable. Get a compiler error. something to do with the allocator.

There is something fishy here. http://en.cppreference.com/w/cpp/container/vector says that the type in a vector (for C++11 and greater) needs to just be Erasable, which const uint8_t should be. But yeah, compiler says no. Better leave as is.

review: Approve
Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

I get this error when using Ninja, can you have a look:

FAILED: src/platforms/mirserver/miral/CMakeFiles/miral-prototypes.dir
/usr/lib/ccache/c++ -DQT_NO_DEBUG -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER -DQT_USING_GL -Isrc/platforms/mirserver/miral -I../src/platforms/mirserver/miral -isystem /usr/include/x86_64-linux-gnu/qt5/QtCore -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem /usr/include/mirserver -isystem /usr/include/mirclient -isystem /usr/include/mircookie -isystem /usr/include/mirplatform -isystem /usr/include/mircommon -isystem /usr/include/uuid -isystem /usr/include/mircore -fPIC -Wall -fno-strict-aliasing -Werror -Wextra -O2 -g -DNDEBUG -std=gnu++14 -MD -MT src/platforms/mirserver/miral/CMakeFiles/miral-prototypes.dir -MF src/platforms/mirserver/miral/CMakeFiles/miral-prototypes.dir/.d -o src/platforms/mirserver/miral/CMakeFiles/miral-prototypes.dir -c /home/gerry/dev/projects/qtmir/miral-DisplayConfigurationStorage/BUILD/src/platforms/mirserver/miral/miral-prototypes_automoc.cpp
Assembler messages:
Fatal error: can't create src/platforms/mirserver/miral/CMakeFiles/miral-prototypes.dir: Is a directory

Revision history for this message
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal

> I get this error when using Ninja, can you have a look:
>
> FAILED: src/platforms/mirserver/miral/CMakeFiles/miral-prototypes.dir
> /usr/lib/ccache/c++ -DQT_NO_DEBUG -DQT_NO_KEYWORDS -DQT_USE_QSTRINGBUILDER
> -DQT_USING_GL -Isrc/platforms/mirserver/miral
> -I../src/platforms/mirserver/miral -isystem /usr/include/x86_64-linux-
> gnu/qt5/QtCore -isystem /usr/include/x86_64-linux-gnu/qt5 -isystem
> /usr/include/mirserver -isystem /usr/include/mirclient -isystem
> /usr/include/mircookie -isystem /usr/include/mirplatform -isystem
> /usr/include/mircommon -isystem /usr/include/uuid -isystem
> /usr/include/mircore -fPIC -Wall -fno-strict-aliasing -Werror -Wextra -O2 -g
> -DNDEBUG -std=gnu++14 -MD -MT src/platforms/mirserver/miral/CMakeFiles
> /miral-prototypes.dir -MF src/platforms/mirserver/miral/CMakeFiles/miral-
> prototypes.dir/.d -o src/platforms/mirserver/miral/CMakeFiles/miral-
> prototypes.dir -c /home/gerry/dev/projects/qtmir/miral-
> DisplayConfigurationStorage/BUILD/src/platforms/mirserver/miral/miral-
> prototypes_automoc.cpp
> Assembler messages:
> Fatal error: can't create src/platforms/mirserver/miral/CMakeFiles/miral-
> prototypes.dir: Is a directory

Not your fault, comes from iteration-0-of-miral-PersistDisplayConfig

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:613
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/537/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4257
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4285
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4119
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4119/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4119
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4119/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4119
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4119/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4119
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4119/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4119
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4119/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4119
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4119/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/537/rebuild

review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal

Text conflict in src/platforms/mirserver/qmirserver_p.cpp
1 conflicts encountered.

Was already top approved.

review: Needs Fixing
Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

> > > + if (output_index == config.clone_output_index.value()) {
> > > + output.top_left = find_output.top_left;
> > > break again?
> > Can't break out of a for_each_output callback
>
> You're right, you're in a lambda. You could "return" instead, but that does
> look confusing in code. Best to leave it.
>
>
> > > + if (config.orientation.is_set()) {output.orientation =
> > > config.orientation.value(); }
> > > + if (config.used.is_set()) {output.used =
> > config.used.value();
> > > }
> > > + if (config.form_factor.is_set()) {output.form_factor =
> > > config.form_factor.value(); }
> > > + if (config.scale.is_set()) {output.scale = config.scale.value(); }
> > >
> > > What if these values were set, and then we want to unset them? Does that
> > make
> > > sense?
> > >
> > > This is all wrapped in a giant try/catch block, why?
> >
> > edid.parse_data throws an exception if it encounters bad data.
> > Would log out something, but this is qtmir::miral so wasn't sure what we do.
>
> Ok, my first instinct is to only to wrap parse_data call. But if the exception
> throws, then you naturally skip all the config saving bits, which is clean. So
> ok.
>
>
> > > + // FIXME - output.edid should be std::vector<uint8_t>, not
> > > std::vector<uint8_t const>
> > > + edid.parse_data(reinterpret_cast<std::vector<uint8_t>
> > const&>(output.edid));
> > > IMO std::vector<uint8_t const> is more correct, why would we want the
> vector
> > > contents to be editable? miral::Edid should take the const one instead.
> >
> > Apparently vector elements can't be const :/ not sure why it's
> constructable,
> > but it's not usable. Get a compiler error. something to do with the
> allocator.
>
> There is something fishy here.
> http://en.cppreference.com/w/cpp/container/vector says that the type in a
> vector (for C++11 and greater) needs to just be Erasable, which const uint8_t
> should be. But yeah, compiler says no. Better leave as is.

"Erasable, but many member functions impose stricter requirements."
Perhaps this is why constructing one is fine in mir but actually using it in our case is where the "Compiler Says No"

Revision history for this message
Nick Dedekind (nick-dedekind) wrote : Posted in a previous version of this proposal

> Text conflict in src/platforms/mirserver/qmirserver_p.cpp
> 1 conflicts encountered.
>
> Was already top approved.

Fixed.

Revision history for this message
Albert Astals Cid (aacid) : Posted in a previous version of this proposal
review: Abstain
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:614
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/574/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4438
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4466
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4297/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/574/rebuild

review: Approve (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:615
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/590/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4553
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4581
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4408
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4408/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4408
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4408/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4408
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4408/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4408
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4408/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4408
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4408/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4408
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4408/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/590/rebuild

review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) :
review: Abstain
Revision history for this message
Gerry Boland (gerboland) wrote :

+++ src/platforms/mirserver/miral/edid.cpp
+ std::ostringstream stringStream;
+ stringStream << "Incorrect EDID structure size {" << data.size() << "}";
+ throw std::runtime_error(stringStream.str());

This would do:
throw std::runtime_error(std::string("Incorrect EDID structure size:") + std::to_string(data.size()));

++ src/platforms/mirserver/miral/persist_display_config.cpp
since you remove the #if MIR_SERVER_VERSION block, please merge the list of mir headers so it is neater.

+++ src/platforms/mirserver/miral/persist_display_config.cpp
Nitpick: space after the "for":
+ for(auto iter = output.modes.cbegin(); iter != output.modes.cend(); ++iter, i++) {

+++ src/platforms/mirserver/qmirserver_p.cpp
Nitpick: please add "// namespace" after the anonymous namespace closing brace

Rest looks good

review: Needs Fixing
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
616. By Nick Dedekind

merged trunk

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

FAILED: Continuous integration, rev:616
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/623/
Executed test runs:
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build/4659/console
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4687
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4510
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4510/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4510
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4510/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4510
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4510/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4510
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4510/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4510
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4510/artifact/output/*zip*/output.zip
    FAILURE: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4510/console

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/623/rebuild

review: Needs Fixing (continuous-integration)
617. By Nick Dedekind

merged trunk

618. By Nick Dedekind

merged with trunk

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> +++ src/platforms/mirserver/miral/edid.cpp
> + std::ostringstream stringStream;
> + stringStream << "Incorrect EDID structure size {" << data.size() <<
> "}";
> + throw std::runtime_error(stringStream.str());
>
> This would do:
> throw std::runtime_error(std::string("Incorrect EDID structure size:") +
> std::to_string(data.size()));
>
>
> ++ src/platforms/mirserver/miral/persist_display_config.cpp
> since you remove the #if MIR_SERVER_VERSION block, please merge the list of
> mir headers so it is neater.
>
> +++ src/platforms/mirserver/miral/persist_display_config.cpp
> Nitpick: space after the "for":
> + for(auto iter = output.modes.cbegin(); iter != output.modes.cend(); ++iter,
> i++) {
>
>
> +++ src/platforms/mirserver/qmirserver_p.cpp
> Nitpick: please add "// namespace" after the anonymous namespace closing brace
>
>
> Rest looks good

Fixed.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:618
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/653/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/4813
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/4841
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4652
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/4652/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4652
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/4652/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4652
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/4652/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4652
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/4652/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4652
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/4652/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4652
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/4652/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-ci/653/rebuild

review: Approve (continuous-integration)

Unmerged revisions

618. By Nick Dedekind

merged with trunk

617. By Nick Dedekind

merged trunk

616. By Nick Dedekind

merged trunk

615. By Nick Dedekind

miral 1.3.1 compat

614. By Nick Dedekind

merged trunk

613. By Nick Dedekind

merged with trunk

612. By Nick Dedekind

more info for identifying a display

611. By Nick Dedekind

print error on failed EDID parse

610. By Nick Dedekind

added check for ouput.connected to load/save config

609. By Nick Dedekind

merged parent

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platforms/mirserver/miral/CMakeLists.txt'
2--- src/platforms/mirserver/miral/CMakeLists.txt 2017-03-15 14:57:23 +0000
3+++ src/platforms/mirserver/miral/CMakeLists.txt 2017-03-31 16:11:02 +0000
4@@ -2,6 +2,7 @@
5
6 add_library(miral-prototypes OBJECT
7 edid.cpp edid.h
8+ display_configuration_storage.h
9 persist_display_config.cpp persist_display_config.h
10 mirbuffer.cpp mirbuffer.h
11 )
12
13=== added file 'src/platforms/mirserver/miral/display_configuration_storage.h'
14--- src/platforms/mirserver/miral/display_configuration_storage.h 1970-01-01 00:00:00 +0000
15+++ src/platforms/mirserver/miral/display_configuration_storage.h 2017-03-31 16:11:02 +0000
16@@ -0,0 +1,59 @@
17+/*
18+ * Copyright © 2016-2017 Canonical Ltd.
19+ *
20+ * This program is free software: you can redistribute it and/or modify it
21+ * under the terms of the GNU General Public License version 3,
22+ * as published by the Free Software Foundation.
23+ *
24+ * This program is distributed in the hope that it will be useful,
25+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
26+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27+ * GNU General Public License for more details.
28+ *
29+ * You should have received a copy of the GNU General Public License
30+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
31+ *
32+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
33+ */
34+
35+#ifndef MIRAL_DISPLAY_CONFIGURATION_STORAGE_H
36+#define MIRAL_DISPLAY_CONFIGURATION_STORAGE_H
37+
38+#include "mir/geometry/rectangle.h"
39+#include "mir/optional_value.h"
40+#include "mir_toolkit/common.h"
41+
42+#include "edid.h"
43+
44+// Prototyping namespace for later incorporation in MirAL
45+namespace miral
46+{
47+
48+struct DisplayId
49+{
50+ Edid edid;
51+ int output_id; // helps to identify a monitor if we have two of the same.
52+};
53+
54+struct DisplayConfigurationOptions
55+{
56+ mir::optional_value<bool> used;
57+ mir::optional_value<uint> clone_output_index;
58+ mir::optional_value<mir::geometry::Size> size;
59+ mir::optional_value<MirOrientation> orientation;
60+ mir::optional_value<MirFormFactor> form_factor;
61+ mir::optional_value<float> scale;
62+};
63+
64+class DisplayConfigurationStorage
65+{
66+public:
67+ virtual ~DisplayConfigurationStorage() = default;
68+
69+ virtual void save(const DisplayId&, const DisplayConfigurationOptions&) = 0;
70+ virtual bool load(const DisplayId&, DisplayConfigurationOptions&) const = 0;
71+};
72+
73+}
74+
75+#endif // MIRAL_DISPLAY_CONFIGURATION_STORAGE_H
76
77=== modified file 'src/platforms/mirserver/miral/edid.cpp'
78--- src/platforms/mirserver/miral/edid.cpp 2017-01-06 11:47:03 +0000
79+++ src/platforms/mirserver/miral/edid.cpp 2017-03-31 16:11:02 +0000
80@@ -25,7 +25,7 @@
81 miral::Edid& miral::Edid::parse_data(std::vector<uint8_t> const& data)
82 {
83 if (data.size() != 128 && data.size() != 256) {
84- throw std::runtime_error("Incorrect EDID structure size");
85+ throw std::runtime_error(std::string("Incorrect EDID structure size:") + std::to_string(data.size()));
86 }
87
88 // check the checksum
89
90=== modified file 'src/platforms/mirserver/miral/persist_display_config.cpp'
91--- src/platforms/mirserver/miral/persist_display_config.cpp 2017-02-02 13:13:39 +0000
92+++ src/platforms/mirserver/miral/persist_display_config.cpp 2017-03-31 16:11:02 +0000
93@@ -17,15 +17,14 @@
94 */
95
96 #include "persist_display_config.h"
97+#include "display_configuration_storage.h"
98+#include "edid.h"
99
100 #include <mir/graphics/display_configuration_policy.h>
101-#include <mir/server.h>
102-#include <mir/version.h>
103-
104-#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 26, 0)
105+#include <mir/graphics/display_configuration.h>
106 #include <mir/graphics/display_configuration_observer.h>
107 #include <mir/observer_registrar.h>
108-#endif
109+#include <mir/server.h>
110
111 namespace mg = mir::graphics;
112
113@@ -33,13 +32,16 @@
114 {
115 struct PersistDisplayConfigPolicy
116 {
117- PersistDisplayConfigPolicy() = default;
118+ PersistDisplayConfigPolicy(std::shared_ptr<miral::DisplayConfigurationStorage> const& storage) :
119+ storage(storage) {}
120 virtual ~PersistDisplayConfigPolicy() = default;
121 PersistDisplayConfigPolicy(PersistDisplayConfigPolicy const&) = delete;
122 auto operator=(PersistDisplayConfigPolicy const&) -> PersistDisplayConfigPolicy& = delete;
123
124 void apply_to(mg::DisplayConfiguration& conf, mg::DisplayConfigurationPolicy& default_policy);
125 void save_config(mg::DisplayConfiguration const& base_conf);
126+
127+ std::shared_ptr<miral::DisplayConfigurationStorage> storage;
128 };
129
130 struct DisplayConfigurationPolicyAdapter : mg::DisplayConfigurationPolicy
131@@ -59,7 +61,6 @@
132 std::shared_ptr<mg::DisplayConfigurationPolicy> const default_policy;
133 };
134
135-#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 26, 0)
136 struct DisplayConfigurationObserver : mg::DisplayConfigurationObserver
137 {
138 void initial_configuration(std::shared_ptr<mg::DisplayConfiguration const> const& /*config*/) override {}
139@@ -74,21 +75,20 @@
140 std::shared_ptr<mg::DisplayConfiguration const> const& /*failed_fallback*/,
141 std::exception const& /*error*/) override {}
142 };
143-#else
144-struct DisplayConfigurationObserver { };
145-#endif
146 }
147
148 struct miral::PersistDisplayConfig::Self : PersistDisplayConfigPolicy, DisplayConfigurationObserver
149 {
150- Self() = default;
151- Self(DisplayConfigurationPolicyWrapper const& custom_wrapper) :
152+ Self(std::shared_ptr<DisplayConfigurationStorage> const& storage) :
153+ PersistDisplayConfigPolicy(storage) {}
154+ Self(std::shared_ptr<DisplayConfigurationStorage> const& storage,
155+ DisplayConfigurationPolicyWrapper const& custom_wrapper) :
156+ PersistDisplayConfigPolicy(storage),
157 custom_wrapper{custom_wrapper} {}
158
159 DisplayConfigurationPolicyWrapper const custom_wrapper =
160 [](const std::shared_ptr<mg::DisplayConfigurationPolicy> &wrapped) { return wrapped; };
161
162-#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 26, 0)
163 void base_configuration_updated(std::shared_ptr<mg::DisplayConfiguration const> const& base_config) override
164 {
165 save_config(*base_config);
166@@ -97,16 +97,16 @@
167 void session_configuration_applied(std::shared_ptr<mir::frontend::Session> const&,
168 std::shared_ptr<mg::DisplayConfiguration> const&){}
169 void session_configuration_removed(std::shared_ptr<mir::frontend::Session> const&) {}
170-#endif
171 };
172
173-miral::PersistDisplayConfig::PersistDisplayConfig() :
174- self{std::make_shared<Self>()}
175+miral::PersistDisplayConfig::PersistDisplayConfig(std::shared_ptr<DisplayConfigurationStorage> const& storage) :
176+ self{std::make_shared<Self>(storage)}
177 {
178 }
179
180-miral::PersistDisplayConfig::PersistDisplayConfig(DisplayConfigurationPolicyWrapper const& custom_wrapper) :
181- self{std::make_shared<Self>(custom_wrapper)}
182+miral::PersistDisplayConfig::PersistDisplayConfig(std::shared_ptr<DisplayConfigurationStorage> const& storage,
183+ DisplayConfigurationPolicyWrapper const& custom_wrapper) :
184+ self{std::make_shared<Self>(storage, custom_wrapper)}
185 {
186 }
187
188@@ -125,27 +125,99 @@
189 return std::make_shared<DisplayConfigurationPolicyAdapter>(self, self->custom_wrapper(wrapped));
190 });
191
192-#if MIR_SERVER_VERSION >= MIR_VERSION_NUMBER(0, 26, 0)
193 server.add_init_callback([this, &server]
194 { server.the_display_configuration_observer_registrar()->register_interest(self); });
195-#else
196- // Up to Mir-0.25 detecting changes to the base display config is only possible client-side
197- // (and gives a different configuration API)
198- // If we decide implementing this is necessary for earlier Mir versions then this is where to plumb it in.
199- (void)&PersistDisplayConfigPolicy::save_config; // Fake "using" the function for now
200-#endif
201 }
202
203 void PersistDisplayConfigPolicy::apply_to(
204 mg::DisplayConfiguration& conf,
205 mg::DisplayConfigurationPolicy& default_policy)
206 {
207- // TODO if the h/w profile (by some definition) has changed, then apply corresponding saved config (if any).
208- // TODO Otherwise...
209 default_policy.apply_to(conf);
210+
211+ if (!storage) {
212+ throw std::runtime_error("No display configuration storage supplied.");
213+ }
214+
215+ conf.for_each_output([this, &conf](mg::UserDisplayConfigurationOutput& output) {
216+ if (!output.connected) return;
217+
218+ try {
219+ miral::DisplayId display_id;
220+ // FIXME - output.edid should be std::vector<uint8_t>, not std::vector<uint8_t const>
221+ display_id.edid.parse_data(reinterpret_cast<std::vector<uint8_t> const&>(output.edid));
222+ display_id.output_id = output.id.as_value();
223+
224+ // TODO if the h/w profile (by some definition) has changed, then apply corresponding saved config (if any).
225+ // TODO Otherwise...
226+
227+ miral::DisplayConfigurationOptions config;
228+ if (storage->load(display_id, config)) {
229+
230+ if (config.size.is_set()) {
231+ int mode_index = output.current_mode_index;
232+ int i = 0;
233+ // Find the mode index which supports the saved size.
234+ for (auto iter = output.modes.cbegin(); iter != output.modes.cend(); ++iter, i++) {
235+ if ((*iter).size == config.size.value()) {
236+ mode_index = i;
237+ break;
238+ }
239+ }
240+ output.current_mode_index = mode_index;
241+ }
242+
243+ uint output_index = 0;
244+ conf.for_each_output([this, &output, config, &output_index](mg::DisplayConfigurationOutput const& find_output) {
245+ if (output_index == config.clone_output_index.value()) {
246+ output.top_left = find_output.top_left;
247+ }
248+ output_index++;
249+ });
250+
251+ if (config.orientation.is_set()) {output.orientation = config.orientation.value(); }
252+ if (config.used.is_set()) {output.used = config.used.value(); }
253+ if (config.form_factor.is_set()) {output.form_factor = config.form_factor.value(); }
254+ if (config.scale.is_set()) {output.scale = config.scale.value(); }
255+ }
256+ } catch (std::runtime_error const& e) {
257+ printf("Failed to parse EDID - %s\n", e.what());
258+ }
259+ });
260 }
261
262-void PersistDisplayConfigPolicy::save_config(mg::DisplayConfiguration const& /*base_conf*/)
263+void PersistDisplayConfigPolicy::save_config(mg::DisplayConfiguration const& conf)
264 {
265- // TODO save display config options against the h/w profile
266+ if (!storage) return;
267+
268+ conf.for_each_output([this, &conf](mg::DisplayConfigurationOutput const& output) {
269+ if (!output.connected) return;
270+
271+ try {
272+ miral::DisplayId display_id;
273+ // FIXME - output.edid should be std::vector<uint8_t>, not std::vector<uint8_t const>
274+ display_id.edid.parse_data(reinterpret_cast<std::vector<uint8_t> const&>(output.edid));
275+ display_id.output_id = output.id.as_value();
276+
277+ miral::DisplayConfigurationOptions config;
278+
279+ uint output_index = 0;
280+ conf.for_each_output([this, output, &config, &output_index](mg::DisplayConfigurationOutput const& find_output) {
281+ if (!config.clone_output_index.is_set() && output.top_left == find_output.top_left) {
282+ config.clone_output_index = output_index;
283+ }
284+ output_index++;
285+ });
286+
287+ config.size = output.extents().size;
288+ config.form_factor = output.form_factor;
289+ config.orientation = output.orientation;
290+ config.scale = output.scale;
291+ config.used = output.used;
292+
293+ storage->save(display_id, config);
294+ } catch (std::runtime_error const& e) {
295+ printf("Failed to parse EDID - %s\n", e.what());
296+ }
297+ });
298 }
299
300=== modified file 'src/platforms/mirserver/miral/persist_display_config.h'
301--- src/platforms/mirserver/miral/persist_display_config.h 2017-01-05 14:36:10 +0000
302+++ src/platforms/mirserver/miral/persist_display_config.h 2017-03-31 16:11:02 +0000
303@@ -27,11 +27,13 @@
304 // Prototyping namespace for later incorporation in MirAL
305 namespace miral
306 {
307+class DisplayConfigurationStorage;
308+
309 /// Restores the saved display configuration and saves changes to the base configuration
310 class PersistDisplayConfig
311 {
312 public:
313- PersistDisplayConfig();
314+ PersistDisplayConfig(std::shared_ptr<DisplayConfigurationStorage> const& storage);
315 ~PersistDisplayConfig();
316 PersistDisplayConfig(PersistDisplayConfig const&);
317 auto operator=(PersistDisplayConfig const&) -> PersistDisplayConfig&;
318@@ -39,7 +41,9 @@
319 // TODO factor this out better
320 using DisplayConfigurationPolicyWrapper =
321 std::function<std::shared_ptr<mir::graphics::DisplayConfigurationPolicy>(const std::shared_ptr<mir::graphics::DisplayConfigurationPolicy> &wrapped)>;
322- PersistDisplayConfig(DisplayConfigurationPolicyWrapper const& custom_wrapper);
323+
324+ PersistDisplayConfig(std::shared_ptr<DisplayConfigurationStorage> const& storage,
325+ DisplayConfigurationPolicyWrapper const& custom_wrapper);
326
327 void operator()(mir::Server& server);
328
329@@ -47,6 +51,7 @@
330 struct Self;
331 std::shared_ptr<Self> self;
332 };
333+
334 }
335
336 #endif //MIRAL_PERSIST_DISPLAY_CONFIG_H
337
338=== modified file 'src/platforms/mirserver/qmirserver_p.cpp'
339--- src/platforms/mirserver/qmirserver_p.cpp 2017-03-28 17:13:24 +0000
340+++ src/platforms/mirserver/qmirserver_p.cpp 2017-03-31 16:11:02 +0000
341@@ -15,6 +15,7 @@
342 */
343
344 #include "qmirserver_p.h"
345+#include "miral/display_configuration_storage.h"
346
347 // local
348 #include "logging.h"
349@@ -42,9 +43,19 @@
350
351 #include <valgrind.h>
352
353+namespace
354+{
355 static int qtmirArgc{1};
356 static const char *qtmirArgv[]{"qtmir"};
357
358+struct DefaultDisplayConfigurationStorage : miral::DisplayConfigurationStorage
359+{
360+ void save(const miral::DisplayId&, const miral::DisplayConfigurationOptions&) override {}
361+
362+ bool load(const miral::DisplayId&, miral::DisplayConfigurationOptions&) const override { return false; }
363+};
364+} // namespace
365+
366 void MirServerThread::run()
367 {
368 auto start_callback = [this]
369@@ -138,7 +149,8 @@
370 addInitCallback,
371 qtmir::SetQtCompositor{screensModel},
372 setTerminator,
373- miral::PersistDisplayConfig{&qtmir::wrapDisplayConfigurationPolicy}
374+ miral::PersistDisplayConfig{std::make_shared<DefaultDisplayConfigurationStorage>(),
375+ &qtmir::wrapDisplayConfigurationPolicy}
376 });
377 }
378

Subscribers

People subscribed via source and target branches