Mir

Merge lp:~raof/mir/new-display-api into lp:mir

Proposed by Chris Halse Rogers on 2016-02-24
Status: Merged
Approved by: Alexandros Frantzis on 2016-02-26
Approved revision: 3375
Merged at revision: 3343
Proposed branch: lp:~raof/mir/new-display-api
Merge into: lp:mir
Diff against target: 2114 lines (+1638/-42)
19 files modified
include/client/mir_toolkit/client_types.h (+35/-0)
include/client/mir_toolkit/mir_client_library.h (+1/-0)
include/client/mir_toolkit/mir_connection.h (+15/-1)
include/client/mir_toolkit/mir_display_configuration.h (+360/-0)
include/test/mir/test/display_config_matchers.h (+9/-0)
include/test/mir/test/doubles/stub_display_configuration.h (+4/-0)
src/client/CMakeLists.txt (+2/-0)
src/client/display_configuration.cpp (+29/-15)
src/client/display_configuration.h (+12/-2)
src/client/display_configuration_api.cpp (+295/-0)
src/client/mir_connection.cpp (+5/-0)
src/client/mir_connection.h (+2/-0)
src/client/mir_connection_api.cpp (+14/-0)
src/client/symbols.map (+33/-0)
tests/acceptance-tests/CMakeLists.txt (+1/-0)
tests/acceptance-tests/test_display_configuration.cpp (+15/-15)
tests/acceptance-tests/test_new_display_configuration.cpp (+671/-0)
tests/mir_test/display_config_matchers.cpp (+97/-0)
tests/mir_test_doubles/stub_display_configuration.cpp (+38/-9)
To merge this branch: bzr merge lp:~raof/mir/new-display-api
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration 2016-02-24 Approve on 2016-02-26
Alexandros Frantzis (community) 2016-02-24 Approve on 2016-02-26
Alan Griffiths 2016-02-24 Approve on 2016-02-26
Andreas Pokorny (community) Approve on 2016-02-25
Kevin DuBois (community) 2016-02-24 Approve on 2016-02-24
Cemil Azizoglu (community) 2016-02-24 Approve on 2016-02-24
PS Jenkins bot continuous-integration 2016-02-24 Needs Fixing on 2016-02-24
Review via email: mp+286975@code.launchpad.net

This proposal supersedes a proposal from 2016-02-18.

Commit Message

New, extensible, display and enumeration API.

Hide all the structs behind the API so we can extend them with all the extra information - scale, form factor, etc - that QtMir would like to have.

This currently does not have any form of configuration setting interface, as that's not
needed for QtMir's immediate needs.

Description of the Change

I've stripped all the setters out of this; since we're implementing a new API I think it's the right time to look at doing something about https://docs.google.com/document/d/1wpoHVYdPZGthN2WS8oDvhRlpyuUqrizK1C4quE4XwMk , but that's likely to be more contentious and take a bit more work.

So just do the bits that QtMir needs now, and add the setters in a follow up.

To post a comment you must log in.
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

A first pass at the API:

> MirDisplayConfig* mir_connection_create_display_configuration()
> MirDisplayConfiguration* mir_connection_create_display_config()

The naming is confusing due to the mismatch of configuration vs config, especially given that other new API functions use mir_display_config (e.g. mir_display_config_release). Not sure what a nice solution would be, though, given our existing API.

> MirOutputConnection mir_output_is_connected(MirOutput const* output);

The object_is_X naming usually implies a boolean return value, but here we get an enum with three values.

> int mir_output_physical_width_mm(MirOutput const* output);
> int mir_output_physical_height_mm(MirOutput const* output);

Should be mir_output_get_physical_*_mm for consistency.

> MirExtent const* mir_output_mode_get_resolution(MirOutputMode const* mode);

Perhaps we should have separate functions to get width and height. It's more consistent with other functions in the new API and also avoids the need for the non-opaque MirExtent.

review: Needs Fixing
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3327
https://mir-jenkins.ubuntu.com/job/mir-ci/298/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build/86
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/92
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/88
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/88
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/88
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/88/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/88
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/88/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/88
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/88/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/88
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/88/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

Fixed the things that can be fixed.

mir_connection_create_display_config()/mir_connection_create_display_configuration() isn't one of those things, unless we go back on the “no #define-time magic” we decided in Austin ☺.

Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:3328
https://mir-jenkins.ubuntu.com/job/mir-ci/299/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build/87/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/93
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/89
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/89
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/89
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/89/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/89
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/89/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/89
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/89/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/89/console

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

review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3329
https://mir-jenkins.ubuntu.com/job/mir-ci/300/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build/88
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/94
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/90
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/90
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/90
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/90/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/90
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/90/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/90
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/90/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/90
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/90/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3327
http://jenkins.qa.ubuntu.com/job/mir-ci/6285/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5911
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4818
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5867
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/435
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/609
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/609/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/609
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/609/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5864
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5864/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8256
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27576
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/431
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/431/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/284
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27577

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6285/rebuild

review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3329
http://jenkins.qa.ubuntu.com/job/mir-ci/6287/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5914
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4821
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5870
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/437
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/611
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/611/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/611
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/611/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5867
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5867/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8259
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27580
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/433
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/433/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/286
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27585

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6287/rebuild

review: Approve (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3331
https://mir-jenkins.ubuntu.com/job/mir-ci/306/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build/95
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/101
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/97
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/97
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/97
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/97/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/97
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/97/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/97
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/97/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/97
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/97/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3331
http://jenkins.qa.ubuntu.com/job/mir-ci/6294/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5923
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4830
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5879
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/443
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/618
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/618/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/618
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/618/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5876
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5876/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8268
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27612
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/439
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/439/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/292
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27613

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6294/rebuild

review: Approve (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3332
https://mir-jenkins.ubuntu.com/job/mir-ci/307/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build/96
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/102
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/98
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/98
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/98
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=amd64,compiler=gcc,platform=mesa,release=xenial/98/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/98
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/98/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/98
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/98/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/98
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-advanced/arch=i386,compiler=gcc,platform=mesa,release=xenial/98/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3332
http://jenkins.qa.ubuntu.com/job/mir-ci/6295/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5924
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4831
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5880
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/444
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/619
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/619/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/619
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/619/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5877
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5877/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8269
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27614
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/440
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/440/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/293
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27615

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6295/rebuild

review: Approve (continuous-integration)
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

discussion/planning:
Should we remove the MirWaitHandles? (https://code.launchpad.net/~kdub/mir/finish-presentation-chain/+merge/285720/comments/728846)

clarifying comment needed:
+int mir_display_config_get_num_outputs(MirDisplayConfig const* config);
Is this the number of active outputs? (in light of mir_display_config_get_max_simultaneous_outputs) or the the number of enabled outputs?

do we need two functions here:
+MirOutput const* mir_display_config_get_output(MirDisplayConfig const* config, size_t index);
+MirOutput* mir_display_config_get_mutable_output(MirDisplayConfig* config, size_t index);
I guess I'd prefer just having:
+MirOutput* mir_display_config_get_output(MirDisplayConfig const* config, size_t index);
In the name of one less function to support.

clarifying content needed:
After reading for a while, I made the connection that MirOutputMode was formerly the list of resolution modes... perhaps MirOutputResolution would have helped make that mental connection quicker.

clarifying content needed:
void mir_output_set_position(MirOutput* output, int x, int y);
the comment says the top-left corner, but in light of rotation, not sure if the corner rotates or not when orientation is applied.

review: Needs Information
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3333
http://jenkins.qa.ubuntu.com/job/mir-ci/6308/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5946
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4853
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5902
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/452
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/632
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/632/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/632
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/632/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5899
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5899/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8287
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27688
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/448
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/448/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/301
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27690

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6308/rebuild

review: Approve (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3349
https://mir-jenkins.ubuntu.com/job/mir-ci/335/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/125
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/137
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/133
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/133
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/130
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/130/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/130
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/130/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/130
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/130/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/130
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/130/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3349
http://jenkins.qa.ubuntu.com/job/mir-ci/6324/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5970
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4877
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5926
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/457
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/648
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/648/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/648
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/648/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5923
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5923/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8304
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27731
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/453
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/453/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/306
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27733

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6324/rebuild

review: Approve (continuous-integration)
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

I've stripped all the setters out of this; since we're implementing a new API I think it's the right time to look at doing something about https://docs.google.com/document/d/1wpoHVYdPZGthN2WS8oDvhRlpyuUqrizK1C4quE4XwMk , but that's likely to be more contentious and take a bit more work.

So just do the bits that QtMir needs now, and add the setters in a follow up.

Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3350
https://mir-jenkins.ubuntu.com/job/mir-ci/337/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/127
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/139
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/135
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/135
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/132
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/132/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/132
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/132/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/132
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/132/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/132
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/132/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3350
http://jenkins.qa.ubuntu.com/job/mir-ci/6327/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/5976
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4883
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5932
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/460
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/651
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/651/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/651
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/651/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5929
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5929/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8310
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27752
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/456
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/456/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/309
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27754

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6327/rebuild

review: Approve (continuous-integration)
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

Cursory review:

40 + * \deprecated Use mir_connection_create_display_configuration() instead.
41 +

Why not mark the function with '__attribute__ ((deprecated))'?

-------------------------------------------------------------------

57 +MirDisplayConfig* mir_connection_create_display_configuration(MirConnection* connection);
58

We are not really creating it, are we? How about mir_connection_get_current_display_configuration() in tandem with mir_output_get_current_mode()?

-------------------------------------------------------------------

124 +int mir_display_config_get_max_simultaneous_outputs(MirDisplayConfig const* config);

Why do we need the config arg here? Also, what does knowing this number give you?

-------------------------------------------------------------------

129 + * This returns the total number of outputs the system has.

should read

129 + * This returns the total number of outputs the system has, matching this configuration.

review: Needs Fixing
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

> Cursory review:
>
> 40 + * \deprecated Use mir_connection_create_display_configuration()
> instead.
> 41 +
>
> Why not mark the function with '__attribute__ ((deprecated))'?

Because that immediately causes all of our current users (including our examples, and the nested server) to fail to build.

I'm following up with changing these in-Mir usages, and I'll update our downstreams, but I didn't immediately force the issue so as to make it easier to break up into reviewable chunks.

>
> -------------------------------------------------------------------
>
> 57 +MirDisplayConfig*
> mir_connection_create_display_configuration(MirConnection* connection);
> 58
>
> We are not really creating it, are we? How about
> mir_connection_get_current_display_configuration() in tandem with
> mir_output_get_current_mode()?
>

This matches the current naming, and - in contrast to mir_output_get_current_mode() - we *are* allocating something that requires cleanup later.

I don't mind renaming, but maybe I'll wait for a second opinion :)

> -------------------------------------------------------------------
>
> 124 +int mir_display_config_get_max_simultaneous_outputs(MirDisplayConfig
> const* config);
>
> Why do we need the config arg here? Also, what does knowing this number give
> you?
>

It's something exposed by our current API, and it can be used by clients to pre-reject obviously invalid setups. For example, many laptops used to have two external output ports and their internal displays, but their GPUs could only drive two outputs at once. Knowing mir_display_get_max_simultaneous_outputs(config) == 2 a configuration client can disallow trying to enable the internal panel *and* both external displays.

We need the config arg here for two reasons: (a) as an implementation detail this is stored in the configuration, and (b) on the conceptual level it can change over time, so it's tied to a particular configuration snapshot.

> -------------------------------------------------------------------
>
> 129 + * This returns the total number of outputs the system has.
>
> should read
>
> 129 + * This returns the total number of outputs the system has, matching
> this configuration.

Hm, that seems confusing to me. What does “matching” mean in this case? We're not doing any filtering here; this *is* the total number of outputs the system had, as of the call to mir_connection_create_display_configuration().

Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

Looks good overall.

A few points for discussion:

+ MirDisplayConfig* mir_connection_create_display_configuration(MirConnection* connection);

DisplayConfig/display_configuration vs DisplayConfiguration/display_config still bugs me. Some day...

+int mir_output_get_num_output_formats(MirOutput const* output)
+ MirPixelFormat mir_output_get_format(MirOutput const* output, size_t index);
...

More consistent as:

mir_output_get_num_pixel_formats()
mir_output_get_pixel_format()
mir_output_set_pixel_format()

+ * \note This may be removed in future, in favour of passing the MirOutput* directly to such APIs.

I don't think this note is useful for a user of the API at the moment.

+ MirDisplayOutputType mir_output_get_type(MirOutput const* output);

We should provide a new type MirOutputType for API consistency.

+typedef enum
+{
+ mir_output_disconnected = 0,
+ mir_output_connected,
+ mir_output_connection_unknown
+} MirOutputConnection;

A more verbose, but also more consistent alternative:

mir_output_connection_state_disconnected
mir_output_connection_state_connected
mir_output_connection_state_unknown
MirOutputConnectionState

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

+ return *reinterpret_cast<std::shared_ptr<mcl::DisplayConfiguration::Config>*>(config);

Ugh!!

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

Minor edits, consistency fixes and musings:

+ * \note This may be removed in future, in favour of passing the MirOutput* directly to such APIs.

Not useful API documentation. Possibly a TODO?

~~~~

+ * Get the number of pixel formats supported by this output
...
+int mir_output_get_num_output_formats(MirOutput const* output);

s/output_formats/formats/

(to match mir_output_get_format())

~~~~

+int mir_output_get_position_x(MirOutput const* output);
...

I know we aim for opaque types, but I wonder if this would be easier to use:

MirRectangle mir_output_get_position(MirOutput const* output);

Also, it is far from clear that this API is tested (the only use of this function I see is in tests/mir_test/display_config_matchers.cpp).

~~~~

+typedef enum
+{
+ mir_output_disconnected = 0,
+ mir_output_connected,
+ mir_output_connection_unknown
+} MirOutputConnection;

Possibly better in include/client/mir_toolkit/client_types.h?

Also, we have tag names on our other typedef'd enums so, be consistent.

review: Needs Fixing
Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

LGTM

review: Approve
Chris Halse Rogers (raof) wrote : Posted in a previous version of this proposal

> + return *reinterpret_cast<std::shared_ptr<mcl::DisplayConfiguration::Config>*
> >(config);
>
> Ugh!!

Yeah. It goes away in the followup MP :).

> +int mir_output_get_position_x(MirOutput const* output);
> ...
>
> I know we aim for opaque types, but I wonder if this would be easier to use:
>
> MirRectangle mir_output_get_position(MirOutput const* output);
>
> Also, it is far from clear that this API is tested (the only use of this
> function I see is in tests/mir_test/display_config_matchers.cpp).

Hah! I originally added a MirExtent struct (MirRectangle isn't quite what we want, as that has width/height) to do this and Alexandros asked to change it to position_x / position_y.

I'll let you fight that out and implement the result ☺.

Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3354
https://mir-jenkins.ubuntu.com/job/mir-ci/359/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/151
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/164
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/160
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/160
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/156
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/156/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/156
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/156/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/156
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/156/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/156
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/156/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:3354
http://jenkins.qa.ubuntu.com/job/mir-ci/6352/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-android-vivid-i386-build/6004
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-clang-vivid-amd64-build/4911
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-vivid-touch/5960
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-xenial-touch/473/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/676
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-amd64-ci/676/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/676
        deb: http://jenkins.qa.ubuntu.com/job/mir-xenial-i386-ci/676/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5957
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-vivid-armhf/5957/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-touch/8331
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27815
    SUCCESS: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/469
        deb: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-builder-xenial-armhf/469/artifact/work/output/*zip*/output.zip
    FAILURE: http://jenkins.qa.ubuntu.com/job/mir-mediumtests-runner-xenial-touch/322/console
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/27816

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/mir-ci/6352/rebuild

review: Approve (continuous-integration)
Alan Griffiths (alan-griffiths) wrote : Posted in a previous version of this proposal

> > + return
> *reinterpret_cast<std::shared_ptr<mcl::DisplayConfiguration::Config>*
> > >(config);
> >
> > Ugh!!
>
> Yeah. It goes away in the followup MP :).

Are all the varied casting ugliness bits going away?

> > +int mir_output_get_position_x(MirOutput const* output);
> > ...
> >
> > I know we aim for opaque types, but I wonder if this would be easier to use:
> >
> > MirRectangle mir_output_get_position(MirOutput const* output);
> >
> > Also, it is far from clear that this API is tested (the only use of this
> > function I see is in tests/mir_test/display_config_matchers.cpp).
>
> Hah! I originally added a MirExtent struct (MirRectangle isn't quite what we
> want, as that has width/height) to do this and Alexandros asked to change it
> to position_x / position_y.
>
> I'll let you fight that out and implement the result ☺.

Not sure that's an effective strategy - you could wait a long time for us to generate the interest needed for a fight. ;)

MirRectangle has a set of members that are unlikely to change. MirExtent on the other hand doesn't have quite as fixed a meaning. (From the name I'd assume it was much the same as MirRectangle - what data members did you propose?)

If you don't like MirRectangle how about MirPosition/MirPoint?

review: Needs Information
Alexandros Frantzis (afrantzis) wrote : Posted in a previous version of this proposal

Pasting my argument for having separate function, from the old MP:

> Perhaps we should have separate functions to get width and height. It's more consistent with other > functions in the new API and also avoids the need for the non-opaque MirExtent.

Cemil Azizoglu (cemil-azizoglu) wrote : Posted in a previous version of this proposal

> Pasting my argument for having separate function, from the old MP:
>
> > Perhaps we should have separate functions to get width and height. It's more
> consistent with other > functions in the new API and also avoids the need for
> the non-opaque MirExtent.

Yes there are other APIs that use *_x(), *_y(). Although, I like the extents/rectangle/point idea, I vote for consistency at this point.

Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

needs fixing:
mir_output_set_orientation is still around in comment and has an implementation, but is not in a header. Should those be removed, or the header define be added for this iteration?
other than that, lgtm

non-blocking trivialities:

Might be helpful to copy this line:
+ * Output orientation, as set by mir_output_set_orientation(), changes the orientation of the output rectangle
+ * in virtual display space, but does not change its top-left corner.
to the get_width/get_height functions.

+ * \pre 0 ≤ index < mir_output_get_num_modes(output)
prefer <= for C api documentation.

+ * This can be used to refer to the output in other APIs, such as
in other parts of the API?

review: Needs Fixing
Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3369
https://mir-jenkins.ubuntu.com/job/mir-ci/374/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/166
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/179
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/175
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/175
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/171
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/171/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/171
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/171/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/171
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/171/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/171
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/171/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
lp:~raof/mir/new-display-api updated on 2016-02-24
3370. By Chris Halse Rogers on 2016-02-24

Appease the almighty Clang harder

Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3370
https://mir-jenkins.ubuntu.com/job/mir-ci/379/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/171
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/184
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/180
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/180
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/176
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/176/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/176
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/176/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/176
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/176/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/176
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/176/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Andreas Pokorny (andreas-pokorny) wrote :

void mir_output_set_current_mode(MirOutput* client_output, MirOutputMode const* mode)
+{
+ auto output = client_to_output(client_output);
+
+ auto internal_mode = reinterpret_cast<MirDisplayMode const*>(mode);
+ ptrdiff_t offset = internal_mode - output->modes;
+ int index = offset / sizeof(MirDisplayMode);
+
+ mir::require(index >= 0);
+ mir::require(index < static_cast<int>(output->num_modes));
+
+ output->current_mode = static_cast<uint32_t>(index);
+}

I believe the offset / sizeof() is wrong and should be / could be:

void mir_output_set_current_mode(MirOutput* client_output, MirOutputMode const* mode)
+{
+ auto output = client_to_output(client_output);
+
+ auto index = std::distance(output->modes, reinterpret_cast<MirDisplayMode const*>(mode));
+
+ mir::require(index >= 0);
+ mir::require(index < static_cast<int>(output->num_modes));
+
+ output->current_mode = static_cast<uint32_t>(index);
+}

nits:
----

There are various longer than 80 columns in the new mirclient display config header and client_to_config is beyond 125 columns

-----

+1198 The new test cases could get an updated year/author info.

review: Needs Fixing
Cemil Azizoglu (cemil-azizoglu) wrote :

LGTM

review: Approve
Kevin DuBois (kdub) wrote :

ascii mafia approved ^_^

review: Approve
lp:~raof/mir/new-display-api updated on 2016-02-24
3371. By Chris Halse Rogers on 2016-02-24

Supplicants for the almighty clang must be consistent.

3372. By Chris Halse Rogers on 2016-02-24

Use std::distance instead of open-coding it.

3373. By Chris Halse Rogers on 2016-02-24

Update copyright on new tests

3374. By Chris Halse Rogers on 2016-02-24

Wrap header at 80 cols

Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3374
https://mir-jenkins.ubuntu.com/job/mir-ci/393/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/186
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/203
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/199
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/199
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/191
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/191/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/191
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/191/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/191
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/191/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/191
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/191/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Andreas Pokorny (andreas-pokorny) wrote :

looks good

review: Approve
Alan Griffiths (alan-griffiths) wrote :

StubDisplayConfig::StubDisplayConfig now creates one card (not one card per output). That seems reasonable, but is that part of the new API?

Alan Griffiths (alan-griffiths) wrote :

The doxygen markup is seriously b. E.g.

+ * \note The MirOutput handle is only valid while \param config is valid.

The \param tag is for documenting a parameter, not referring to it in the note text. The result looks like:

Note
    The MirOutput handle is only valid while

Parameters
    config is valid.

In addition, for the functions to appear in the "MIR graphics tools API" documentation module the definitions need to be enclosed in:

/**
 * \addtogroup mir_toolkit
 * @{
 */
...
/**@}*/

Please run $ make doc && firefox doc/html/group__mir__toolkit.html and check the results!

review: Needs Fixing
Chris Halse Rogers (raof) wrote :

> StubDisplayConfig::StubDisplayConfig now creates one card (not one card per
> output). That seems reasonable, but is that part of the new API?

Kind of; the new API has no notion of cards. This is reasonable because none of our existing backends can handle multiple cards, and once we *do* support multiple cards the existing API we have is ill-suited to handling them (for example, you can have an output connected to more than one card).

Urgh. I did briefly check the documentation, but didn't notice that. I'm clearly misrememdering the doxygen markup to reference a function argument...

Chris Halse Rogers (raof) wrote :

Ok. That's not formatted *quite* how I want it, but it's at least not borken!

lp:~raof/mir/new-display-api updated on 2016-02-26
3375. By Chris Halse Rogers on 2016-02-26

Fixup doxygen

Thanks, Alan!

Mir CI Bot (mir-ci-bot) wrote :

PASSED: Continuous integration, rev:3375
https://mir-jenkins.ubuntu.com/job/mir-ci/410/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/211
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/235
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/227
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/227
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/218
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/218/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/218
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/218/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/218
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/218/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/218
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/218/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/218
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/218/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
Alan Griffiths (alan-griffiths) wrote :

LGTM

review: Approve
Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve
Mir CI Bot (mir-ci-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/client/mir_toolkit/client_types.h'
2--- include/client/mir_toolkit/client_types.h 2016-01-29 08:18:22 +0000
3+++ include/client/mir_toolkit/client_types.h 2016-02-26 07:01:49 +0000
4@@ -45,6 +45,15 @@
5 typedef struct MirBufferStream MirBufferStream;
6 typedef struct MirPersistentId MirPersistentId;
7 typedef struct MirBlob MirBlob;
8+typedef struct MirDisplayConfig MirDisplayConfig;
9+
10+/**
11+ * Descriptor for an output connection.
12+ *
13+ * Each MirOutput corresponds to a video output. This may be a physical connection on the system,
14+ * like HDMI or DisplayPort, or may be a virtual output such as a remote display or screencast display.
15+ */
16+typedef struct MirOutput MirOutput;
17
18 /**
19 * Returned by asynchronous functions. Must not be free'd by
20@@ -272,6 +281,32 @@
21 mir_display_output_type_edp
22 } MirDisplayOutputType;
23
24+typedef enum MirOutputType
25+{
26+ mir_output_type_unknown,
27+ mir_output_type_vga,
28+ mir_output_type_dvii,
29+ mir_output_type_dvid,
30+ mir_output_type_dvia,
31+ mir_output_type_composite,
32+ mir_output_type_svideo,
33+ mir_output_type_lvds,
34+ mir_output_type_component,
35+ mir_output_type_ninepindin,
36+ mir_output_type_displayport,
37+ mir_output_type_hdmia,
38+ mir_output_type_hdmib,
39+ mir_output_type_tv,
40+ mir_output_type_edp
41+} MirOutputType;
42+
43+typedef enum MirOutputConnectionState
44+{
45+ mir_output_connection_state_disconnected = 0,
46+ mir_output_connection_state_connected,
47+ mir_output_connection_state_unknown
48+} MirOutputConnectionState;
49+
50 typedef struct MirDisplayMode
51 {
52 uint32_t vertical_resolution;
53
54=== modified file 'include/client/mir_toolkit/mir_client_library.h'
55--- include/client/mir_toolkit/mir_client_library.h 2016-01-22 05:26:25 +0000
56+++ include/client/mir_toolkit/mir_client_library.h 2016-02-26 07:01:49 +0000
57@@ -26,5 +26,6 @@
58 #include <mir_toolkit/mir_platform_message.h>
59 #include <mir_toolkit/cursors.h>
60 #include <mir_toolkit/mir_cookie.h>
61+#include <mir_toolkit/mir_display_configuration.h>
62
63 #endif /* MIR_CLIENT_LIBRARY_H */
64
65=== modified file 'include/client/mir_toolkit/mir_connection.h'
66--- include/client/mir_toolkit/mir_connection.h 2016-01-29 08:18:22 +0000
67+++ include/client/mir_toolkit/mir_connection.h 2016-02-26 07:01:49 +0000
68@@ -145,6 +145,9 @@
69
70 /**
71 * Query the display
72+ *
73+ * \deprecated Use mir_connection_create_display_configuration() instead.
74+ *
75 * \warning return value must be destroyed via mir_display_config_destroy()
76 * \warning may return null if connection is invalid
77 * \param [in] connection The connection
78@@ -153,9 +156,20 @@
79 MirDisplayConfiguration* mir_connection_create_display_config(MirConnection *connection);
80
81 /**
82+ * Query the display
83+ *
84+ * \pre mir_connection_is_valid(connection) == true
85+ * \warning return value must be destroyed via mir_display_config_release()
86+ *
87+ * \param [in] connection The connection
88+ * \return structure that describes the display configuration
89+ */
90+MirDisplayConfig* mir_connection_create_display_configuration(MirConnection* connection);
91+
92+/**
93 * Register a callback to be called when the hardware display configuration changes
94 *
95- * Once a change has occurred, you can use mir_connection_create_display_config to see
96+ * Once a change has occurred, you can use mir_connection_create_display_configuration to see
97 * the new configuration.
98 *
99 * \param [in] connection The connection
100
101=== added file 'include/client/mir_toolkit/mir_display_configuration.h'
102--- include/client/mir_toolkit/mir_display_configuration.h 1970-01-01 00:00:00 +0000
103+++ include/client/mir_toolkit/mir_display_configuration.h 2016-02-26 07:01:49 +0000
104@@ -0,0 +1,360 @@
105+/*
106+ * Copyright © 2016 Canonical Ltd.
107+ *
108+ * This program is free software: you can redistribute it and/or modify it
109+ * under the terms of the GNU Lesser General Public License version 3,
110+ * as published by the Free Software Foundation.
111+ *
112+ * This program is distributed in the hope that it will be useful,
113+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
114+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
115+ * GNU Lesser General Public License for more details.
116+ *
117+ * You should have received a copy of the GNU Lesser General Public License
118+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
119+ *
120+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
121+ */
122+
123+#ifndef MIR_TOOLKIT_MIR_DISPLAY_CONFIGURATION_H_
124+#define MIR_TOOLKIT_MIR_DISPLAY_CONFIGURATION_H_
125+
126+#include "client_types.h"
127+
128+#ifdef __cplusplus
129+extern "C" {
130+#endif
131+
132+/**
133+ * \addtogroup mir_toolkit
134+ * @{
135+ */
136+
137+/**
138+ * A descriptor for a display mode.
139+ *
140+ * A display mode contains all the information necessary to drive a display. It
141+ * includes resolution and refresh rate, but also pixel clock, vsync and hsync
142+ * timings, and so on.
143+ */
144+typedef struct MirOutputMode MirOutputMode;
145+
146+/**
147+ * Release resources associated with a MirDisplayConfig handle.
148+ *
149+ * \param [in] config The handle to release
150+ */
151+void mir_display_config_release(MirDisplayConfig* config);
152+
153+/**
154+ * Get the maximum possible number of simultaneously active outputs this system
155+ * supports.
156+ *
157+ * \note There may be restrictions on the configuration required to achieve this
158+ * many active outputs. Typically the achievable number of simultaneously active
159+ * outputs is lower than this number.
160+ *
161+ * \param [in] config The configuration to query
162+ * \returns The maximum number of simultaneously active outputs
163+ * supportable at this time.
164+ */
165+int mir_display_config_get_max_simultaneous_outputs(
166+ MirDisplayConfig const* config);
167+
168+/**
169+ * Get the number of outputs available in this display configuration.
170+ *
171+ * This returns the total number of outputs the system has. This includes both
172+ * enabled and disabled output connections, and is typically larger than the
173+ * value returned from mir_display_config_get_max_simultaneous_outputs().
174+ *
175+ * Typically this will be constant over the lifetime of a client as devices
176+ * usually do not gain extra physical ports at runtime. However, hotpluggable
177+ * display devices exist and the number of virtual outputs may change at
178+ * runtime, so this should always be called to determine the number of outputs
179+ * to iterate over.
180+ *
181+ * \param [in] config The configuration to query
182+ * \returns The number of outputs available in this configuration.
183+ */
184+int mir_display_config_get_num_outputs(MirDisplayConfig const* config);
185+
186+/**
187+ * Get a read-only handle to the index 'th output of this configuration
188+ *
189+ * \note The MirOutput handle is only valid while config is valid.
190+ * \pre 0 <= index < mir_display_config_get_num_outputs(config)
191+ * \param [in] config The configuration to query
192+ * \param [in] index The index of the output to get
193+ * \returns A read-only handle to a MirOutput within config which is valid
194+ * until mir_display_config_release(config) is called.
195+ */
196+MirOutput const* mir_display_config_get_output(MirDisplayConfig const* config,
197+ size_t index);
198+
199+/**
200+ * Get the number of modes in the supported mode list of this output.
201+ *
202+ * The list of supported modes is retrieved from the hardware, possibly modified
203+ * by any applicable quirk tables, and may not be exhaustive.
204+ *
205+ * \param [in] output The MirOutput to query
206+ * \returns The number of modes in the supported mode list of output.
207+ */
208+int mir_output_get_num_modes(MirOutput const* output);
209+
210+/**
211+ * Get a handle for a mode descriptor from the list of supported modes.
212+ *
213+ * The list of supported modes is retrieved from the hardware, possibly modified
214+ * by any applicable quirk tables, and may not be exhaustive.
215+ *
216+ * \pre 0 <= index < mir_output_get_num_modes(output)
217+ * \note The handle remains valid as long as output is valid.
218+ *
219+ * \param [in] output The MirOutput to query
220+ * \param [in] index The index of the mode to retrieve.
221+ * \returns A handle for a description of the supported mode. This is valid
222+ * for as long as output is valid. The return value is never null.
223+ */
224+MirOutputMode const* mir_output_get_mode(MirOutput const* output, size_t index);
225+
226+/**
227+ * Get a handle to the output's preferred mode.
228+ *
229+ * This is provided by the output itself. For modern displays (LCD, OLED, etc)
230+ * it is typically a mode with the native resolution.
231+ *
232+ * An output may not have a preferred mode, in which case this call will return
233+ * NULL.
234+ *
235+ * \note The handle remains valid as long as output is valid.
236+ *
237+ * \param [in] output The MirOutput to query
238+ * \returns A handle for a description of the supported mode. This is valid
239+ * for as long as output is valid. If the output does not have a
240+ * preferred mode, it returns NULL.
241+ */
242+MirOutputMode const* mir_output_get_preferred_mode(MirOutput const* output);
243+
244+/**
245+ * Get a handle to the output's current mode.
246+ *
247+ * An output may not have a current mode (for example, if it is disabled), in
248+ * which case this call will return NULL.
249+ *
250+ * \note The handle remains valid as long as output is valid.
251+ *
252+ * \param [in] output The MirOutput to query
253+ * \returns A handle for a description of the supported mode. This is valid
254+ * for as long as output is valid. If the output does not have a
255+ * current mode, it returns NULL.
256+ */
257+MirOutputMode const* mir_output_get_current_mode(MirOutput const* output);
258+
259+/**
260+ * Get the number of pixel formats supported by this output
261+ *
262+ * \param [in] output The MirOutput to query
263+ * \returns The number of pixel formats for output.
264+ */
265+int mir_output_get_num_pixel_formats(MirOutput const* output);
266+
267+/**
268+ * Get a pixel format from the list of supported formats
269+ *
270+ * \pre 0 <= index < mir_output_get_num_pixel_formats(output)
271+ *
272+ * \param [in] output The MirOutput to query
273+ * \param [in] index The index of the format to query
274+ * \returns The index 'th supported pixel format.
275+ */
276+MirPixelFormat mir_output_get_pixel_format(MirOutput const* output,
277+ size_t index);
278+
279+/**
280+ * Get the current pixel format.
281+ *
282+ * \param [in] output The MirOutput to query
283+ * \returns The current pixel format. This may be mir_pixel_format_invalid
284+ * (for example, if the output is not currently enabled).
285+ */
286+MirPixelFormat mir_output_get_current_pixel_format(MirOutput const* output);
287+
288+/**
289+ * Set the output format
290+ *
291+ * \param [in] output The MirOutput to modify
292+ * \param [in] format The MirPixelFormat to set
293+ */
294+void mir_output_set_pixel_format(MirOutput* output, MirPixelFormat format);
295+
296+/**
297+ * Get the ID of an output
298+ *
299+ * This can be used to refer to the output in other parts of the API, such as
300+ * mir_surface_spec_set_fullscreen_on_output().
301+ *
302+ * \param [in] output The MirOutput to query.
303+ * \returns The ID of output, which may be used to refer to it in other
304+ * parts of the API.
305+ */
306+int mir_output_get_id(MirOutput const* output);
307+
308+/**
309+ * Get the physical connection type of an output.
310+ *
311+ * This is a best-effort determination, and may be incorrect.
312+ *
313+ * \param [in] output The MirOutput to query
314+ * \returns The type of the display connection, or mir_output_type_unknown
315+ * if it cannot be determined.
316+ */
317+MirOutputType mir_output_get_type(MirOutput const* output);
318+
319+/**
320+ * Get the x coordinate of the top-left point of the output in the virtual
321+ * display space.
322+ *
323+ * Outputs can be thought of as viewports into a virtual display space. They may
324+ * freely overlap, coincide, or be disjoint as desired.
325+ *
326+ * Output orientation changes the orientation of the output rectangle in virtual
327+ * display space, but does not change its top-left corner.
328+ *
329+ * \param [in] output The MirOutput to query
330+ * \returns The x coordinate of the top-left point of the output in the
331+ * virtual display space.
332+ */
333+int mir_output_get_position_x(MirOutput const* output);
334+
335+/**
336+ * Get the y coordinate of the top-left point of the output in the virtual
337+ * display space.
338+ *
339+ * Outputs can be thought of as viewports into a virtual display space. They may
340+ * freely overlap, coincide, or be disjoint as desired.
341+ *
342+ * Output orientation changes the orientation of the output rectangle in virtual
343+ * display space, but does not change its top-left corner.
344+ *
345+ * \param [in] output The MirOutput to query
346+ * \returns The y coordinate of the top-left point of the output in the
347+ * virtual display space.
348+ */
349+int mir_output_get_position_y(MirOutput const* output);
350+
351+/**
352+ * Get whether there is a display physically connected to the output.
353+ *
354+ * This gives a best-effort determination of whether or not enabling this output
355+ * will result in an image being displayed to the user.
356+ *
357+ * The accuracy of this determination varies with connection type - for example,
358+ * for DisplayPort and HDMI connections a return value of
359+ * mir_output_connection_state_connected is usually a reliable indicator that
360+ * there is a powered-on display connected.
361+ *
362+ * VGA and DVI connectors can usually determine whether or not there is a
363+ * physically connected display, but cannot distinguish between a powered or
364+ * unpowered display.
365+ *
366+ * It is not always possible to determine whether or not there is a display
367+ * connected; in such cases mir_output_connection_state_unknown is returned.
368+ *
369+ * \param [in] output The MirOutput to query
370+ * \returns Whether there is a display connected to this output.
371+ */
372+MirOutputConnectionState mir_output_get_connection_state(
373+ MirOutput const* output);
374+
375+/**
376+ * Get whether this output is enabled in the current configuration.
377+ *
378+ * \param [in] output the MirOutput to query
379+ * \returns Whether the output is enabled.
380+ */
381+bool mir_output_is_enabled(MirOutput const* output);
382+
383+/**
384+ * Get the physical width of the connected display, in millimetres.
385+ *
386+ * A best-effort report of the physical width of the display connected to this
387+ * output. This is retrieved from the display hardware, possibly modified by any
388+ * applicable quirk tables.
389+ *
390+ * Where this information is unavailable or inapplicable (for example,
391+ * projectors), 0 is returned.
392+ *
393+ * \param [in] output the MirOutput to query
394+ * \returns Physical width of the connected display, in mm.
395+ */
396+int mir_output_get_physical_width_mm(MirOutput const* output);
397+
398+/**
399+ * Get the physical height of the connected display, in millimetres.
400+ *
401+ * A best-effort report of the physical height of the display connected to this
402+ * output. This is retrieved from the display hardware, possibly modified by any
403+ * applicable quirk tables.
404+ *
405+ * Where this information is unavailable or inapplicable (for example,
406+ * projectors), 0 is returned.
407+ *
408+ * \param [in] output the MirOutput to query
409+ * \returns Physical height of the connected display, in mm.
410+ */
411+int mir_output_get_physical_height_mm(MirOutput const* output);
412+
413+/**
414+ * Get the power state of a connected display.
415+ *
416+ * It is undefined which power state is returned for an output which is not
417+ * connected.
418+ *
419+ * \param [in] output The MirOutput to query
420+ * \returns The power state of the display connected to output.
421+ */
422+MirPowerMode mir_output_get_power_mode(MirOutput const* output);
423+
424+/**
425+ * Get the orientation of a display.
426+ *
427+ * \param [in] output The MirOutput to query
428+ * \returns The orientation of output
429+ */
430+MirOrientation mir_output_get_orientation(MirOutput const* output);
431+
432+/**
433+ * Get the width, in pixels, of a MirOutputMode
434+ *
435+ * \note This is unaffected by the orientation of the output
436+ *
437+ * \param [in] mode The MirOutputMode to query
438+ * \returns The width, in pixels, of mode.
439+ */
440+int mir_output_mode_get_width(MirOutputMode const* mode);
441+
442+/** Get the height, in pixels, of a MirOutputMode
443+ *
444+ * \note This is unaffected by the orientation of the output
445+ *
446+ * \param [in] mode The MirOutputMode to query
447+ * \returns The height, in pixels, of mode.
448+ */
449+int mir_output_mode_get_height(MirOutputMode const* mode);
450+
451+/** Get the refresh rate, in Hz, of a MirOutputMode
452+ *
453+ * \param [in] mode The MirOutputMode to query
454+ * \returns The refresh rate, in Hz, of mode
455+ */
456+double mir_output_mode_get_refresh_rate(MirOutputMode const* mode);
457+
458+/**@}*/
459+
460+#ifdef __cplusplus
461+}
462+#endif
463+
464+#endif //MIR_TOOLKIT_MIR_DISPLAY_CONFIGURATION_H_
465
466=== modified file 'include/test/mir/test/display_config_matchers.h'
467--- include/test/mir/test/display_config_matchers.h 2016-01-29 08:18:22 +0000
468+++ include/test/mir/test/display_config_matchers.h 2016-02-26 07:01:49 +0000
469@@ -76,6 +76,15 @@
470 bool compare_display_configurations(MirDisplayConfiguration const* display_config2,
471 graphics::DisplayConfiguration const& display_config1);
472
473+bool compare_display_configurations(MirDisplayConfig const* client_config,
474+ graphics::DisplayConfiguration const& server_config);
475+
476+bool compare_display_configurations(graphics::DisplayConfiguration const& server_config,
477+ MirDisplayConfig const* client_config);
478+
479+bool compare_display_configurations(MirDisplayConfig const* config1,
480+ MirDisplayConfig const* config2);
481+
482 MATCHER_P(DisplayConfigMatches, config, "")
483 {
484 return compare_display_configurations(arg, config);
485
486=== modified file 'include/test/mir/test/doubles/stub_display_configuration.h'
487--- include/test/mir/test/doubles/stub_display_configuration.h 2016-01-29 08:18:22 +0000
488+++ include/test/mir/test/doubles/stub_display_configuration.h 2016-02-26 07:01:49 +0000
489@@ -22,6 +22,7 @@
490 #include "mir/graphics/display_configuration.h"
491
492 #include <vector>
493+#include <mir_toolkit/client_types.h>
494
495 namespace mir
496 {
497@@ -37,6 +38,9 @@
498
499 StubDisplayConfigurationOutput(graphics::DisplayConfigurationOutputId id,
500 geometry::Size px_size, geometry::Size mm_size, MirPixelFormat format, double vrefresh, bool connected);
501+
502+ StubDisplayConfigurationOutput(graphics::DisplayConfigurationOutputId id,
503+ std::vector<graphics::DisplayConfigurationMode> modes, std::vector<MirPixelFormat> formats);
504 };
505
506 class StubDisplayConfig : public graphics::DisplayConfiguration
507
508=== modified file 'src/client/CMakeLists.txt'
509--- src/client/CMakeLists.txt 2016-02-23 20:08:23 +0000
510+++ src/client/CMakeLists.txt 2016-02-26 07:01:49 +0000
511@@ -81,8 +81,10 @@
512 presentation_chain.cpp
513 mir_presentation_chain_api.cpp
514 mir_buffer_api.cpp
515+ display_configuration_api.cpp
516 ${MIR_CLIENT_SOURCES}
517 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h
518+ ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_display_configuration.h
519 )
520
521 # Ensure protobuf C++ headers have been produced before
522
523=== modified file 'src/client/display_configuration.cpp'
524--- src/client/display_configuration.cpp 2016-01-29 08:18:22 +0000
525+++ src/client/display_configuration.cpp 2016-02-26 07:01:49 +0000
526@@ -53,6 +53,13 @@
527 output_formats = new MirPixelFormat[num_formats];
528 }
529
530+mcl::DisplayOutput::DisplayOutput(DisplayOutput&& rhs)
531+{
532+ std::memcpy(this, &rhs, sizeof(*this));
533+ rhs.modes = nullptr;
534+ rhs.output_formats = nullptr;
535+}
536+
537 mcl::DisplayOutput::~DisplayOutput()
538 {
539 delete[] modes;
540@@ -103,7 +110,8 @@
541 }
542
543 mcl::DisplayConfiguration::DisplayConfiguration()
544- : notify_change([]{})
545+ : config{std::make_shared<Config>()},
546+ notify_change([]{})
547 {
548 }
549
550@@ -113,25 +121,25 @@
551
552 void mcl::DisplayConfiguration::set_configuration(mp::DisplayConfiguration const& msg)
553 {
554- std::lock_guard<std::mutex> lk(guard);
555+ auto new_config = std::make_shared<Config>();
556
557- cards.clear();
558 for (auto i = 0; i < msg.display_card_size(); i++)
559 {
560 auto const& msg_card = msg.display_card(i);
561 MirDisplayCard card;
562 fill_display_card(card, msg_card);
563- cards.push_back(card);
564+ new_config->cards.push_back(card);
565 }
566
567- outputs.clear();
568 for (auto i = 0; i < msg.display_output_size(); i++)
569 {
570 auto const& msg_output = msg.display_output(i);
571- auto output = std::make_shared<mcl::DisplayOutput>(msg_output.mode_size(), msg_output.pixel_format_size());
572- fill_display_output(*output, msg_output);
573- outputs.push_back(output);
574+ new_config->outputs.emplace_back(msg_output.mode_size(), msg_output.pixel_format_size());
575+ fill_display_output(new_config->outputs.back(), msg_output);
576 }
577+
578+ std::lock_guard<std::mutex> lk{guard};
579+ config = new_config;
580 }
581
582 void mcl::DisplayConfiguration::update_configuration(mp::DisplayConfiguration const& msg)
583@@ -144,24 +152,24 @@
584 //user is responsible for freeing the returned value
585 MirDisplayConfiguration* mcl::DisplayConfiguration::copy_to_client() const
586 {
587- std::lock_guard<std::mutex> lk(guard);
588+ auto snapshot = take_snapshot();
589 auto new_config = new MirDisplayConfiguration;
590
591 /* Cards */
592- new_config->num_cards = cards.size();
593+ new_config->num_cards = snapshot->cards.size();
594 new_config->cards = new MirDisplayCard[new_config->num_cards];
595
596- for (auto i = 0u; i < cards.size(); i++)
597- new_config->cards[i] = cards[i];
598+ for (auto i = 0u; i < snapshot->cards.size(); i++)
599+ new_config->cards[i] = snapshot->cards[i];
600
601 /* Outputs */
602- new_config->num_outputs = outputs.size();
603+ new_config->num_outputs = snapshot->outputs.size();
604 new_config->outputs = new MirDisplayOutput[new_config->num_outputs];
605
606- for (auto i = 0u; i < outputs.size(); i++)
607+ for (auto i = 0u; i < snapshot->outputs.size(); i++)
608 {
609 auto new_info = &new_config->outputs[i];
610- MirDisplayOutput* output = outputs[i].get();
611+ MirDisplayOutput* output = &snapshot->outputs[i];
612 std::memcpy(new_info, output, sizeof(MirDisplayOutput));
613
614 new_info->output_formats = new MirPixelFormat[new_info->num_output_formats];
615@@ -176,6 +184,12 @@
616 return new_config;
617 }
618
619+auto mcl::DisplayConfiguration::take_snapshot() const -> std::shared_ptr<Config>
620+{
621+ std::lock_guard<std::mutex> lk{guard};
622+ return config;
623+}
624+
625 void mcl::DisplayConfiguration::set_display_change_handler(std::function<void()> const& fn)
626 {
627 std::lock_guard<std::mutex> lk(guard);
628
629=== modified file 'src/client/display_configuration.h'
630--- src/client/display_configuration.h 2013-08-28 03:41:48 +0000
631+++ src/client/display_configuration.h 2016-02-26 07:01:49 +0000
632@@ -35,6 +35,9 @@
633 {
634 public:
635 DisplayOutput(size_t num_modes_, size_t num_formats);
636+
637+ DisplayOutput(DisplayOutput const&) = delete;
638+ DisplayOutput(DisplayOutput&& rhs);
639 ~DisplayOutput();
640 };
641
642@@ -44,6 +47,12 @@
643 class DisplayConfiguration
644 {
645 public:
646+ struct Config
647+ {
648+ std::vector<MirDisplayCard> cards;
649+ std::vector<DisplayOutput> outputs;
650+ };
651+
652 DisplayConfiguration();
653 ~DisplayConfiguration();
654
655@@ -53,11 +62,12 @@
656
657 //copying to a c POD, so kinda kludgy
658 MirDisplayConfiguration* copy_to_client() const;
659+ std::shared_ptr<Config> take_snapshot() const;
660
661 private:
662 std::mutex mutable guard;
663- std::vector<MirDisplayCard> cards;
664- std::vector<std::shared_ptr<DisplayOutput>> outputs;
665+ std::shared_ptr<Config> config;
666+
667 std::function<void()> notify_change;
668 };
669
670
671=== added file 'src/client/display_configuration_api.cpp'
672--- src/client/display_configuration_api.cpp 1970-01-01 00:00:00 +0000
673+++ src/client/display_configuration_api.cpp 2016-02-26 07:01:49 +0000
674@@ -0,0 +1,295 @@
675+/*
676+ * Copyright © 2016 Canonical Ltd.
677+ *
678+ * This program is free software: you can redistribute it and/or modify it
679+ * under the terms of the GNU Lesser General Public License version 3,
680+ * as published by the Free Software Foundation.
681+ *
682+ * This program is distributed in the hope that it will be useful,
683+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
684+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
685+ * GNU Lesser General Public License for more details.
686+ *
687+ * You should have received a copy of the GNU Lesser General Public License
688+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
689+ *
690+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
691+ */
692+
693+#include <mir_toolkit/mir_display_configuration.h>
694+#include <mir/require.h>
695+
696+#include "display_configuration.h"
697+
698+namespace mcl = mir::client;
699+
700+namespace
701+{
702+std::shared_ptr<mcl::DisplayConfiguration::Config>& client_to_config(MirDisplayConfig* config)
703+{
704+ return *reinterpret_cast<std::shared_ptr<mcl::DisplayConfiguration::Config>*>(config);
705+}
706+
707+std::shared_ptr<mcl::DisplayConfiguration::Config const>& client_to_config(MirDisplayConfig const* config)
708+{
709+ return *reinterpret_cast<std::shared_ptr<mcl::DisplayConfiguration::Config const>*>(const_cast<MirDisplayConfig*>(config));
710+}
711+
712+MirOutput* output_to_client(MirDisplayOutput* output)
713+{
714+ return reinterpret_cast<MirOutput*>(output);
715+}
716+
717+MirOutput const* output_to_client(MirDisplayOutput const* output)
718+{
719+ return reinterpret_cast<MirOutput const*>(output);
720+}
721+
722+MirDisplayOutput* client_to_output(MirOutput* client)
723+{
724+ return reinterpret_cast<MirDisplayOutput*>(client);
725+}
726+
727+MirDisplayOutput const* client_to_output(MirOutput const* client)
728+{
729+ return reinterpret_cast<MirDisplayOutput const*>(client);
730+}
731+}
732+
733+int mir_display_config_get_num_outputs(MirDisplayConfig const* client)
734+{
735+ auto config = client_to_config(client);
736+ return config->outputs.size();
737+}
738+
739+MirOutput const* mir_display_config_get_output(MirDisplayConfig const* client_config, size_t index)
740+{
741+ auto config = client_to_config(client_config);
742+
743+ mir::require(index < config->outputs.size());
744+
745+ return output_to_client(&config->outputs[index]);
746+}
747+
748+MirOutput* mir_display_config_get_mutable_output(MirDisplayConfig* client_config, size_t index)
749+{
750+ auto config = client_to_config(client_config);
751+
752+ mir::require(index < config->outputs.size());
753+
754+ return output_to_client(&config->outputs[index]);
755+}
756+
757+bool mir_output_is_enabled(MirOutput const* client_output)
758+{
759+ auto output = client_to_output(client_output);
760+
761+ return (output->used != 0);
762+}
763+
764+void mir_output_enable(MirOutput* client_output)
765+{
766+ auto output = client_to_output(client_output);
767+
768+ output->used = 1;
769+}
770+
771+void mir_output_disable(MirOutput* client_output)
772+{
773+ auto output = client_to_output(client_output);
774+
775+ output->used = 0;
776+}
777+
778+int mir_display_config_get_max_simultaneous_outputs(MirDisplayConfig const* client_config)
779+{
780+ auto config = client_to_config(client_config);
781+
782+ return config->cards[0].max_simultaneous_outputs;
783+}
784+
785+int mir_output_get_id(MirOutput const* client_output)
786+{
787+ auto output = client_to_output(client_output);
788+
789+ return output->output_id;
790+}
791+
792+MirOutputType mir_output_get_type(MirOutput const* client_output)
793+{
794+ auto output = client_to_output(client_output);
795+
796+ return static_cast<MirOutputType>(output->type);
797+}
798+
799+int mir_output_get_physical_width_mm(MirOutput const *client_output)
800+{
801+ auto output = client_to_output(client_output);
802+
803+ return output->physical_width_mm;
804+}
805+
806+int mir_output_get_num_modes(MirOutput const* client_output)
807+{
808+ auto output = client_to_output(client_output);
809+
810+ return output->num_modes;
811+}
812+
813+MirOutputMode const* mir_output_get_preferred_mode(MirOutput const* client_output)
814+{
815+ auto output = client_to_output(client_output);
816+
817+ if (output->preferred_mode >= output->num_modes)
818+ {
819+ return nullptr;
820+ }
821+ else
822+ {
823+ return reinterpret_cast<MirOutputMode const*>(&output->modes[output->preferred_mode]);
824+ }
825+}
826+
827+MirOutputMode const* mir_output_get_current_mode(MirOutput const* client_output)
828+{
829+ auto output = client_to_output(client_output);
830+
831+ if (output->current_mode >= output->num_modes)
832+ {
833+ return nullptr;
834+ }
835+ else
836+ {
837+ return reinterpret_cast<MirOutputMode const*>(&output->modes[output->current_mode]);
838+ }
839+}
840+
841+void mir_output_set_current_mode(MirOutput* client_output, MirOutputMode const* mode)
842+{
843+ auto output = client_to_output(client_output);
844+
845+ int index = std::distance(
846+ const_cast<MirDisplayMode const*>(output->modes),
847+ reinterpret_cast<MirDisplayMode const*>(mode));
848+
849+ mir::require(index >= 0);
850+ mir::require(index < static_cast<int>(output->num_modes));
851+
852+ output->current_mode = static_cast<uint32_t>(index);
853+}
854+
855+MirOutputMode const* mir_output_get_mode(MirOutput const* client_output, size_t index)
856+{
857+ auto output = client_to_output(client_output);
858+
859+ return reinterpret_cast<MirOutputMode const*>(&output->modes[index]);
860+}
861+
862+int mir_output_get_num_pixel_formats(MirOutput const* client_output)
863+{
864+ auto output = client_to_output(client_output);
865+
866+ return output->num_output_formats;
867+}
868+
869+MirPixelFormat mir_output_get_pixel_format(MirOutput const* client_output, size_t index)
870+{
871+ auto output = client_to_output(client_output);
872+
873+ return output->output_formats[index];
874+}
875+
876+MirPixelFormat mir_output_get_current_pixel_format(MirOutput const* client_output)
877+{
878+ auto output = client_to_output(client_output);
879+
880+ return output->current_format;
881+}
882+
883+void mir_output_set_pixel_format(MirOutput* client_output, MirPixelFormat format)
884+{
885+ auto output = client_to_output(client_output);
886+
887+ // TODO: Maybe check format validity?
888+ output->current_format = format;
889+}
890+
891+int mir_output_get_position_x(MirOutput const* client_output)
892+{
893+ auto output = client_to_output(client_output);
894+
895+ return output->position_x;
896+}
897+
898+int mir_output_get_position_y(MirOutput const* client_output)
899+{
900+ auto output = client_to_output(client_output);
901+
902+ return output->position_y;
903+}
904+
905+void mir_output_set_position(MirOutput* client_output, int x, int y)
906+{
907+ auto output = client_to_output(client_output);
908+
909+ output->position_x = x;
910+ output->position_y = y;
911+}
912+
913+MirOutputConnectionState mir_output_get_connection_state(MirOutput const *client_output)
914+{
915+ auto output = client_to_output(client_output);
916+
917+ // TODO: actually plumb through mir_output_connection_state_unknown.
918+ return output->connected == 0 ? mir_output_connection_state_disconnected :
919+ mir_output_connection_state_connected;
920+}
921+
922+int mir_output_get_physical_height_mm(MirOutput const *client_output)
923+{
924+ auto output = client_to_output(client_output);
925+
926+ return output->physical_height_mm;
927+}
928+
929+MirPowerMode mir_output_get_power_mode(MirOutput const* client_output)
930+{
931+ auto output = client_to_output(client_output);
932+
933+ return output->power_mode;
934+}
935+
936+void mir_output_set_power_mode(MirOutput* client_output, MirPowerMode mode)
937+{
938+ auto output = client_to_output(client_output);
939+
940+ output->power_mode = mode;
941+}
942+
943+MirOrientation mir_output_get_orientation(MirOutput const* client_output)
944+{
945+ auto output = client_to_output(client_output);
946+
947+ return output->orientation;
948+}
949+
950+int mir_output_mode_get_width(MirOutputMode const* mode)
951+{
952+ auto internal_mode = reinterpret_cast<MirDisplayMode const *>(mode);
953+
954+ return internal_mode->horizontal_resolution;
955+}
956+
957+int mir_output_mode_get_height(MirOutputMode const* mode)
958+{
959+ auto internal_mode = reinterpret_cast<MirDisplayMode const *>(mode);
960+
961+ return internal_mode->vertical_resolution;
962+}
963+
964+double mir_output_mode_get_refresh_rate(MirOutputMode const* mode)
965+{
966+ auto internal_mode = reinterpret_cast<MirDisplayMode const *>(mode);
967+
968+ return internal_mode->refresh_rate;
969+}
970
971=== modified file 'src/client/mir_connection.cpp'
972--- src/client/mir_connection.cpp 2016-02-23 16:12:59 +0000
973+++ src/client/mir_connection.cpp 2016-02-26 07:01:49 +0000
974@@ -1009,6 +1009,11 @@
975 surface_map->erase(stream->rpc_id());
976 }
977
978+std::shared_ptr<mcl::DisplayConfiguration::Config> MirConnection::snapshot_display_configuration() const
979+{
980+ return display_configuration->take_snapshot();
981+}
982+
983 void MirConnection::create_presentation_chain(
984 mir_presentation_chain_callback callback,
985 void *context)
986
987=== modified file 'src/client/mir_connection.h'
988--- src/client/mir_connection.h 2016-02-23 16:12:59 +0000
989+++ src/client/mir_connection.h 2016-02-26 07:01:49 +0000
990@@ -31,6 +31,7 @@
991 #include "mir_toolkit/mir_client_library.h"
992 #include "mir_toolkit/client_types_nbs.h"
993 #include "mir_surface.h"
994+#include "display_configuration.h"
995
996 #include <atomic>
997 #include <memory>
998@@ -132,6 +133,7 @@
999 void populate(MirPlatformPackage& platform_package);
1000 void populate_graphics_module(MirModuleProperties& properties);
1001 MirDisplayConfiguration* create_copy_of_display_config();
1002+ std::shared_ptr<mir::client::DisplayConfiguration::Config> snapshot_display_configuration() const;
1003 void available_surface_formats(MirPixelFormat* formats,
1004 unsigned int formats_size, unsigned int& valid_formats);
1005
1006
1007=== modified file 'src/client/mir_connection_api.cpp'
1008--- src/client/mir_connection_api.cpp 2016-01-29 08:18:22 +0000
1009+++ src/client/mir_connection_api.cpp 2016-02-26 07:01:49 +0000
1010@@ -232,6 +232,20 @@
1011 return nullptr;
1012 }
1013
1014+MirDisplayConfig* mir_connection_create_display_configuration(
1015+ MirConnection* connection)
1016+{
1017+ mir::require(mir_connection_is_valid(connection));
1018+
1019+ return reinterpret_cast<MirDisplayConfig*>(new std::shared_ptr<mcl::DisplayConfiguration::Config>{connection->snapshot_display_configuration()});
1020+}
1021+
1022+void mir_display_config_release(MirDisplayConfig* user_config)
1023+{
1024+ auto config = reinterpret_cast<std::shared_ptr<mcl::DisplayConfiguration::Config>*>(user_config);
1025+ delete config;
1026+}
1027+
1028 void mir_connection_set_display_config_change_callback(
1029 MirConnection* connection,
1030 mir_display_config_callback callback,
1031
1032=== modified file 'src/client/symbols.map'
1033--- src/client/symbols.map 2016-02-23 20:08:23 +0000
1034+++ src/client/symbols.map 2016-02-26 07:01:49 +0000
1035@@ -222,6 +222,39 @@
1036 mir_surface_spec_set_shell_chrome;
1037 } MIR_CLIENT_9v18;
1038
1039+MIR_CLIENT_9_unreleased {
1040+ global:
1041+ mir_connection_create_display_configuration;
1042+ mir_display_config_release;
1043+ mir_display_config_get_num_outputs;
1044+ mir_connection_apply_display_configuration;
1045+ mir_connection_set_base_display_configuration;
1046+ mir_display_config_get_output;
1047+ mir_output_is_enabled;
1048+ mir_display_config_get_max_simultaneous_outputs;
1049+ mir_output_get_id;
1050+ mir_output_get_type;
1051+ mir_output_get_preferred_mode;
1052+ mir_output_get_physical_width_mm;
1053+ mir_output_get_physical_height_mm;
1054+ mir_output_get_connection_state;
1055+ mir_output_get_position_x;
1056+ mir_output_get_position_y;
1057+ mir_output_get_current_mode;
1058+ mir_output_get_current_pixel_format;
1059+ mir_output_get_power_mode;
1060+ mir_output_get_orientation;
1061+ mir_output_get_num_modes;
1062+ mir_output_get_mode;
1063+ mir_output_get_num_pixel_formats;
1064+ mir_output_get_pixel_format;
1065+ mir_output_mode_get_width;
1066+ mir_output_mode_get_height;
1067+ mir_output_mode_get_refresh_rate;
1068+ local:
1069+ *;
1070+} MIR_CLIENT_9v19;
1071+
1072 MIR_CLIENT_DETAIL_9 {
1073 global:
1074 extern "C++" {
1075
1076=== modified file 'tests/acceptance-tests/CMakeLists.txt'
1077--- tests/acceptance-tests/CMakeLists.txt 2016-01-29 08:18:22 +0000
1078+++ tests/acceptance-tests/CMakeLists.txt 2016-02-26 07:01:49 +0000
1079@@ -53,6 +53,7 @@
1080 test_session_mediator_report.cpp
1081 test_surface_raise.cpp
1082 test_client_cookie.cpp
1083+ test_new_display_configuration.cpp
1084 )
1085
1086 if (MIR_TEST_PLATFORM STREQUAL "mesa-kms" OR MIR_TEST_PLATFORM STREQUAL "mesa-x11")
1087
1088=== modified file 'tests/acceptance-tests/test_display_configuration.cpp'
1089--- tests/acceptance-tests/test_display_configuration.cpp 2016-01-29 08:18:22 +0000
1090+++ tests/acceptance-tests/test_display_configuration.cpp 2016-02-26 07:01:49 +0000
1091@@ -103,7 +103,7 @@
1092 }
1093 }
1094
1095-struct DisplayConfigurationTest : mtf::ConnectedClientWithASurface
1096+struct LegacyDisplayConfigurationTest : mtf::ConnectedClientWithASurface
1097 {
1098 void SetUp() override
1099 {
1100@@ -116,7 +116,7 @@
1101 StubAuthorizer stub_authorizer;
1102 };
1103
1104-TEST_F(DisplayConfigurationTest, display_configuration_reaches_client)
1105+TEST_F(LegacyDisplayConfigurationTest, display_configuration_reaches_client)
1106 {
1107 auto configuration = mir_connection_create_display_config(connection);
1108
1109@@ -141,7 +141,7 @@
1110 }
1111 }
1112
1113-TEST_F(DisplayConfigurationTest, hw_display_change_notification_reaches_all_clients)
1114+TEST_F(LegacyDisplayConfigurationTest, hw_display_change_notification_reaches_all_clients)
1115 {
1116 std::atomic<bool> callback_called{false};
1117
1118@@ -175,7 +175,7 @@
1119 mir_connection_release(unsubscribed_connection);
1120 }
1121
1122-TEST_F(DisplayConfigurationTest, display_change_request_for_unauthorized_client_fails)
1123+TEST_F(LegacyDisplayConfigurationTest, display_change_request_for_unauthorized_client_fails)
1124 {
1125 stub_authorizer.allow_configure_display = false;
1126
1127@@ -250,7 +250,7 @@
1128 };
1129 }
1130
1131-TEST_F(DisplayConfigurationTest, changing_config_for_focused_client_configures_display)
1132+TEST_F(LegacyDisplayConfigurationTest, changing_config_for_focused_client_configures_display)
1133 {
1134 EXPECT_CALL(mock_display, configure(_)).Times(0);
1135
1136@@ -271,7 +271,7 @@
1137 display_client.disconnect();
1138 }
1139
1140-TEST_F(DisplayConfigurationTest, focusing_client_with_display_config_configures_display)
1141+TEST_F(LegacyDisplayConfigurationTest, focusing_client_with_display_config_configures_display)
1142 {
1143 EXPECT_CALL(mock_display, configure(_)).Times(0);
1144
1145@@ -300,7 +300,7 @@
1146 testing::Mock::VerifyAndClearExpectations(&mock_display);
1147 }
1148
1149-TEST_F(DisplayConfigurationTest, changing_focus_from_client_with_config_to_client_without_config_configures_display)
1150+TEST_F(LegacyDisplayConfigurationTest, changing_focus_from_client_with_config_to_client_without_config_configures_display)
1151 {
1152 DisplayClient display_client{new_connection()};
1153 SimpleClient simple_client{new_connection()};
1154@@ -331,7 +331,7 @@
1155 simple_client.disconnect();
1156 }
1157
1158-TEST_F(DisplayConfigurationTest, hw_display_change_doesnt_apply_base_config_if_per_session_config_is_active)
1159+TEST_F(LegacyDisplayConfigurationTest, hw_display_change_doesnt_apply_base_config_if_per_session_config_is_active)
1160 {
1161 DisplayClient display_client{new_connection()};
1162
1163@@ -373,7 +373,7 @@
1164 }
1165 }
1166
1167-TEST_F(DisplayConfigurationTest, shell_initiated_display_configuration_notifies_clients)
1168+TEST_F(LegacyDisplayConfigurationTest, shell_initiated_display_configuration_notifies_clients)
1169 {
1170 using namespace testing;
1171
1172@@ -415,7 +415,7 @@
1173 client.disconnect();
1174 }
1175
1176-TEST_F(DisplayConfigurationTest,
1177+TEST_F(LegacyDisplayConfigurationTest,
1178 client_setting_base_config_configures_display_if_a_session_config_is_not_applied)
1179 {
1180 DisplayClient display_client{new_connection()};
1181@@ -434,7 +434,7 @@
1182 display_client.disconnect();
1183 }
1184
1185-TEST_F(DisplayConfigurationTest,
1186+TEST_F(LegacyDisplayConfigurationTest,
1187 client_setting_base_config_does_not_configure_display_if_a_session_config_is_applied)
1188 {
1189 DisplayClient display_client{new_connection()};
1190@@ -468,7 +468,7 @@
1191 }
1192 }
1193
1194-TEST_F(DisplayConfigurationTest,
1195+TEST_F(LegacyDisplayConfigurationTest,
1196 client_is_notified_of_new_base_config_eventually_after_set_base_configuration)
1197 {
1198 DisplayClient display_client{new_connection()};
1199@@ -492,7 +492,7 @@
1200 display_client.disconnect();
1201 }
1202
1203-TEST_F(DisplayConfigurationTest,
1204+TEST_F(LegacyDisplayConfigurationTest,
1205 set_base_configuration_for_unauthorized_client_fails)
1206 {
1207 stub_authorizer.allow_set_base_display_configuration = false;
1208@@ -508,7 +508,7 @@
1209 mir_connection_release(connection);
1210 }
1211
1212-TEST_F(DisplayConfigurationTest, disconnection_of_client_with_display_config_reconfigures_display)
1213+TEST_F(LegacyDisplayConfigurationTest, disconnection_of_client_with_display_config_reconfigures_display)
1214 {
1215 EXPECT_CALL(mock_display, configure(_)).Times(0);
1216
1217@@ -534,7 +534,7 @@
1218 testing::Mock::VerifyAndClearExpectations(&mock_display);
1219 }
1220
1221-TEST_F(DisplayConfigurationTest,
1222+TEST_F(LegacyDisplayConfigurationTest,
1223 disconnection_without_releasing_surfaces_of_client_with_display_config_reconfigures_display)
1224 {
1225 EXPECT_CALL(mock_display, configure(_)).Times(0);
1226
1227=== added file 'tests/acceptance-tests/test_new_display_configuration.cpp'
1228--- tests/acceptance-tests/test_new_display_configuration.cpp 1970-01-01 00:00:00 +0000
1229+++ tests/acceptance-tests/test_new_display_configuration.cpp 2016-02-26 07:01:49 +0000
1230@@ -0,0 +1,671 @@
1231+/*
1232+ * Copyright © 2013-2016 Canonical Ltd.
1233+ *
1234+ * This program is free software: you can redistribute it and/or modify
1235+ * it under the terms of the GNU General Public License version 3 as
1236+ * published by the Free Software Foundation.
1237+ *
1238+ * This program is distributed in the hope that it will be useful,
1239+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1240+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1241+ * GNU General Public License for more details.
1242+ *
1243+ * You should have received a copy of the GNU General Public License
1244+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1245+ *
1246+ * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
1247+ * Kevin DuBois <kevin.dubois@canonical.com>
1248+ * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
1249+ */
1250+
1251+#include "mir/main_loop.h"
1252+#include "mir/frontend/session_authorizer.h"
1253+#include "mir/graphics/event_handler_register.h"
1254+#include "mir/shell/display_configuration_controller.h"
1255+
1256+#include "mir_test_framework/connected_client_with_a_surface.h"
1257+#include "mir/test/doubles/null_platform.h"
1258+#include "mir/test/doubles/fake_display.h"
1259+#include "mir/test/doubles/null_display_sync_group.h"
1260+#include "mir/test/doubles/null_platform.h"
1261+#include "mir/test/display_config_matchers.h"
1262+#include "mir/test/doubles/stub_display_configuration.h"
1263+#include "mir/test/doubles/stub_session_authorizer.h"
1264+#include "mir/test/fake_shared.h"
1265+#include "mir/test/pipe.h"
1266+#include "mir/test/wait_condition.h"
1267+#include "mir/test/signal.h"
1268+
1269+#include "mir_toolkit/mir_client_library.h"
1270+
1271+#include <atomic>
1272+#include <chrono>
1273+
1274+#include <gmock/gmock.h>
1275+#include <gtest/gtest.h>
1276+
1277+namespace mg = mir::graphics;
1278+namespace geom = mir::geometry;
1279+namespace mf = mir::frontend;
1280+namespace mtf = mir_test_framework;
1281+namespace mtd = mir::test::doubles;
1282+namespace mt = mir::test;
1283+
1284+using namespace testing;
1285+using namespace std::literals::chrono_literals;
1286+
1287+namespace
1288+{
1289+mtd::StubDisplayConfig stub_display_config;
1290+
1291+mtd::StubDisplayConfig changed_stub_display_config{1};
1292+
1293+class MockDisplay : public mtd::FakeDisplay
1294+{
1295+public:
1296+ MockDisplay(): mtd::FakeDisplay()
1297+ {
1298+ using namespace testing;
1299+ ON_CALL(*this, configure(_))
1300+ .WillByDefault(Invoke(
1301+ [this](mg::DisplayConfiguration const& new_config)
1302+ {
1303+ mtd::FakeDisplay::configure(new_config);
1304+ }));
1305+ }
1306+
1307+ MOCK_METHOD1(configure, void(mg::DisplayConfiguration const&));
1308+};
1309+
1310+struct StubAuthorizer : mtd::StubSessionAuthorizer
1311+{
1312+ bool configure_display_is_allowed(mf::SessionCredentials const&) override
1313+ {
1314+ return allow_configure_display;
1315+ }
1316+
1317+ bool set_base_display_configuration_is_allowed(mf::SessionCredentials const&) override
1318+ {
1319+ return allow_set_base_display_configuration;
1320+ }
1321+
1322+ std::atomic<bool> allow_configure_display{true};
1323+ std::atomic<bool> allow_set_base_display_configuration{true};
1324+};
1325+
1326+void wait_for_server_actions_to_finish(mir::ServerActionQueue& server_action_queue)
1327+{
1328+ mt::WaitCondition last_action_done;
1329+ server_action_queue.enqueue(
1330+ &last_action_done,
1331+ [&] { last_action_done.wake_up_everyone(); });
1332+
1333+ last_action_done.wait_for_at_most_seconds(5);
1334+}
1335+}
1336+
1337+struct DisplayConfigurationTest : mtf::ConnectedClientWithASurface
1338+{
1339+ void SetUp() override
1340+ {
1341+ server.override_the_session_authorizer([this] { return mt::fake_shared(stub_authorizer); });
1342+ preset_display(mt::fake_shared(mock_display));
1343+ mtf::ConnectedClientWithASurface::SetUp();
1344+ }
1345+
1346+ testing::NiceMock<MockDisplay> mock_display;
1347+ StubAuthorizer stub_authorizer;
1348+};
1349+
1350+TEST_F(DisplayConfigurationTest, display_configuration_reaches_client)
1351+{
1352+ auto configuration = mir_connection_create_display_configuration(connection);
1353+
1354+ EXPECT_THAT(configuration,
1355+ mt::DisplayConfigMatches(std::cref(stub_display_config)));
1356+
1357+ mir_display_config_release(configuration);
1358+}
1359+
1360+namespace
1361+{
1362+void display_change_handler(MirConnection* connection, void* context)
1363+{
1364+ auto configuration = mir_connection_create_display_configuration(connection);
1365+
1366+ EXPECT_THAT(configuration,
1367+ mt::DisplayConfigMatches(std::cref(changed_stub_display_config)));
1368+ mir_display_config_release(configuration);
1369+
1370+ auto callback_called = static_cast<mt::Signal*>(context);
1371+ callback_called->raise();
1372+}
1373+}
1374+
1375+TEST_F(DisplayConfigurationTest, hw_display_change_notification_reaches_all_clients)
1376+{
1377+ mt::Signal callback_called;
1378+
1379+ mir_connection_set_display_config_change_callback(connection, &display_change_handler, &callback_called);
1380+
1381+ MirConnection* unsubscribed_connection = mir_connect_sync(new_connection().c_str(), "notifier");
1382+
1383+ mock_display.emit_configuration_change_event(
1384+ mt::fake_shared(changed_stub_display_config));
1385+
1386+ EXPECT_TRUE(callback_called.wait_for(std::chrono::seconds{10}));
1387+
1388+ // At this point, the message has gone out on the wire. since with unsubscribed_connection
1389+ // we're emulating a client that is passively subscribed, we will just wait for the display
1390+ // configuration to change and then will check the new config.
1391+
1392+ auto config = mir_connection_create_display_configuration(unsubscribed_connection);
1393+ while((unsigned)mir_display_config_get_num_outputs(config) != changed_stub_display_config.outputs.size())
1394+ {
1395+ mir_display_config_release(config);
1396+ std::this_thread::sleep_for(std::chrono::microseconds(500));
1397+ config = mir_connection_create_display_configuration(unsubscribed_connection);
1398+ }
1399+
1400+ EXPECT_THAT(config,
1401+ mt::DisplayConfigMatches(std::cref(changed_stub_display_config)));
1402+
1403+ mir_display_config_release(config);
1404+
1405+ mir_connection_release(unsubscribed_connection);
1406+}
1407+
1408+namespace
1409+{
1410+struct SimpleClient
1411+{
1412+ SimpleClient(std::string const& mir_test_socket) :
1413+ mir_test_socket{mir_test_socket} {}
1414+
1415+ void connect()
1416+ {
1417+ connection = mir_connect_sync(mir_test_socket.c_str(), __PRETTY_FUNCTION__);
1418+
1419+ auto const spec = mir_connection_create_spec_for_normal_surface(connection, 100, 100, mir_pixel_format_abgr_8888);
1420+ surface = mir_surface_create_sync(spec);
1421+ mir_surface_spec_release(spec);
1422+ mir_buffer_stream_swap_buffers_sync(mir_surface_get_buffer_stream(surface));
1423+ }
1424+
1425+ void disconnect()
1426+ {
1427+ mir_surface_release_sync(surface);
1428+ mir_connection_release(connection);
1429+ }
1430+
1431+ void disconnect_without_releasing_surface()
1432+ {
1433+ mir_connection_release(connection);
1434+ }
1435+
1436+ std::string mir_test_socket;
1437+ MirConnection* connection{nullptr};
1438+ MirSurface* surface{nullptr};
1439+};
1440+
1441+struct DisplayClient : SimpleClient
1442+{
1443+ using SimpleClient::SimpleClient;
1444+
1445+ std::unique_ptr<MirDisplayConfig,void(*)(MirDisplayConfig*)> get_base_config()
1446+ {
1447+ return {mir_connection_create_display_configuration(connection),
1448+ &mir_display_config_release};
1449+ }
1450+};
1451+}
1452+
1453+namespace
1454+{
1455+struct DisplayConfigMatchingContext
1456+{
1457+ std::function<void(MirDisplayConfig*)> matcher;
1458+ mt::Signal done;
1459+};
1460+
1461+void new_display_config_matches(MirConnection* connection, void* ctx)
1462+{
1463+ auto context = reinterpret_cast<DisplayConfigMatchingContext*>(ctx);
1464+
1465+ auto config = mir_connection_create_display_configuration(connection);
1466+ context->matcher(config);
1467+ mir_display_config_release(config);
1468+ context->done.raise();
1469+}
1470+}
1471+
1472+TEST_F(DisplayConfigurationTest, shell_initiated_display_configuration_notifies_clients)
1473+{
1474+ using namespace testing;
1475+
1476+ // Create a new client for explicit lifetime handling.
1477+ SimpleClient client{new_connection()};
1478+
1479+ client.connect();
1480+
1481+ std::shared_ptr<mg::DisplayConfiguration> new_conf;
1482+ new_conf = server.the_display()->configuration();
1483+
1484+ new_conf->for_each_output([](mg::UserDisplayConfigurationOutput& output)
1485+ {
1486+ if (output.connected)
1487+ {
1488+ output.used = !output.used;
1489+ }
1490+ });
1491+
1492+ DisplayConfigMatchingContext context;
1493+ context.matcher = [new_conf](MirDisplayConfig* conf)
1494+ {
1495+ EXPECT_THAT(conf, mt::DisplayConfigMatches(std::cref(*new_conf)));
1496+ };
1497+
1498+ mir_connection_set_display_config_change_callback(
1499+ client.connection,
1500+ &new_display_config_matches,
1501+ &context);
1502+
1503+ server.the_display_configuration_controller()->set_base_configuration(new_conf);
1504+
1505+ EXPECT_TRUE(context.done.wait_for(std::chrono::seconds{10}));
1506+
1507+ EXPECT_THAT(
1508+ *server.the_display()->configuration(),
1509+ mt::DisplayConfigMatches(std::cref(*new_conf)));
1510+
1511+ client.disconnect();
1512+}
1513+
1514+struct DisplayPowerSetting : public DisplayConfigurationTest, public ::testing::WithParamInterface<MirPowerMode> {};
1515+struct DisplayOrientationSetting : public DisplayConfigurationTest, public ::testing::WithParamInterface<MirOrientation> {};
1516+struct DisplayFormatSetting : public DisplayConfigurationTest, public ::testing::WithParamInterface<MirPixelFormat> {};
1517+
1518+TEST_P(DisplayPowerSetting, can_get_power_mode)
1519+{
1520+ using namespace testing;
1521+
1522+ auto mode = GetParam();
1523+
1524+ std::shared_ptr<mg::DisplayConfiguration> server_config = server.the_display()->configuration();
1525+
1526+ server_config->for_each_output(
1527+ [mode](mg::UserDisplayConfigurationOutput& output)
1528+ {
1529+ output.power_mode = mode;
1530+ });
1531+
1532+ server.the_display_configuration_controller()->set_base_configuration(server_config);
1533+ wait_for_server_actions_to_finish(*server.the_main_loop());
1534+
1535+ DisplayClient client{new_connection()};
1536+
1537+ client.connect();
1538+
1539+ auto client_config = client.get_base_config();
1540+
1541+ for (int i = 0; i < mir_display_config_get_num_outputs(client_config.get()); ++i)
1542+ {
1543+ auto output = mir_display_config_get_output(client_config.get(), i);
1544+
1545+ EXPECT_THAT(mir_output_get_power_mode(output), Eq(mode));
1546+ }
1547+
1548+ client.disconnect();
1549+}
1550+
1551+TEST_P(DisplayOrientationSetting, can_get_orientation)
1552+{
1553+ using namespace testing;
1554+
1555+ auto orientation = GetParam();
1556+
1557+ std::shared_ptr<mg::DisplayConfiguration> server_config = server.the_display()->configuration();
1558+
1559+ server_config->for_each_output(
1560+ [orientation](mg::UserDisplayConfigurationOutput& output)
1561+ {
1562+ output.orientation = orientation;
1563+ });
1564+
1565+ mock_display.emit_configuration_change_event(server_config);
1566+ mock_display.wait_for_configuration_change_handler();
1567+
1568+ DisplayClient client{new_connection()};
1569+
1570+ client.connect();
1571+
1572+ auto client_config = client.get_base_config();
1573+
1574+ for (int i = 0; i < mir_display_config_get_num_outputs(client_config.get()); ++i)
1575+ {
1576+ auto output = mir_display_config_get_output(client_config.get(), i);
1577+
1578+ EXPECT_THAT(mir_output_get_orientation(output), Eq(orientation));
1579+ }
1580+
1581+ client.disconnect();
1582+}
1583+
1584+namespace
1585+{
1586+std::vector<MirPixelFormat> const formats{
1587+ mir_pixel_format_abgr_8888,
1588+ mir_pixel_format_xbgr_8888,
1589+ mir_pixel_format_argb_8888,
1590+ mir_pixel_format_xrgb_8888,
1591+ mir_pixel_format_bgr_888,
1592+ mir_pixel_format_rgb_888,
1593+ mir_pixel_format_rgb_565,
1594+ mir_pixel_format_rgba_5551,
1595+ mir_pixel_format_rgba_4444,
1596+};
1597+}
1598+
1599+TEST_P(DisplayFormatSetting, can_get_all_output_format)
1600+{
1601+ using namespace testing;
1602+
1603+ auto format = GetParam();
1604+ mtd::StubDisplayConfig single_format_config(1, {format});
1605+
1606+ mock_display.emit_configuration_change_event(mt::fake_shared(single_format_config));
1607+ mock_display.wait_for_configuration_change_handler();
1608+
1609+ DisplayClient client{new_connection()};
1610+
1611+ client.connect();
1612+
1613+ auto client_config = client.get_base_config();
1614+
1615+ for (int i = 0; i < mir_display_config_get_num_outputs(client_config.get()); ++i)
1616+ {
1617+ auto output = mir_display_config_get_output(client_config.get(), i);
1618+
1619+ EXPECT_THAT(mir_output_get_current_pixel_format(output), Eq(format));
1620+ }
1621+
1622+ client.disconnect();
1623+}
1624+
1625+INSTANTIATE_TEST_CASE_P(DisplayConfiguration, DisplayPowerSetting,
1626+ Values(mir_power_mode_on, mir_power_mode_standby, mir_power_mode_suspend, mir_power_mode_off));
1627+
1628+INSTANTIATE_TEST_CASE_P(DisplayConfiguration, DisplayFormatSetting,
1629+ ValuesIn(formats));
1630+
1631+TEST_F(DisplayConfigurationTest, client_received_configuration_matches_server_config)
1632+{
1633+ mg::DisplayConfigurationMode hd{{1280, 720}, 60.0};
1634+ mg::DisplayConfigurationMode fhd{{1920, 1080}, 60.0};
1635+ mg::DisplayConfigurationMode proper_size{{1920, 1200}, 60.0};
1636+ mg::DisplayConfigurationMode retina{{3210, 2800}, 60.0};
1637+
1638+ mtd::StubDisplayConfigurationOutput tv{
1639+ mg::DisplayConfigurationOutputId{1},
1640+ {hd, fhd},
1641+ {mir_pixel_format_abgr_8888}};
1642+ mtd::StubDisplayConfigurationOutput monitor{
1643+ mg::DisplayConfigurationOutputId{2},
1644+ {hd, fhd, proper_size, retina},
1645+ {mir_pixel_format_abgr_8888}};
1646+
1647+ std::vector<mg::DisplayConfigurationOutput> outputs{tv, monitor};
1648+
1649+ auto config = std::make_shared<mtd::StubDisplayConfig>(outputs);
1650+
1651+ mock_display.emit_configuration_change_event(config);
1652+ mock_display.wait_for_configuration_change_handler();
1653+
1654+ DisplayClient client{new_connection()};
1655+
1656+ client.connect();
1657+
1658+ auto client_config = client.get_base_config();
1659+ auto server_config = server.the_display()->configuration();
1660+
1661+ EXPECT_THAT(client_config.get(), mt::DisplayConfigMatches(std::cref(*server_config)));
1662+
1663+ client.disconnect();
1664+}
1665+
1666+TEST_F(DisplayConfigurationTest, client_receives_correct_mode_information)
1667+{
1668+ mg::DisplayConfigurationMode hd{{1280, 720}, 60.0};
1669+ mg::DisplayConfigurationMode fhd{{1920, 1080}, 60.0};
1670+ mg::DisplayConfigurationMode proper_size{{1920, 1200}, 60.0};
1671+ mg::DisplayConfigurationMode retina{{3210, 2800}, 60.0};
1672+
1673+ mg::DisplayConfigurationOutputId const id{2};
1674+
1675+ std::vector<mg::DisplayConfigurationMode> modes{hd, fhd, proper_size, retina};
1676+
1677+ mtd::StubDisplayConfigurationOutput monitor{
1678+ id,
1679+ modes,
1680+ {mir_pixel_format_abgr_8888}};
1681+
1682+ std::vector<mg::DisplayConfigurationOutput> outputs{monitor};
1683+
1684+ mock_display.emit_configuration_change_event(std::make_shared<mtd::StubDisplayConfig>(outputs));
1685+ mock_display.wait_for_configuration_change_handler();
1686+
1687+ DisplayClient client{new_connection()};
1688+
1689+ client.connect();
1690+
1691+ auto config = client.get_base_config();
1692+
1693+ ASSERT_THAT(mir_display_config_get_num_outputs(config.get()), Eq(1));
1694+
1695+ std::vector<mg::DisplayConfigurationMode> received_modes;
1696+
1697+ auto output = mir_display_config_get_output(config.get(), 0);
1698+
1699+ for (auto i = 0; i < mir_output_get_num_modes(output) ; ++i)
1700+ {
1701+ auto mode = mir_output_get_mode(output, i);
1702+ auto width = mir_output_mode_get_width(mode);
1703+ auto height = mir_output_mode_get_height(mode);
1704+ auto refresh = mir_output_mode_get_refresh_rate(mode);
1705+
1706+ received_modes.push_back(mg::DisplayConfigurationMode{{width, height}, refresh});
1707+ }
1708+
1709+ EXPECT_THAT(received_modes, ContainerEq(modes));
1710+
1711+ client.disconnect();
1712+}
1713+
1714+TEST_F(DisplayConfigurationTest, mode_width_and_height_are_independent_of_orientation)
1715+{
1716+ mg::DisplayConfigurationMode hd{{1280, 720}, 60.0};
1717+ mg::DisplayConfigurationMode fhd{{1920, 1080}, 60.0};
1718+ mg::DisplayConfigurationMode proper_size{{1920, 1200}, 60.0};
1719+ mg::DisplayConfigurationMode retina{{3210, 2800}, 60.0};
1720+
1721+ mg::DisplayConfigurationOutputId const id{2};
1722+
1723+ std::vector<mg::DisplayConfigurationMode> modes{hd, fhd, proper_size, retina};
1724+
1725+ mtd::StubDisplayConfigurationOutput monitor{
1726+ id,
1727+ modes,
1728+ {mir_pixel_format_abgr_8888}};
1729+
1730+ std::vector<mg::DisplayConfigurationOutput> outputs{monitor};
1731+
1732+ std::shared_ptr<mg::DisplayConfiguration> server_config;
1733+ server_config = std::make_shared<mtd::StubDisplayConfig>(outputs);
1734+ mock_display.emit_configuration_change_event(server_config);
1735+ mock_display.wait_for_configuration_change_handler();
1736+
1737+ DisplayClient client{new_connection()};
1738+ client.connect();
1739+
1740+
1741+ DisplayConfigMatchingContext context;
1742+ context.matcher = [&server_config](MirDisplayConfig* conf)
1743+ {
1744+ EXPECT_THAT(conf, mt::DisplayConfigMatches(std::cref(*server_config)));
1745+ };
1746+
1747+ mir_connection_set_display_config_change_callback(
1748+ client.connection,
1749+ &new_display_config_matches,
1750+ &context);
1751+
1752+ for (auto const orientation :
1753+ {mir_orientation_normal, mir_orientation_left, mir_orientation_inverted, mir_orientation_right})
1754+ {
1755+ server_config = server.the_display()->configuration();
1756+ server_config->for_each_output(
1757+ [orientation](mg::UserDisplayConfigurationOutput& output)
1758+ {
1759+ output.orientation = orientation;
1760+ });
1761+ server.the_display_configuration_controller()->set_base_configuration(server_config);
1762+
1763+ EXPECT_TRUE(context.done.wait_for(std::chrono::seconds{10}));
1764+ context.done.reset();
1765+
1766+ auto config = client.get_base_config();
1767+ ASSERT_THAT(mir_display_config_get_num_outputs(config.get()), Eq(1));
1768+
1769+ std::vector<mg::DisplayConfigurationMode> received_modes;
1770+
1771+ auto output = mir_display_config_get_output(config.get(), 0);
1772+
1773+ for (auto i = 0; i < mir_output_get_num_modes(output) ; ++i)
1774+ {
1775+ auto mode = mir_output_get_mode(output, i);
1776+ auto width = mir_output_mode_get_width(mode);
1777+ auto height = mir_output_mode_get_height(mode);
1778+ auto refresh = mir_output_mode_get_refresh_rate(mode);
1779+
1780+ received_modes.push_back(mg::DisplayConfigurationMode{{width, height}, refresh});
1781+ }
1782+
1783+ EXPECT_THAT(received_modes, ContainerEq(modes));
1784+ }
1785+
1786+ client.disconnect();
1787+}
1788+
1789+TEST_F(DisplayConfigurationTest, output_position_is_independent_of_orientation)
1790+{
1791+ std::array<mir::geometry::Point, 3> const positions = {{
1792+ mir::geometry::Point{-100, 10},
1793+ mir::geometry::Point{100, 10000},
1794+ mir::geometry::Point{-100, 10}
1795+ }};
1796+
1797+ std::shared_ptr<mg::DisplayConfiguration> server_config = server.the_display()->configuration();
1798+ server_config->for_each_output(
1799+ [position = positions.begin()](mg::UserDisplayConfigurationOutput& output) mutable
1800+ {
1801+ output.top_left = *position;
1802+ ++position;
1803+ });
1804+ server.the_display_configuration_controller()->set_base_configuration(server_config);
1805+
1806+ DisplayClient client{new_connection()};
1807+
1808+ client.connect();
1809+
1810+ DisplayConfigMatchingContext context;
1811+ context.matcher = [&server_config](MirDisplayConfig* conf)
1812+ {
1813+ EXPECT_THAT(conf, mt::DisplayConfigMatches(std::cref(*server_config)));
1814+ };
1815+
1816+ mir_connection_set_display_config_change_callback(
1817+ client.connection,
1818+ &new_display_config_matches,
1819+ &context);
1820+
1821+ for (auto const orientation :
1822+ {mir_orientation_normal, mir_orientation_left, mir_orientation_inverted, mir_orientation_right})
1823+ {
1824+ server_config = server.the_display()->configuration();
1825+ server_config->for_each_output(
1826+ [orientation](mg::UserDisplayConfigurationOutput& output)
1827+ {
1828+ output.orientation = orientation;
1829+ });
1830+ server.the_display_configuration_controller()->set_base_configuration(server_config);
1831+
1832+ EXPECT_TRUE(context.done.wait_for(std::chrono::seconds{10}));
1833+ context.done.reset();
1834+
1835+ auto config = client.get_base_config();
1836+
1837+ auto position = positions.begin();
1838+ for (auto i = 0; i < mir_display_config_get_num_outputs(config.get()); ++i)
1839+ {
1840+ auto output = mir_display_config_get_output(config.get(), i);
1841+
1842+ EXPECT_THAT(mir_output_get_position_x(output), Eq(position->x.as_int()));
1843+ EXPECT_THAT(mir_output_get_position_y(output), Eq(position->y.as_int()));
1844+
1845+ ++position;
1846+ }
1847+ }
1848+
1849+ client.disconnect();
1850+}
1851+
1852+TEST_F(DisplayConfigurationTest, client_receives_correct_output_positions)
1853+{
1854+ std::array<mir::geometry::Point, 3> const positions = {{
1855+ mir::geometry::Point{-100, 10},
1856+ mir::geometry::Point{100, 10000},
1857+ mir::geometry::Point{-100, 10}
1858+ }};
1859+
1860+ std::shared_ptr<mg::DisplayConfiguration> server_config = server.the_display()->configuration();
1861+ server_config->for_each_output(
1862+ [position = positions.begin()](mg::UserDisplayConfigurationOutput& output) mutable
1863+ {
1864+ output.top_left = *position;
1865+ ++position;
1866+ });
1867+
1868+ DisplayClient client{new_connection()};
1869+
1870+ client.connect();
1871+
1872+ DisplayConfigMatchingContext context;
1873+ context.matcher = [server_config](MirDisplayConfig* conf)
1874+ {
1875+ EXPECT_THAT(conf, mt::DisplayConfigMatches(std::cref(*server_config)));
1876+ };
1877+
1878+ mir_connection_set_display_config_change_callback(
1879+ client.connection,
1880+ &new_display_config_matches,
1881+ &context);
1882+
1883+ server.the_display_configuration_controller()->set_base_configuration(server_config);
1884+
1885+ EXPECT_TRUE(context.done.wait_for(std::chrono::seconds{10}));
1886+
1887+ auto config = client.get_base_config();
1888+
1889+ auto position = positions.begin();
1890+ for (auto i = 0; i < mir_display_config_get_num_outputs(config.get()); ++i)
1891+ {
1892+ auto output = mir_display_config_get_output(config.get(), i);
1893+
1894+ EXPECT_THAT(mir_output_get_position_x(output), Eq(position->x.as_int()));
1895+ EXPECT_THAT(mir_output_get_position_y(output), Eq(position->y.as_int()));
1896+
1897+ ++position;
1898+ }
1899+
1900+ client.disconnect();
1901+}
1902
1903=== modified file 'tests/mir_test/display_config_matchers.cpp'
1904--- tests/mir_test/display_config_matchers.cpp 2016-01-29 08:18:22 +0000
1905+++ tests/mir_test/display_config_matchers.cpp 2016-02-26 07:01:49 +0000
1906@@ -20,6 +20,7 @@
1907 #include "mir/graphics/display_configuration.h"
1908 #include "mir_protobuf.pb.h"
1909 #include "mir_toolkit/client_types.h"
1910+#include "mir_toolkit/mir_display_configuration.h"
1911 #include <gtest/gtest.h>
1912
1913 namespace mg = mir::graphics;
1914@@ -30,6 +31,18 @@
1915 namespace
1916 {
1917
1918+size_t find_mode_index(MirOutput const* output, MirOutputMode const* mode)
1919+{
1920+ for (int i = 0; i < mir_output_get_num_modes(output); ++i)
1921+ {
1922+ if (mir_output_get_mode(output, i) == mode)
1923+ {
1924+ return i;
1925+ }
1926+ }
1927+ return static_cast<size_t>(-1);
1928+}
1929+
1930 class TestDisplayConfiguration : public mg::DisplayConfiguration
1931 {
1932 public:
1933@@ -168,6 +181,68 @@
1934 }
1935 }
1936
1937+ TestDisplayConfiguration(MirDisplayConfig const* config)
1938+ {
1939+ /* Cards; fake it, 'cause we only ever support 1 card at the moment */
1940+ cards.push_back(
1941+ mg::DisplayConfigurationCard{
1942+ mg::DisplayConfigurationCardId{1},
1943+ static_cast<size_t>(mir_display_config_get_max_simultaneous_outputs(config))
1944+ });
1945+
1946+ /* Outputs */
1947+ for (int i = 0; i < mir_display_config_get_num_outputs(config); i++)
1948+ {
1949+ auto const client_output = mir_display_config_get_output(config, i);
1950+ mg::DisplayConfigurationOutput display_output
1951+ {
1952+ mg::DisplayConfigurationOutputId(mir_output_get_id(client_output)),
1953+ mg::DisplayConfigurationCardId(1),
1954+ static_cast<mg::DisplayConfigurationOutputType>(mir_output_get_type(client_output)),
1955+ {},
1956+ {},
1957+ static_cast<uint32_t>(find_mode_index(client_output, mir_output_get_preferred_mode(client_output))),
1958+ geom::Size{mir_output_get_physical_width_mm(client_output),
1959+ mir_output_get_physical_height_mm(client_output)},
1960+ mir_output_get_connection_state(client_output) == mir_output_connection_state_connected,
1961+ mir_output_is_enabled(client_output),
1962+ geom::Point{mir_output_get_position_x(client_output),
1963+ mir_output_get_position_y(client_output)},
1964+ static_cast<uint32_t>(find_mode_index(client_output, (mir_output_get_current_mode(client_output)))),
1965+ mir_output_get_current_pixel_format(client_output),
1966+ mir_output_get_power_mode(client_output),
1967+ mir_output_get_orientation(client_output),
1968+ 1.0f,
1969+ mir_form_factor_monitor
1970+ };
1971+
1972+ /* Modes */
1973+ std::vector<mg::DisplayConfigurationMode> modes;
1974+ for (int n = 0; n < mir_output_get_num_modes(client_output); n++)
1975+ {
1976+ auto const client_mode = mir_output_get_mode(client_output, n);
1977+ modes.push_back(
1978+ {
1979+ geom::Size{
1980+ mir_output_mode_get_width(client_mode),
1981+ mir_output_mode_get_height(client_mode)},
1982+ mir_output_mode_get_refresh_rate(client_mode)
1983+ });
1984+ }
1985+ display_output.modes = modes;
1986+
1987+ /* Pixel formats */
1988+ std::vector<MirPixelFormat> pixel_formats;
1989+ for (int n = 0; n < mir_output_get_num_pixel_formats(client_output); n++)
1990+ {
1991+ pixel_formats.push_back(mir_output_get_pixel_format(client_output, n));
1992+ }
1993+ display_output.pixel_formats = pixel_formats;
1994+
1995+ outputs.push_back(display_output);
1996+ }
1997+ }
1998+
1999 TestDisplayConfiguration(TestDisplayConfiguration const& other)
2000 : mg::DisplayConfiguration(),
2001 cards{other.cards},
2002@@ -323,3 +398,25 @@
2003 TestDisplayConfiguration config2{*display_config2};
2004 return compare_display_configurations(display_config1, config2);
2005 }
2006+
2007+bool mt::compare_display_configurations(MirDisplayConfig const* client_config,
2008+ mg::DisplayConfiguration const& server_config)
2009+{
2010+ TestDisplayConfiguration translated_config{client_config};
2011+ return compare_display_configurations(server_config, translated_config);
2012+}
2013+
2014+bool mt::compare_display_configurations(mg::DisplayConfiguration const& server_config,
2015+ MirDisplayConfig const* client_config)
2016+{
2017+ TestDisplayConfiguration translated_config{client_config};
2018+ return compare_display_configurations(server_config, translated_config);
2019+}
2020+
2021+bool mt::compare_display_configurations(MirDisplayConfig const* config1,
2022+ MirDisplayConfig const* config2)
2023+{
2024+ TestDisplayConfiguration translated_config_one{config1};
2025+ TestDisplayConfiguration translated_config_two{config2};
2026+ return compare_display_configurations(translated_config_one, translated_config_two);
2027+}
2028
2029=== modified file 'tests/mir_test_doubles/stub_display_configuration.cpp'
2030--- tests/mir_test_doubles/stub_display_configuration.cpp 2015-12-03 17:22:33 +0000
2031+++ tests/mir_test_doubles/stub_display_configuration.cpp 2016-02-26 07:01:49 +0000
2032@@ -19,6 +19,7 @@
2033 #include "mir/test/doubles/stub_display_configuration.h"
2034
2035 #include <limits>
2036+#include <boost/throw_exception.hpp>
2037
2038 namespace mtd = mir::test::doubles;
2039
2040@@ -52,6 +53,35 @@
2041 {
2042 }
2043
2044+mtd::StubDisplayConfigurationOutput::StubDisplayConfigurationOutput(
2045+ graphics::DisplayConfigurationOutputId id,
2046+ std::vector<graphics::DisplayConfigurationMode> modes,
2047+ std::vector<MirPixelFormat> formats)
2048+ : DisplayConfigurationOutput{
2049+ id,
2050+ graphics::DisplayConfigurationCardId{0},
2051+ graphics::DisplayConfigurationOutputType::edp,
2052+ formats,
2053+ modes,
2054+ static_cast<uint32_t>(modes.size() - 1),
2055+ {200, 200},
2056+ true,
2057+ true,
2058+ {0, 0},
2059+ 0,
2060+ formats[0],
2061+ mir_power_mode_on,
2062+ mir_orientation_normal,
2063+ 1.0f,
2064+ mir_form_factor_monitor
2065+ }
2066+{
2067+ if (modes.empty())
2068+ {
2069+ BOOST_THROW_EXCEPTION(std::logic_error{"Attempted to create a stub output with no modes"});
2070+ }
2071+}
2072+
2073 mtd::StubDisplayConfig::StubDisplayConfig() :
2074 StubDisplayConfig(3)
2075 {
2076@@ -95,7 +125,7 @@
2077 mtd::StubDisplayConfig::StubDisplayConfig(unsigned int num_displays, std::vector<MirPixelFormat> const& pfs)
2078 {
2079 /* construct a non-trivial dummy display config to send */
2080- int mode_index = 0;
2081+ int mode_index = 1;
2082 for (auto i = 0u; i < num_displays; i++)
2083 {
2084 std::vector<graphics::DisplayConfigurationMode> modes;
2085@@ -131,7 +161,7 @@
2086 geometry::Point top_left{};
2087 graphics::DisplayConfigurationOutput output{
2088 graphics::DisplayConfigurationOutputId{static_cast<int>(i + 1)},
2089- graphics::DisplayConfigurationCardId{static_cast<int>(i)},
2090+ graphics::DisplayConfigurationCardId{1},
2091 graphics::DisplayConfigurationOutputType::vga,
2092 pfs,
2093 connected(i) ? modes : std::vector<graphics::DisplayConfigurationMode>{},
2094@@ -148,14 +178,13 @@
2095 };
2096
2097 outputs.push_back(output);
2098-
2099- graphics::DisplayConfigurationCard card{
2100- graphics::DisplayConfigurationCardId{static_cast<int>(i)},
2101- i + 1
2102- };
2103-
2104- cards.push_back(card);
2105 }
2106+ graphics::DisplayConfigurationCard card{
2107+ graphics::DisplayConfigurationCardId{1},
2108+ 5
2109+ };
2110+
2111+ cards.push_back(card);
2112 }
2113
2114 mtd::StubDisplayConfig::StubDisplayConfig(std::vector<geometry::Rectangle> const& rects)

Subscribers

People subscribed via source and target branches