Mir

Merge lp:~raof/mir/waylanding-again into lp:mir

Proposed by Chris Halse Rogers on 2017-08-25
Status: Merged
Approved by: Alan Griffiths on 2017-09-07
Approved revision: 4217
Merged at revision: 4244
Proposed branch: lp:~raof/mir/waylanding-again
Merge into: lp:mir
Diff against target: 4937 lines (+4487/-18)
32 files modified
CMakeLists.txt (+12/-0)
debian/control (+1/-0)
examples/CMakeLists.txt (+9/-0)
examples/wayland_client.c (+391/-0)
include/platform/mir/graphics/egl_extensions.h (+11/-0)
include/platform/mir/graphics/wayland_allocator.h (+45/-0)
include/server/mir/frontend/buffer_stream.h (+1/-0)
include/test/mir/test/doubles/mock_egl.h (+7/-0)
src/CMakeLists.txt (+1/-0)
src/include/server/mir/compositor/buffer_stream.h (+0/-1)
src/include/server/mir/default_server_configuration.h (+2/-0)
src/include/server/mir/server_configuration.h (+1/-0)
src/platform/graphics/CMakeLists.txt (+1/-0)
src/platform/graphics/egl_extensions.cpp (+34/-1)
src/platforms/mesa/server/CMakeLists.txt (+2/-0)
src/platforms/mesa/server/buffer_allocator.cpp (+231/-0)
src/platforms/mesa/server/buffer_allocator.h (+9/-1)
src/platforms/mesa/server/kms/CMakeLists.txt (+2/-0)
src/platforms/mesa/server/kms/platform.cpp (+14/-0)
src/protocol/CMakeLists.txt (+28/-0)
src/protocol/wrapper_generator.cpp (+509/-0)
src/server/CMakeLists.txt (+2/-0)
src/server/display_server.cpp (+11/-3)
src/server/frontend/CMakeLists.txt (+2/-0)
src/server/frontend/wayland/CMakeLists.txt (+14/-0)
src/server/frontend/wayland/core_generated_interfaces.h (+1189/-0)
src/server/frontend/wayland/wayland_connector.cpp (+1785/-0)
src/server/frontend/wayland/wayland_connector.h (+83/-0)
src/server/frontend/wayland/wayland_default_configuration.cpp (+39/-0)
src/server/symbols.map (+1/-0)
tests/mir_test_doubles/mock_egl.cpp (+48/-1)
tests/mir_test_doubles/nested_mock_egl.cpp (+2/-11)
To merge this branch: bzr merge lp:~raof/mir/waylanding-again
Reviewer Review Type Date Requested Status
Alan Griffiths 2017-08-25 Approve on 2017-09-07
Mir CI Bot continuous-integration Approve on 2017-09-07
Review via email: mp+329566@code.launchpad.net

Commit message

First round of Wayland support

This is sufficient to
a) Not break unrelated tests, and
b) Provide enough protocol to run es2gears_wayland
c) Provide input support to Wayland clients

To post a comment you must log in.
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:4177
https://mir-jenkins.ubuntu.com/job/mir-ci/3582/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4905/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5127
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5116
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5116
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5116
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4944/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4944/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-25
4178. By Chris Halse Rogers on 2017-08-25

Revert miscellaneous detritus that got accumulated

4179. By Chris Halse Rogers on 2017-08-25

Add missing wayland_allocator.h

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

FAILED: Continuous integration, rev:4179
https://mir-jenkins.ubuntu.com/job/mir-ci/3583/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4906/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5128
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5117
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5117
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5117
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4945/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4945/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-25
4180. By Chris Halse Rogers on 2017-08-25

Wayland: Drop unused Mir-specific protocol

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

FAILED: Continuous integration, rev:4180
https://mir-jenkins.ubuntu.com/job/mir-ci/3584/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4907/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5129
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5118
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5118
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5118
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4946/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4946/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-28
4181. By Chris Halse Rogers on 2017-08-28

examples/wayland_client.c: Drop unused Mir-wayland-protocol #include

4182. By Chris Halse Rogers on 2017-08-28

examples/wayland-client.c: Actually construct a window.

It now actually draws stuff that you can see!

4183. By Chris Halse Rogers on 2017-08-28

Wayland: Handle ShmBuffer frame events properly

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

FAILED: Continuous integration, rev:4183
https://mir-jenkins.ubuntu.com/job/mir-ci/3588/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4911/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5136
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5125
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5125
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5125
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4950/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4950/console

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

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

FAILED: Continuous integration, rev:4183
https://mir-jenkins.ubuntu.com/job/mir-ci/3589/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4912/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5137
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5126
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5126
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5126
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4951/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4951/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-28
4184. By Chris Halse Rogers on 2017-08-28

Wayland: Remove some more debug logging

4185. By Chris Halse Rogers on 2017-08-28

Wayland: Even more Mir-protocol-ectomy

4186. By Chris Halse Rogers on 2017-08-28

Wayland: Initialise pointer-button tracking set.

Otherwise the first button press is likely to crash the server!

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

FAILED: Continuous integration, rev:4185
https://mir-jenkins.ubuntu.com/job/mir-ci/3590/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4913/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5138
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5127
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5127
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5127
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4952/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4952/console

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

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

FAILED: Continuous integration, rev:4186
https://mir-jenkins.ubuntu.com/job/mir-ci/3591/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4915/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5140
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5129
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5129
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5129
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4954/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4954/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-29
4187. By Chris Halse Rogers on 2017-08-29

WaylandExecutor: Clean up event source on eventloop destruction

4188. By Chris Halse Rogers on 2017-08-29

mgm::BufferAllocator: Remove unused destruction_listener member.

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

FAILED: Continuous integration, rev:4188
https://mir-jenkins.ubuntu.com/job/mir-ci/3593/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4917/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5142
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5131
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5131
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5131
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4956
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4956/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4956
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4956/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4956
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4956/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4956
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4956/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4956
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4956/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4956/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4956/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4956
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4956/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-29
4189. By Chris Halse Rogers on 2017-08-29

build: Silence -Wpsabi on ARM.

This is a shiny new warning in GCC 7.1, warning about them fixing an ABI bug that
has resulted in the ARM ABI changing.

There's nothing we can do about this, except rebuild everything with GCC 7.1.

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

FAILED: Continuous integration, rev:4189
https://mir-jenkins.ubuntu.com/job/mir-ci/3594/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4918/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5132
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5132
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5132
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4957/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4957/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4957/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4957/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4957/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4957/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4957/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4957
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4957/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
Chris Halse Rogers (raof) wrote :

Oh, balls.

Cross-compilation with generated binaries. Sigh.

Gerry Boland (gerboland) wrote :

+class WaylandBuffer :
+ void gl_bind_to_texture() override
+ for (auto&& frame : frames)
+ {
+ auto framer = std::move(frame);
+ executor->spawn(
+ [frame = framer.release(), deleter = framer.get_deleter()]()
+ {
+ wl_callback_send_done(frame, 0);
+ wl_client_flush(wl_resource_get_client(frame));
+ deleter(frame);
+ });
+ }
+ frames.clear();

More a question of intent: if a client has no new frame to draw, are we doing wrong to delete the frame on the server? I would expect we only delete a frame when we have got a new one from the client.

Or instead do we tell the client, compositor has released the frame, and client can then specify that buffer be re-used? That seems a bit wasteful. /me trying to interpret the buffer exchange design from wayland.xml

It's the fact you need the Executor just to deal with frame release, that made me bring this up.

+ struct DestructionShim
+ {
+ std::shared_ptr<std::mutex> const mutex = std::make_shared<std::mutex>();
The way you're sharing this mutex between this and the WaylandBuffer is a bit peculiar looking, but I suspect unavoidable, as you need the mutex for the on_buffer_destroyed callback. You *could* use the void*, but what you're doing is indeed cleaner.

+ if (dpy == EGL_NO_DISPLAY)
+ BOOST_THROW_EXCEPTION((std::runtime_error{"Fuck"}));
Mir has been rated PG13 due to its low expletive, violence and sexual content, please don't jeopardise that. The kids are where its at for all that sweet merchandising profit.

+++ src/platforms/mesa/server/kms/platform.cpp
does this file need to change? I only see header files being added.

+++ src/protocol/wrapper_generator.cpp
Missing licence.

to be continued...

lp:~raof/mir/waylanding-again updated on 2017-08-29
4190. By Chris Halse Rogers on 2017-08-29

Ahem.

Oops. I thought I'd removed all of that aggression before commiting.

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

FAILED: Continuous integration, rev:4190
https://mir-jenkins.ubuntu.com/job/mir-ci/3602/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4926/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5151
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5141
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5141
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5141
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4965
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4965/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4965
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4965/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4965
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4965/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4965
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4965/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4965
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4965/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4965/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4965/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4965
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4965/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:4190
https://mir-jenkins.ubuntu.com/job/mir-ci/3603/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4927/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5152
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5142
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5142
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5142
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4966/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4966/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-30
4191. By Chris Halse Rogers on 2017-08-30

Copyright header for wayland_allocator.h

4192. By Chris Halse Rogers on 2017-08-30

Copyright header for wrapper_generator.cpp

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

FAILED: Continuous integration, rev:4190
https://mir-jenkins.ubuntu.com/job/mir-ci/3604/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4928/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5153
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5143
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4967
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4967/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4967
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4967/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4967
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4967/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4967
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4967/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4967
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4967/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4967/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4967/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4967
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4967/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:4190
https://mir-jenkins.ubuntu.com/job/mir-ci/3605/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4929/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5154
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5144
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5144
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5144
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4968/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4968
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4968/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4968
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4968/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4968
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4968/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4968
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4968/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4968/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4968/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4968
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4968/artifact/output/*zip*/output.zip

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

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

FAILED: Continuous integration, rev:4192
https://mir-jenkins.ubuntu.com/job/mir-ci/3606/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4930/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5155
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5145
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5145
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5145
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4969
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4969/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4969
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4969/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4969
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4969/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4969
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4969/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4969
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4969/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4969/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4969/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4969
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4969/artifact/output/*zip*/output.zip

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-31
4193. By Chris Halse Rogers on 2017-08-31

Wayland: Commit the generated wrapper header.

This allows us to avoid cross-compilation worries, which is a bit hairy with CMake.
The header is also not going to change over time in the absence of generator changes,
so we can happily recommit the header every time we change the generator.

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

PASSED: Continuous integration, rev:4193
https://mir-jenkins.ubuntu.com/job/mir-ci/3615/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4942
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5167
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5157
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5157
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5157
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4981/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4981
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4981/artifact/output/*zip*/output.zip

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

review: Approve (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-08-31
4194. By Chris Halse Rogers on 2017-08-31

Wayland: Rework frame notification to be protocol-compliant.

The set of requested frame notification callbacks is a wl_surface property, not a
wl_buffer property.

That is, if a client commits a wl_buffer and a frame callback, then commits *another*
wl_buffer and frame callback before the compositor has triggered the first callback
the first access should trigger *both* frame callbacks, in order requested.

4195. By Chris Halse Rogers on 2017-08-31

Wayland: Make wl_buffer submission protocol-compliant.

A wl_surface is documented to operate with double-buffered content; that is, in mailbox mode.
Subsequent wl_buffer commits should supercede previous ones, rather than being queued.

So, set the BufferStream to framedropping mode.

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

PASSED: Continuous integration, rev:4195
https://mir-jenkins.ubuntu.com/job/mir-ci/3616/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4943
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5168
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5158
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5158
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5158
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4982/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4982
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4982/artifact/output/*zip*/output.zip

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

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

+ DestructionShim* shim;
+
+ shim = wl_container_of(notifier, shim, destruction_listener);

I thought we were passing an uninitialized value to a function, but no, its a nasty lowercase MACRO imitating a function, but doing something a function can't!!

I guess this isn't something we can fix.

Alan Griffiths (alan-griffiths) wrote :

[terminal 1]
$ bin/miral-shell

[terminal 2]
$ bin/mir_demo_client_wayland
...
^C

The server crashes (this doesn't happen with using Shift-Alt-F4 to send SIGTERM).

~~~~

+ * Copyright © 2015 Canonical LTD

Really 2015? We use "Ltd." elsewhere.

~~~~

+ GNU General Public License version 3

2 or 3

~~~~

+#include "../../../../include/server/mir/executor.h"

1. Not the approved way to reach a header.
2. Platforms shouldn't be depending on mirserver (yes I realize it's an interface)

~~~~

+#include "../../scene/mediating_display_changer.h"

1. Not the approved way to reach a header.
2. The frontend shouldn't be dependent on scene internals. (It should define an abstraction that scene can implement.)

~~~~

I just merged to trunk and "built" and got...

/home/alan/display_server/mir1/src/server/frontend/wayland/wayland_connector.cpp:21:10: fatal error: 'core_generated_interfaces.h' file not found
#include "core_generated_interfaces.h"
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

"make refresh-wayland-wrapper" fixes that, but something isn't quite right.

review: Needs Fixing
lp:~raof/mir/waylanding-again updated on 2017-09-01
4196. By Chris Halse Rogers on 2017-09-01

mf::BufferStream: Pull resize() method up.

This provides the Wayland frontend to nearly-correctly set the size of its
buffers, as the size of the wl_surface is defined by the size of the
wl_buffer attached to it.

4197. By Chris Halse Rogers on 2017-09-01

Fix copyright header

4198. By Chris Halse Rogers on 2017-09-01

WaylandAllocator: Drop no-longer-used Executor forward declaration and #include

Chris Halse Rogers (raof) wrote :

Heh. Turns out that doing the not-quite-correct-but-near-enough thing is *easier* than I thought; this now also renders at the right size.

lp:~raof/mir/waylanding-again updated on 2017-09-01
4199. By Chris Halse Rogers on 2017-09-01

mf::WaylandConnector: Replace unnecesasry mediating_display_changer.h #include with display_changer.h

Gerry Boland (gerboland) wrote :

Nice work so far, I can bring up wayland glmark and Qt apps using wayland, and they render ok.

Input is problematic. Seems Qt apps not getting input events. And moving mouse over glmark quickly causes server lockup.

Alan Griffiths (alan-griffiths) wrote :

I'm off work until Tuesday, so won't be reviewing in detail until then. But looks like my "Needs Fixings" are being fixed.

review: Abstain
lp:~raof/mir/waylanding-again updated on 2017-09-04
4200. By Chris Halse Rogers on 2017-09-03

WaylandConnector: Drop (unused) GlobalEventSender.

We weren't hooking up output hotplug events anyway, so there's no need to
bring it in and then ignore it.

4201. By Chris Halse Rogers on 2017-09-04

Wayland: Fix WlShmBuffer lifetime issues.

Of course, wl_buffers being destroyed on client disconnect doesn't just hit the hardware-accelerated
buffers. Do the same dance here so that we don't crash when accessing a freed buffer on client
disconnect.

Chris Halse Rogers (raof) wrote :

Hah! The reason why input is problematic is that the *window* is only set to 100x100! You only get input in the top-left-hand corner.

That took altogether too long to figure out.

lp:~raof/mir/waylanding-again updated on 2017-09-04
4202. By Chris Halse Rogers on 2017-09-04

Wayland: Dispatch input events from the eventloop thread.

As with the rest of the things...

4203. By Chris Halse Rogers on 2017-09-04

Wayland: Also update *window* size on buffer submission.

Updating the BufferStream size will get us rendering at the right size, but
we also need to update the window size so that input and such work.

Gerry Boland (gerboland) wrote :

Little patch to make it compile on artful: https://pastebin.ubuntu.com/25464701/

Input is more stable now, but something broke Qt app rendering - colours are there, but each line offset by a little, as if window width not quite right.

lp:~raof/mir/waylanding-again updated on 2017-09-05
4204. By Chris Halse Rogers on 2017-09-05

Wayland: Fix WlShmBuffer lifetime handling.

A single wl_buffer can be attached to multiple wl_surface-s or a single wl_surface
multiple times. We need to handle this case and only allocate a single WlShmSurface
to be shared between all the relevant BufferStreams, as we must only send a
wl_buffer.release() event after *all* users of the buffer have relinquished ownership.

Hang this on the existing DestructionShim infrastructure.

4205. By Chris Halse Rogers on 2017-09-05

WlSeat: Broadcast seat capabilities on bind.

We need to broadcast what capabilities the wl_seat has, otherwise Qt (quite correctly)
never tries to bind to a pointer or keyboard.

4206. By Chris Halse Rogers on 2017-09-05

Wayland: We don't want to send a key-down immediately after each key-up

4207. By Chris Halse Rogers on 2017-09-05

Wayland: Add bonus comment

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

FAILED: Continuous integration, rev:4196
https://mir-jenkins.ubuntu.com/job/mir-ci/3628/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4957/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5182
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5172
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5172
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5172
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4996/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4996
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4996/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4996/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4996
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4996/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4996
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4996/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4996/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4996
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4996/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4996
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4996/artifact/output/*zip*/output.zip

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

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

I just merged to trunk and "built" and got...

../libmirsharedmesaservercommon-static.a(buffer_allocator.cpp.o): In function `WaylandBuffer':
/home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:346: undefined reference to `wl_resource_get_destroy_listener'
/home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:365: undefined reference to `wl_resource_add_destroy_listener'
../libmirsharedmesaservercommon-static.a(buffer_allocator.cpp.o): In function `~WaylandBuffer':
/home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:405: undefined reference to `wl_resource_queue_event'
/home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:406: undefined reference to `wl_resource_get_destroy_listener'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
src/platforms/mesa/server/x11/CMakeFiles/mirplatformservermesax11.dir/build.make:105: recipe for target 'lib/server-modules/server-mesa-x11.so.13' failed
make[2]: *** [lib/server-modules/server-mesa-x11.so.13] Error 1
CMakeFiles/Makefile2:1823: recipe for target 'src/platforms/mesa/server/x11/CMakeFiles/mirplatformservermesax11.dir/all' failed

Once again "make refresh-wayland-wrapper" fixes that, but something isn't quite right.

Alan Griffiths (alan-griffiths) wrote :

> I just merged to trunk and "built" and got...
>
> ../libmirsharedmesaservercommon-static.a(buffer_allocator.cpp.o): In function
> `WaylandBuffer':
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:3
> 46: undefined reference to `wl_resource_get_destroy_listener'
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:3
> 65: undefined reference to `wl_resource_add_destroy_listener'
> ../libmirsharedmesaservercommon-static.a(buffer_allocator.cpp.o): In function
> `~WaylandBuffer':
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:4
> 05: undefined reference to `wl_resource_queue_event'
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:4
> 06: undefined reference to `wl_resource_get_destroy_listener'
> clang: error: linker command failed with exit code 1 (use -v to see
> invocation)
> src/platforms/mesa/server/x11/CMakeFiles/mirplatformservermesax11.dir/build.ma
> ke:105: recipe for target 'lib/server-modules/server-mesa-x11.so.13' failed
> make[2]: *** [lib/server-modules/server-mesa-x11.so.13] Error 1
> CMakeFiles/Makefile2:1823: recipe for target
> 'src/platforms/mesa/server/x11/CMakeFiles/mirplatformservermesax11.dir/all'
> failed
>
> Once again "make refresh-wayland-wrapper" fixes that, but something isn't
> quite right.

Loads of tests fail, and (possibly related):

$ cmake-build-debug/bin/miral-shell
...
wl_global_create: implemented version for 'wl_seat' higher than interface version (6 > 5)
ERROR: /home/alan/display_server/mir/src/server/frontend/wayland/wayland_connector.cpp(1026): Throw in function mir::frontend::WlSeat::WlSeat(wl_display *, const std::shared_ptr<mir::Executor> &)
Dynamic exception type: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::runtime_error> >
std::exception::what: Failed to export wl_seat interface

Segmentation fault (core dumped)

Alan Griffiths (alan-griffiths) wrote :

> I just merged to trunk and "built" and got...
>
> ../libmirsharedmesaservercommon-static.a(buffer_allocator.cpp.o): In function
> `WaylandBuffer':
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:3
> 46: undefined reference to `wl_resource_get_destroy_listener'
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:3
> 65: undefined reference to `wl_resource_add_destroy_listener'
> ../libmirsharedmesaservercommon-static.a(buffer_allocator.cpp.o): In function
> `~WaylandBuffer':
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:4
> 05: undefined reference to `wl_resource_queue_event'
> /home/alan/display_server/mir/src/platforms/mesa/server/buffer_allocator.cpp:4
> 06: undefined reference to `wl_resource_get_destroy_listener'
> clang: error: linker command failed with exit code 1 (use -v to see
> invocation)
> src/platforms/mesa/server/x11/CMakeFiles/mirplatformservermesax11.dir/build.ma
> ke:105: recipe for target 'lib/server-modules/server-mesa-x11.so.13' failed
> make[2]: *** [lib/server-modules/server-mesa-x11.so.13] Error 1
> CMakeFiles/Makefile2:1823: recipe for target
> 'src/platforms/mesa/server/x11/CMakeFiles/mirplatformservermesax11.dir/all'
> failed
>
> Once again "make refresh-wayland-wrapper" fixes that, but something isn't
> quite right.

Loads of tests fail, and (possibly related):

$ cmake-build-debug/bin/miral-shell
...
wl_global_create: implemented version for 'wl_seat' higher than interface version (6 > 5)
ERROR: /home/alan/display_server/mir/src/server/frontend/wayland/wayland_connector.cpp(1026): Throw in function mir::frontend::WlSeat::WlSeat(wl_display *, const std::shared_ptr<mir::Executor> &)
Dynamic exception type: boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::runtime_error> >
std::exception::what: Failed to export wl_seat interface

Segmentation fault (core dumped)

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

FAILED: Continuous integration, rev:4207
https://mir-jenkins.ubuntu.com/job/mir-ci/3629/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4958/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5186
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5174
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5174
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5174
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/4997/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/4997/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/4997/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/4997/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/4997/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/4997/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4997
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/4997/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/4997/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-09-06
4208. By Chris Halse Rogers on 2017-09-06

build: Prevent “make clean” from deleting core_generated_interfaces.h.

add_custom_command() causes the output file to be treated as a generated file and
hence deleted on clean. We don't want this, as it's committed to VCS.

Use add_custom_target(), which *just* adds a generation target and doesn't try
to clean up on clean.

4209. By Chris Halse Rogers on 2017-09-06

WlSeat: Only advertise wl_seat version 5.

It seems that Xenial only has wl_seat version 5, and so bails if we try to export v6.

We don't actually expose any of the additional properties in v6, so it's painless to just export v5.

4210. By Chris Halse Rogers on 2017-09-06

Remove vestigial LifetimeGuard class

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

PASSED: Continuous integration, rev:4210
https://mir-jenkins.ubuntu.com/job/mir-ci/3631/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4967
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5195
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5183
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5183
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5183
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5006/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5006
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5006/artifact/output/*zip*/output.zip

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

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

Close, just a few nits...

=== modified file 'tests/mir_test_framework/CMakeLists.txt'
--- tests/mir_test_framework/CMakeLists.txt 2017-08-30 11:59:08 +0000
+++ tests/mir_test_framework/CMakeLists.txt 2017-09-06 06:18:29 +0000
@@ -85,6 +85,7 @@

 target_link_libraries(mir-test-framework-static

+ mirserver

Not needed

~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+/*
+ * Copyright © 2015 Canonical Ltd.

Probably want 2017 too.

+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3,

2 or 3

+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Christopher James Halse Rogers <email address hidden>
+ */
+
+#include "mir/default_server_configuration.h"
+#include "wayland_connector.h"
+
+#include "../../scene/mediating_display_changer.h"

#include "mir/frontend/display_changer.h"

+#include "mir/graphics/platform.h"
+
+namespace mf = mir::frontend;
+
+std::shared_ptr<mf::Connector>
+ mir::DefaultServerConfiguration::the_wayland_connector()
+{
+ return wayland_connector(
+ [this]() -> std::shared_ptr<mf::Connector>
+ {
+ return std::make_shared<mf::WaylandConnector>(
+ the_frontend_shell(),
+ *the_mediating_display_changer(),

                *the_frontend_display_changer(),

(Do we really want to avoid sharing ownership? Where's the lifetime guarantee?)

+ the_buffer_allocator());
+ });
+}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~

=== added file 'src/server/frontend/wayland/core_generated_interfaces.h'

Could benefit from a header comment to say it is generated.

The generated code uses a lot of reinterpret_cast<> where static_cast<> is all that is needed to downcast from void*.

review: Needs Fixing
Alan Griffiths (alan-griffiths) wrote :

I guess a server crash might be enough to block landing, but this is beyond what we decided was minimal viable feature...

$ bin/miral-app --x11-displays=1200x900 --keymap=gb

Then in the miral-app terminal:

$ QT_QPA_PLATFORM=wayland kate& kate&

Use the mouse to switch to the wayland instance of kate, pull down the file menu then click on the editor panel.

Expect: menu disappears
Actual: server crashes:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::runtime_error> >'
  what(): Setting null buffer is unimplemented

lp:~raof/mir/waylanding-again updated on 2017-09-07
4211. By Chris Halse Rogers on 2017-09-07

Wayland: Handle (mostly) client attaching null wl_buffers

4212. By Chris Halse Rogers on 2017-09-07

build: Drop unnecessary mirserver dependency from mir-test-framework-static

4213. By Chris Halse Rogers on 2017-09-07

Wayland: small improvements to wrapper_generator.

Add a comment to the top of the generated file noting that it is autogenerated and
saying how to regenerate it.

Use static_cast<> rather than reinterpret_cast<> for casting from void*.

4214. By Chris Halse Rogers on 2017-09-07

Wayland: Refresh core_generated_interfaces with new wrapper_generator.

4215. By Chris Halse Rogers on 2017-09-07

Wayland: Fix up copyright header

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

FAILED: Continuous integration, rev:4215
https://mir-jenkins.ubuntu.com/job/mir-ci/3637/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4975/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5203/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5191/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5191/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5191/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5014/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5014/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-09-07
4216. By Chris Halse Rogers on 2017-09-07

Wayland: Warn, rather than crash the server, upon a client requesting an unimplemented buffer offset.

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

FAILED: Continuous integration, rev:4216
https://mir-jenkins.ubuntu.com/job/mir-ci/3638/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/4976/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5204/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5192/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5192/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5192/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5015/console
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5015/console

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

review: Needs Fixing (continuous-integration)
lp:~raof/mir/waylanding-again updated on 2017-09-07
4217. By Chris Halse Rogers on 2017-09-07

Merge trunk, resolving conflict

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

PASSED: Continuous integration, rev:4217
https://mir-jenkins.ubuntu.com/job/mir-ci/3639/
Executed test runs:
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-mir/4977
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/5205
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=artful/5193
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/5193
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=zesty/5193
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=artful/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=zesty/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=artful/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=zesty/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=artful/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=mesa,release=zesty/5016/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5016
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/5016/artifact/output/*zip*/output.zip

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

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

> I guess a server crash might be enough to block landing, but this is beyond
> what we decided was minimal viable feature...
>
> $ bin/miral-app --x11-displays=1200x900 --keymap=gb
>
> Then in the miral-app terminal:
>
> $ QT_QPA_PLATFORM=wayland kate& kate&
>
> Use the mouse to switch to the wayland instance of kate, pull down the file
> menu then click on the editor panel.
>
> Expect: menu disappears
> Actual: server crashes:
> terminate called after throwing an instance of 'boost::exception_detail::clone
> _impl<boost::exception_detail::error_info_injector<std::runtime_error> >'
> what(): Setting null buffer is unimplemented

Was -r 4216 meant to stop this crash? (It is still happening)

Alan Griffiths (alan-griffiths) wrote :

+#include "mir/default_server_configuration.h"
+#include "wayland_connector.h"
+
+#include "../../scene/mediating_display_changer.h"

#include "mir/frontend/display_changer.h"

+#include "mir/graphics/platform.h"
+
+namespace mf = mir::frontend;
+
+std::shared_ptr<mf::Connector>
+ mir::DefaultServerConfiguration::the_wayland_connector()
+{
+ return wayland_connector(
+ [this]() -> std::shared_ptr<mf::Connector>
+ {
+ return std::make_shared<mf::WaylandConnector>(
+ the_frontend_shell(),
+ *the_mediating_display_changer(),

                *the_frontend_display_changer(),

(Do we really want to avoid sharing ownership? Where's the lifetime guarantee?)

+ the_buffer_allocator());
+ });
+}

Alan Griffiths (alan-griffiths) wrote :

> +#include "mir/default_server_configuration.h"
> +#include "wayland_connector.h"
> +
> +#include "../../scene/mediating_display_changer.h"
>
> #include "mir/frontend/display_changer.h"
>
> +#include "mir/graphics/platform.h"
> +
> +namespace mf = mir::frontend;
> +
> +std::shared_ptr<mf::Connector>
> + mir::DefaultServerConfiguration::the_wayland_connector()
> +{
> + return wayland_connector(
> + [this]() -> std::shared_ptr<mf::Connector>
> + {
> + return std::make_shared<mf::WaylandConnector>(
> + the_frontend_shell(),
> + *the_mediating_display_changer(),
>
> *the_frontend_display_changer(),
>
> (Do we really want to avoid sharing ownership? Where's the lifetime
> guarantee?)
>
> + the_buffer_allocator());
> + });
> +}

nm, let's land this and fixup afterwards.

review: Approve
Chris Halse Rogers (raof) wrote :

On Thu, Sep 7, 2017 at 9:08 PM, Alan Griffiths <email address hidden>
wrote:
>> I guess a server crash might be enough to block landing, but this
>> is beyond
>> what we decided was minimal viable feature...
>>
>> $ bin/miral-app --x11-displays=1200x900 --keymap=gb
>>
>> Then in the miral-app terminal:
>>
>> $ QT_QPA_PLATFORM=wayland kate& kate&
>>
>> Use the mouse to switch to the wayland instance of kate, pull down
>> the file
>> menu then click on the editor panel.
>>
>> Expect: menu disappears
>> Actual: server crashes:
>> terminate called after throwing an instance of
>> 'boost::exception_detail::clone
>>
>> _impl<boost::exception_detail::error_info_injector<std::runtime_error>
>> >'
>> what(): Setting null buffer is unimplemented
>
> Was -r 4216 meant to stop this crash? (It is still happening)

Huh. That particular crash *definitely* cannot happen, and I could
happily switch between Kate instances, open menus, and such without
anything crashing.

I wonder what's up.

Chris Halse Rogers (raof) wrote :

On Thu, Sep 7, 2017 at 9:18 PM, Alan Griffiths <email address hidden>
wrote:
> +#include "mir/default_server_configuration.h"
> +#include "wayland_connector.h"
> +
> +#include "../../scene/mediating_display_changer.h"
>
> #include "mir/frontend/display_changer.h"
>
> +#include "mir/graphics/platform.h"
> +
> +namespace mf = mir::frontend;
> +
> +std::shared_ptr<mf::Connector>
> + mir::DefaultServerConfiguration::the_wayland_connector()
> +{
> + return wayland_connector(
> + [this]() -> std::shared_ptr<mf::Connector>
> + {
> + return std::make_shared<mf::WaylandConnector>(
> + the_frontend_shell(),
> + *the_mediating_display_changer(),
>
> *the_frontend_display_changer(),
>
> (Do we really want to avoid sharing ownership? Where's the lifetime
> guarantee?)

The lifetime guarantee is that WaylandConnector does not store any
reference to the mf::DisplayChanger; it's purely used at initialisation
time.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-08-25 11:05:07 +0000
3+++ CMakeLists.txt 2017-09-07 05:58:57 +0000
4@@ -74,6 +74,16 @@
5 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-mismatched-tags")
6 endif()
7
8+# GCC 7.1 fixed a bug in the ARM ABI, which results in some std::vector methods
9+# (among others) generating this warning.
10+#
11+# There's nothing we can do about it; everything just needs to be rebuilt with
12+# GCC 7.1.
13+check_cxx_compiler_flag(-Wpsabi HAS_W_PSABI)
14+if(HAS_W_PSABI)
15+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")
16+endif()
17+
18 option(MIR_USE_LD_GOLD "Enables the \"gold\" linker." OFF)
19 if(MIR_USE_LD_GOLD)
20 set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=gold")
21@@ -206,6 +216,8 @@
22
23 pkg_check_modules(UDEV REQUIRED libudev)
24 pkg_check_modules(GLIB REQUIRED glib-2.0)
25+pkg_check_modules(WAYLAND_SERVER REQUIRED wayland-server)
26+pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
27
28 include_directories (SYSTEM ${GLESv2_INCLUDE_DIRS})
29 include_directories (SYSTEM ${EGL_INCLUDE_DIRS})
30
31=== modified file 'debian/control'
32--- debian/control 2017-08-23 11:56:37 +0000
33+++ debian/control 2017-09-07 05:58:57 +0000
34@@ -31,6 +31,7 @@
35 libudev-dev,
36 libgtest-dev,
37 google-mock (>= 1.6.0+svn437),
38+ libxml++2.6-dev,
39 # only enable valgrind once it's been tested to work on each architecture:
40 valgrind [amd64 i386 armhf arm64],
41 libglib2.0-dev,
42
43=== modified file 'examples/CMakeLists.txt'
44--- examples/CMakeLists.txt 2017-08-30 12:38:21 +0000
45+++ examples/CMakeLists.txt 2017-09-07 05:58:57 +0000
46@@ -274,6 +274,15 @@
47 mirclient
48 )
49
50+include_directories(${MIR_GENERATED_INCLUDE_DIRECTORIES})
51+
52+mir_add_wrapped_executable(mir_demo_client_wayland wayland_client.c)
53+target_link_libraries(mir_demo_client_wayland
54+
55+ ${WAYLAND_CLIENT_LIBRARIES}
56+)
57+
58 mir_add_wrapped_executable(mir_demo_client_screencast screencast.cpp)
59
60 target_link_libraries(mir_demo_client_screencast mirclient)
61+
62
63=== added file 'examples/wayland_client.c'
64--- examples/wayland_client.c 1970-01-01 00:00:00 +0000
65+++ examples/wayland_client.c 2017-09-07 05:58:57 +0000
66@@ -0,0 +1,391 @@
67+/*
68+ * Copyright © 2015 Canonical Ltd.
69+ *
70+ * This program is free software: you can redistribute it and/or modify
71+ * it under the terms of the GNU General Public License version 2 or 3 as
72+ * published by the Free Software Foundation.
73+ *
74+ * This program is distributed in the hope that it will be useful,
75+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
76+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77+ * GNU General Public License for more details.
78+ *
79+ * You should have received a copy of the GNU General Public License
80+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
81+ *
82+ * Author: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
83+ */
84+
85+#ifndef _GNU_SOURCE
86+#define _GNU_SOURCE
87+#endif
88+
89+#include <stdlib.h>
90+#include <string.h>
91+#include <sys/mman.h>
92+#include <sys/types.h>
93+#include <sys/stat.h>
94+#include <fcntl.h>
95+#include <unistd.h>
96+#include <stdio.h>
97+#include <stdbool.h>
98+
99+#include <wayland-client.h>
100+#include <wayland-client-core.h>
101+
102+struct globals
103+{
104+ struct wl_compositor* compositor;
105+ struct wl_shm* shm;
106+ struct wl_seat* seat;
107+ struct wl_output* output;
108+ struct wl_shell* shell;
109+};
110+
111+static void new_global(
112+ void* data,
113+ struct wl_registry* registry,
114+ uint32_t id,
115+ char const* interface,
116+ uint32_t version)
117+{
118+ (void)version;
119+ struct globals* globals = data;
120+
121+ if (strcmp(interface, "wl_compositor") == 0)
122+ {
123+ globals->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 3);
124+ }
125+ else if (strcmp(interface, "wl_shm") == 0)
126+ {
127+ globals->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
128+ // Normally we'd add a listener to pick up the supported formats here
129+ // As luck would have it, I know that argb8888 is the only format we support :)
130+ }
131+ else if (strcmp(interface, "wl_seat") == 0)
132+ {
133+ globals->seat = wl_registry_bind(registry, id, &wl_seat_interface, 4);
134+ }
135+ else if (strcmp(interface, "wl_output") == 0)
136+ {
137+ globals->output = wl_registry_bind(registry, id, &wl_output_interface, 2);
138+ }
139+ else if (strcmp(interface, "wl_shell") == 0)
140+ {
141+ globals->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
142+ }
143+}
144+
145+static void global_remove(
146+ void* data,
147+ struct wl_registry* registry,
148+ uint32_t name)
149+{
150+ (void)data;
151+ (void)registry;
152+ (void)name;
153+}
154+
155+static struct wl_registry_listener const registry_listener = {
156+ .global = new_global,
157+ .global_remove = global_remove
158+};
159+
160+static struct wl_shm_pool*
161+make_shm_pool(struct wl_shm* shm, int size, void **data)
162+{
163+ struct wl_shm_pool *pool;
164+ int fd;
165+
166+ fd = open("/dev/shm", O_TMPFILE | O_RDWR | O_EXCL, S_IRWXU);
167+ if (fd < 0) {
168+ return NULL;
169+ }
170+
171+ posix_fallocate(fd, 0, size);
172+
173+ *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
174+ if (*data == MAP_FAILED) {
175+ close(fd);
176+ return NULL;
177+ }
178+
179+ pool = wl_shm_create_pool(shm, fd, size);
180+
181+ close(fd);
182+
183+ return pool;
184+}
185+
186+struct draw_context
187+{
188+ void* content_area;
189+ struct wl_display* display;
190+ struct wl_surface* surface;
191+ struct wl_callback* new_frame_signal;
192+ struct Buffers
193+ {
194+ struct wl_buffer* buffer;
195+ bool available;
196+ } buffers[4];
197+ bool waiting_for_buffer;
198+};
199+
200+static struct wl_buffer* find_free_buffer(struct draw_context* ctx)
201+{
202+ for (int i = 0; i < 4 ; ++i)
203+ {
204+ if (ctx->buffers[i].available)
205+ {
206+ ctx->buffers[i].available = false;
207+ return ctx->buffers[i].buffer;
208+ }
209+ }
210+ return NULL;
211+}
212+
213+static void draw_new_stuff(void* data, struct wl_callback* callback, uint32_t time);
214+
215+static const struct wl_callback_listener frame_listener =
216+{
217+ .done = &draw_new_stuff
218+};
219+
220+static void update_free_buffers(void* data, struct wl_buffer* buffer)
221+{
222+ struct draw_context* ctx = data;
223+ for (int i = 0; i < 4 ; ++i)
224+ {
225+ if (ctx->buffers[i].buffer == buffer)
226+ {
227+ ctx->buffers[i].available = true;
228+ }
229+ }
230+
231+ if (ctx->waiting_for_buffer)
232+ {
233+ struct wl_callback* fake_frame = wl_display_sync(ctx->display);
234+ wl_callback_add_listener(fake_frame, &frame_listener, ctx);
235+ }
236+
237+ ctx->waiting_for_buffer = false;
238+}
239+
240+static void draw_new_stuff(
241+ void* data,
242+ struct wl_callback* callback,
243+ uint32_t time)
244+{
245+ (void)time;
246+ static unsigned char current_value = 128;
247+ struct draw_context* ctx = data;
248+
249+ wl_callback_destroy(callback);
250+
251+ struct wl_buffer* buffer = find_free_buffer(ctx);
252+ if (!buffer)
253+ {
254+ ctx->waiting_for_buffer = false;
255+ return;
256+ }
257+
258+ memset(ctx->content_area, current_value, 400 * 400 * 4);
259+ ++current_value;
260+
261+ ctx->new_frame_signal = wl_surface_frame(ctx->surface);
262+ wl_callback_add_listener(ctx->new_frame_signal, &frame_listener, ctx);
263+ wl_surface_attach(ctx->surface, buffer, 0, 0);
264+ wl_surface_commit(ctx->surface);
265+}
266+
267+static struct wl_buffer_listener const buffer_listener = {
268+ .release = update_free_buffers
269+};
270+
271+void mouse_enter(
272+ void *data,
273+ struct wl_pointer *wl_pointer,
274+ uint32_t serial,
275+ struct wl_surface *surface,
276+ wl_fixed_t surface_x,
277+ wl_fixed_t surface_y)
278+{
279+ (void)data;
280+ (void)wl_pointer;
281+ (void)serial;
282+ (void)surface;
283+ printf("Received mouse_enter event: (%f, %f)\n",
284+ wl_fixed_to_double(surface_x),
285+ wl_fixed_to_double(surface_y));
286+}
287+
288+void mouse_leave(
289+ void *data,
290+ struct wl_pointer *wl_pointer,
291+ uint32_t serial,
292+ struct wl_surface *surface)
293+{
294+ (void)data;
295+ (void)wl_pointer;
296+ (void)serial;
297+ (void)surface;
298+ printf("Received mouse_exit event\n");
299+}
300+
301+void mouse_motion(
302+ void *data,
303+ struct wl_pointer *wl_pointer,
304+ uint32_t time,
305+ wl_fixed_t surface_x,
306+ wl_fixed_t surface_y)
307+{
308+ (void)data;
309+ (void)wl_pointer;
310+
311+ printf("Received motion event: (%f, %f) @ %i\n",
312+ wl_fixed_to_double(surface_x),
313+ wl_fixed_to_double(surface_y),
314+ time);
315+}
316+
317+void mouse_button(
318+ void *data,
319+ struct wl_pointer *wl_pointer,
320+ uint32_t serial,
321+ uint32_t time,
322+ uint32_t button,
323+ uint32_t state)
324+{
325+ (void)serial;
326+ (void)data;
327+ (void)wl_pointer;
328+
329+ printf("Received button event: Button %i, state %i @ %i\n",
330+ button,
331+ state,
332+ time);
333+}
334+
335+void mouse_axis(
336+ void *data,
337+ struct wl_pointer *wl_pointer,
338+ uint32_t time,
339+ uint32_t axis,
340+ wl_fixed_t value)
341+{
342+ (void)data;
343+ (void)wl_pointer;
344+
345+ printf("Received axis event: axis %i, value %f @ %i\n",
346+ axis,
347+ wl_fixed_to_double(value),
348+ time);
349+}
350+
351+
352+
353+static struct wl_pointer_listener const pointer_listener = {
354+ .enter = &mouse_enter,
355+ .leave = &mouse_leave,
356+ .motion = &mouse_motion,
357+ .button = &mouse_button,
358+ .axis = &mouse_axis
359+};
360+
361+static void output_geometry(void *data,
362+ struct wl_output *wl_output,
363+ int32_t x,
364+ int32_t y,
365+ int32_t physical_width,
366+ int32_t physical_height,
367+ int32_t subpixel,
368+ const char *make,
369+ const char *model,
370+ int32_t transform)
371+{
372+ (void)data;
373+ (void)wl_output;
374+ (void)subpixel;
375+ (void)make;
376+ (void)model;
377+ (void)transform;
378+ printf("Got geometry: (%imm × %imm)@(%i, %i)\n", physical_width, physical_height, x, y);
379+}
380+
381+static void output_mode(void *data,
382+ struct wl_output *wl_output,
383+ uint32_t flags,
384+ int32_t width,
385+ int32_t height,
386+ int32_t refresh)
387+{
388+ (void)data;
389+ (void)wl_output;
390+ printf("Got mode: %i×%i@%i (flags: %i)\n", width, height, refresh, flags);
391+}
392+
393+static void output_done(void* data, struct wl_output* wl_output)
394+{
395+ (void)data;
396+ (void)wl_output;
397+ printf("Output events done\n");
398+}
399+
400+static void output_scale(void* data, struct wl_output* wl_output, int32_t factor)
401+{
402+ (void)data;
403+ (void)wl_output;
404+ printf("Output scale: %i\n", factor);
405+}
406+
407+static struct wl_output_listener const output_listener = {
408+ .geometry = &output_geometry,
409+ .mode = &output_mode,
410+ .done = &output_done,
411+ .scale = &output_scale,
412+};
413+
414+int main()
415+{
416+ struct wl_display* display = wl_display_connect(NULL);
417+ struct globals* globals;
418+ globals = calloc(sizeof *globals, 1);
419+
420+ struct wl_registry* registry = wl_display_get_registry(display);
421+
422+ wl_registry_add_listener(registry, &registry_listener, globals);
423+
424+ wl_display_roundtrip(display);
425+
426+ struct wl_pointer* pointer = wl_seat_get_pointer(globals->seat);
427+ wl_pointer_add_listener(pointer, &pointer_listener, NULL);
428+
429+ void* pool_data = NULL;
430+ struct wl_shm_pool* shm_pool = make_shm_pool(globals->shm, 400 * 400 * 4, &pool_data);
431+
432+ struct draw_context* ctx = calloc(sizeof *ctx, 1);
433+
434+ for (int i = 0; i < 4; ++i)
435+ {
436+ ctx->buffers[i].buffer = wl_shm_pool_create_buffer(shm_pool, 0, 400, 400, 400, WL_SHM_FORMAT_ARGB8888);
437+ ctx->buffers[i].available = true;
438+ wl_buffer_add_listener(ctx->buffers[i].buffer, &buffer_listener, ctx);
439+ }
440+
441+ ctx->display = display;
442+ ctx->surface = wl_compositor_create_surface(globals->compositor);
443+ ctx->content_area = pool_data;
444+
445+ struct wl_shell_surface* window = wl_shell_get_shell_surface(globals->shell, ctx->surface);
446+ wl_shell_surface_set_toplevel(window);
447+
448+ struct wl_callback* first_frame = wl_display_sync(display);
449+ wl_callback_add_listener(first_frame, &frame_listener, ctx);
450+
451+ wl_output_add_listener(globals->output, &output_listener, NULL);
452+
453+ while (wl_display_dispatch(display))
454+ ;
455+
456+ return 0;
457+}
458
459=== modified file 'include/platform/mir/graphics/egl_extensions.h'
460--- include/platform/mir/graphics/egl_extensions.h 2017-07-28 17:00:43 +0000
461+++ include/platform/mir/graphics/egl_extensions.h 2017-09-07 05:58:57 +0000
462@@ -19,6 +19,8 @@
463 #ifndef MIR_GRAPHICS_EGL_EXTENSIONS_H_
464 #define MIR_GRAPHICS_EGL_EXTENSIONS_H_
465
466+#include <experimental/optional>
467+
468 #define EGL_EGLEXT_PROTOTYPES
469 #include <EGL/egl.h>
470 #include <EGL/eglext.h>
471@@ -35,6 +37,15 @@
472 PFNEGLCREATEIMAGEKHRPROC const eglCreateImageKHR;
473 PFNEGLDESTROYIMAGEKHRPROC const eglDestroyImageKHR;
474 PFNGLEGLIMAGETARGETTEXTURE2DOESPROC const glEGLImageTargetTexture2DOES;
475+
476+ struct WaylandExtensions
477+ {
478+ WaylandExtensions();
479+
480+ PFNEGLBINDWAYLANDDISPLAYWL const eglBindWaylandDisplayWL;
481+ PFNEGLQUERYWAYLANDBUFFERWL const eglQueryWaylandBufferWL;
482+ };
483+ std::experimental::optional<WaylandExtensions> const wayland;
484 };
485
486 }
487
488=== added file 'include/platform/mir/graphics/wayland_allocator.h'
489--- include/platform/mir/graphics/wayland_allocator.h 1970-01-01 00:00:00 +0000
490+++ include/platform/mir/graphics/wayland_allocator.h 2017-09-07 05:58:57 +0000
491@@ -0,0 +1,45 @@
492+/*
493+ * Copyright © 2017 Canonical Ltd.
494+ *
495+ * This program is free software: you can redistribute it and/or modify it
496+ * under the terms of the GNU Lesser General Public License version 2 or 3,
497+ * as published by the Free Software Foundation.
498+ *
499+ * This program is distributed in the hope that it will be useful,
500+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
501+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
502+ * GNU Lesser General Public License for more details.
503+ *
504+ * You should have received a copy of the GNU Lesser General Public License
505+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
506+ *
507+ * Authored by:
508+ * Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
509+ */
510+
511+#ifndef MIR_PLATFORM_GRAPHICS_WAYLAND_ALLOCATOR_H_
512+#define MIR_PLATFORM_GRAPHICS_WAYLAND_ALLOCATOR_H_
513+
514+#include <vector>
515+#include <memory>
516+
517+#include <wayland-server-core.h>
518+
519+namespace mir
520+{
521+namespace graphics
522+{
523+class Buffer;
524+
525+class WaylandAllocator
526+{
527+public:
528+ virtual ~WaylandAllocator() = default;
529+
530+ virtual void bind_display(wl_display* display) = 0;
531+ virtual std::unique_ptr<Buffer> buffer_from_resource (wl_resource* buffer, std::function<void ()>&& on_consumed) = 0;
532+};
533+}
534+}
535+
536+#endif //MIR_PLATFORM_GRAPHICS_WAYLAND_ALLOCATOR_H_
537
538=== modified file 'include/server/mir/frontend/buffer_stream.h'
539--- include/server/mir/frontend/buffer_stream.h 2017-08-16 04:04:53 +0000
540+++ include/server/mir/frontend/buffer_stream.h 2017-09-07 05:58:57 +0000
541@@ -45,6 +45,7 @@
542 virtual ~BufferStream() = default;
543
544 virtual void submit_buffer(std::shared_ptr<graphics::Buffer> const& buffer) = 0;
545+ virtual void resize(geometry::Size const& size) = 0;
546
547 virtual void add_observer(std::shared_ptr<scene::SurfaceObserver> const& observer) = 0;
548 virtual void remove_observer(std::weak_ptr<scene::SurfaceObserver> const& observer) = 0;
549
550=== modified file 'include/test/mir/test/doubles/mock_egl.h'
551--- include/test/mir/test/doubles/mock_egl.h 2017-07-28 17:00:43 +0000
552+++ include/test/mir/test/doubles/mock_egl.h 2017-09-07 05:58:57 +0000
553@@ -158,6 +158,13 @@
554 int64_t*, int64_t*,
555 int64_t*));
556
557+ MOCK_METHOD2(eglBindWaylandDisplayWL,
558+ EGLBoolean(EGLDisplay, struct wl_display*));
559+ MOCK_METHOD2(eglUnbindWaylandDisplayWL,
560+ EGLBoolean(EGLDisplay, struct wl_display*));
561+ MOCK_METHOD4(eglQueryWaylandBufferWL,
562+ EGLBoolean(EGLDisplay, struct wl_resource*, EGLint, EGLint*));
563+
564 EGLDisplay const fake_egl_display;
565 EGLConfig const* const fake_configs;
566 EGLint const fake_configs_num;
567
568=== modified file 'src/CMakeLists.txt'
569--- src/CMakeLists.txt 2017-08-21 14:18:55 +0000
570+++ src/CMakeLists.txt 2017-09-07 05:58:57 +0000
571@@ -21,6 +21,7 @@
572 add_subdirectory(capnproto/)
573 add_subdirectory(common/)
574 add_subdirectory(protobuf/)
575+add_subdirectory(protocol/)
576 include_directories(${MIR_GENERATED_INCLUDE_DIRECTORIES})
577
578 add_subdirectory(platform/)
579
580=== modified file 'src/include/server/mir/compositor/buffer_stream.h'
581--- src/include/server/mir/compositor/buffer_stream.h 2017-07-28 17:00:43 +0000
582+++ src/include/server/mir/compositor/buffer_stream.h 2017-09-07 05:58:57 +0000
583@@ -45,7 +45,6 @@
584 virtual std::shared_ptr<graphics::Buffer>
585 lock_compositor_buffer(void const* user_id) = 0;
586 virtual geometry::Size stream_size() = 0;
587- virtual void resize(geometry::Size const& size) = 0;
588 virtual int buffers_ready_for_compositor(void const* user_id) const = 0;
589 virtual void drop_old_buffers() = 0;
590 virtual bool has_submitted_buffer() const = 0;
591
592=== modified file 'src/include/server/mir/default_server_configuration.h'
593--- src/include/server/mir/default_server_configuration.h 2017-07-28 17:00:43 +0000
594+++ src/include/server/mir/default_server_configuration.h 2017-09-07 05:58:57 +0000
595@@ -175,6 +175,7 @@
596 * dependencies of DisplayServer on the rest of the Mir
597 * @{ */
598 std::shared_ptr<frontend::Connector> the_connector() override;
599+ std::shared_ptr<frontend::Connector> the_wayland_connector() override;
600 std::shared_ptr<frontend::Connector> the_prompt_connector() override;
601 std::shared_ptr<graphics::Display> the_display() override;
602 std::shared_ptr<compositor::Compositor> the_compositor() override;
603@@ -375,6 +376,7 @@
604 /** @} */
605
606 CachedPtr<frontend::Connector> connector;
607+ CachedPtr<frontend::Connector> wayland_connector;
608 CachedPtr<frontend::Connector> prompt_connector;
609
610 CachedPtr<input::InputReport> input_report;
611
612=== modified file 'src/include/server/mir/server_configuration.h'
613--- src/include/server/mir/server_configuration.h 2017-07-28 17:00:43 +0000
614+++ src/include/server/mir/server_configuration.h 2017-09-07 05:58:57 +0000
615@@ -69,6 +69,7 @@
616 // TODO most of these interfaces are wider DisplayServer needs...
617 // TODO ...some or all of them need narrowing
618 virtual std::shared_ptr<frontend::Connector> the_connector() = 0;
619+ virtual std::shared_ptr<frontend::Connector> the_wayland_connector() = 0;
620 virtual std::shared_ptr<frontend::Connector> the_prompt_connector() = 0;
621 virtual std::shared_ptr<graphics::Display> the_display() = 0;
622 virtual std::shared_ptr<compositor::Compositor> the_compositor() = 0;
623
624=== modified file 'src/platform/graphics/CMakeLists.txt'
625--- src/platform/graphics/CMakeLists.txt 2017-05-08 03:04:26 +0000
626+++ src/platform/graphics/CMakeLists.txt 2017-09-07 05:58:57 +0000
627@@ -14,6 +14,7 @@
628 platform_probe.cpp
629 atomic_frame.cpp
630 ${PROJECT_SOURCE_DIR}/include/platform/mir/graphics/display.h
631+ ${PROJECT_SOURCE_DIR}/include/platform/mir/graphics/wayland_allocator.h
632 )
633
634 add_library(mirplatformgraphicscommon OBJECT
635
636=== modified file 'src/platform/graphics/egl_extensions.cpp'
637--- src/platform/graphics/egl_extensions.cpp 2017-07-28 17:00:43 +0000
638+++ src/platform/graphics/egl_extensions.cpp 2017-09-07 05:58:57 +0000
639@@ -21,8 +21,26 @@
640 #include <boost/throw_exception.hpp>
641 #include <stdexcept>
642
643+#define MIR_LOG_COMPONENT "EGL extensions"
644+#include "mir/log.h"
645+
646 namespace mg=mir::graphics;
647
648+namespace
649+{
650+std::experimental::optional<mg::EGLExtensions::WaylandExtensions> maybe_wayland_ext()
651+{
652+ try
653+ {
654+ return mg::EGLExtensions::WaylandExtensions{};
655+ }
656+ catch (std::runtime_error const&)
657+ {
658+ return {};
659+ }
660+}
661+}
662+
663 mg::EGLExtensions::EGLExtensions() :
664 eglCreateImageKHR{
665 reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>(eglGetProcAddress("eglCreateImageKHR"))},
666@@ -36,7 +54,8 @@
667 * mix ES and GL code. But other drivers won't be so lenient.
668 */
669 glEGLImageTargetTexture2DOES{
670- reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"))}
671+ reinterpret_cast<PFNGLEGLIMAGETARGETTEXTURE2DOESPROC>(eglGetProcAddress("glEGLImageTargetTexture2DOES"))},
672+ wayland{maybe_wayland_ext()}
673 {
674 if (!eglCreateImageKHR || !eglDestroyImageKHR)
675 BOOST_THROW_EXCEPTION(std::runtime_error("EGL implementation doesn't support EGLImage"));
676@@ -44,3 +63,17 @@
677 if (!glEGLImageTargetTexture2DOES)
678 BOOST_THROW_EXCEPTION(std::runtime_error("GLES2 implementation doesn't support updating a texture from an EGLImage"));
679 }
680+
681+mg::EGLExtensions::WaylandExtensions::WaylandExtensions() :
682+ eglBindWaylandDisplayWL{
683+ reinterpret_cast<PFNEGLBINDWAYLANDDISPLAYWL>(eglGetProcAddress("eglBindWaylandDisplayWL"))
684+ },
685+ eglQueryWaylandBufferWL{
686+ reinterpret_cast<PFNEGLQUERYWAYLANDBUFFERWL>(eglGetProcAddress("eglQueryWaylandBufferWL"))
687+ }
688+{
689+ if (!eglBindWaylandDisplayWL || !eglQueryWaylandBufferWL)
690+ {
691+ BOOST_THROW_EXCEPTION(std::runtime_error("EGL implementation doesn't support EGL_WL_bind_wayland_display"));
692+ }
693+}
694\ No newline at end of file
695
696=== modified file 'src/platforms/mesa/server/CMakeLists.txt'
697--- src/platforms/mesa/server/CMakeLists.txt 2017-05-17 04:48:46 +0000
698+++ src/platforms/mesa/server/CMakeLists.txt 2017-09-07 05:58:57 +0000
699@@ -8,6 +8,7 @@
700 include_directories(
701 ${server_common_include_dirs}
702 ${DRM_INCLUDE_DIRS}
703+ ${WAYLAND_SERVER_INCLUDE_DIRS}
704 )
705
706 add_library(
707@@ -30,4 +31,5 @@
708
709 server_platform_common
710 kms_utils
711+ ${WAYLAND_SERVER_LDFLAGS} ${WAYLAND_SERVER_LIBRARIES}
712 )
713
714=== modified file 'src/platforms/mesa/server/buffer_allocator.cpp'
715--- src/platforms/mesa/server/buffer_allocator.cpp 2017-07-28 17:00:43 +0000
716+++ src/platforms/mesa/server/buffer_allocator.cpp 2017-09-07 05:58:57 +0000
717@@ -44,6 +44,12 @@
718 #include <cassert>
719 #include <fcntl.h>
720
721+#include <wayland-server.h>
722+
723+#define MIR_LOG_COMPONENT "mesa-buffer-allocator"
724+#include <mir/log.h>
725+#include <mutex>
726+
727 namespace mg = mir::graphics;
728 namespace mgm = mg::mesa;
729 namespace mgc = mg::common;
730@@ -317,3 +323,228 @@
731
732 return pixel_formats;
733 }
734+
735+namespace
736+{
737+class WaylandBuffer :
738+ public mir::graphics::BufferBasic,
739+ public mir::graphics::NativeBufferBase,
740+ public mir::renderer::gl::TextureSource
741+{
742+public:
743+ WaylandBuffer(
744+ EGLDisplay dpy,
745+ wl_resource* buffer,
746+ std::shared_ptr<mg::EGLExtensions> const& extensions,
747+ std::function<void()>&& on_consumed)
748+ : buffer{buffer},
749+ dpy{dpy},
750+ egl_image{EGL_NO_IMAGE_KHR},
751+ extensions{extensions},
752+ on_consumed{std::move(on_consumed)}
753+ {
754+ if (auto notifier = wl_resource_get_destroy_listener(buffer, &on_buffer_destroyed))
755+ {
756+ DestructionShim* shim;
757+
758+ shim = wl_container_of(notifier, shim, destruction_listener);
759+
760+ if (shim->associated_buffer)
761+ BOOST_THROW_EXCEPTION(std::logic_error("Attempt to associate a single wl_buffer with multiple WaylandBuffer wrappers"));
762+
763+ shim->associated_buffer = this;
764+ buffer_mutex = shim->mutex;
765+ }
766+ else
767+ {
768+ auto shim = new DestructionShim;
769+ shim->destruction_listener.notify = &on_buffer_destroyed;
770+ shim->associated_buffer = this;
771+ buffer_mutex = shim->mutex;
772+
773+ wl_resource_add_destroy_listener(buffer, &shim->destruction_listener);
774+ }
775+
776+ if (extensions->wayland->eglQueryWaylandBufferWL(dpy, buffer, EGL_WIDTH, &width) == EGL_FALSE)
777+ {
778+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query WaylandAllocator buffer width"));
779+ }
780+ if (extensions->wayland->eglQueryWaylandBufferWL(dpy, buffer, EGL_HEIGHT, &height) == EGL_FALSE)
781+ {
782+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query WaylandAllocator buffer height"));
783+ }
784+
785+ EGLint texture_format;
786+ if (!extensions->wayland->eglQueryWaylandBufferWL(dpy, buffer, EGL_TEXTURE_FORMAT, &texture_format))
787+ {
788+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to query WL buffer format"));
789+ }
790+
791+ if (texture_format == EGL_TEXTURE_RGB)
792+ {
793+ format = mir_pixel_format_xrgb_8888;
794+ }
795+ else if (texture_format == EGL_TEXTURE_RGBA)
796+ {
797+ format = mir_pixel_format_argb_8888;
798+ }
799+ else
800+ {
801+ BOOST_THROW_EXCEPTION((std::invalid_argument{"YUV buffers are unimplemented"}));
802+ }
803+ }
804+
805+ ~WaylandBuffer()
806+ {
807+ if (egl_image != EGL_NO_IMAGE_KHR)
808+ extensions->eglDestroyImageKHR(dpy, egl_image);
809+
810+ std::lock_guard<std::mutex> lock{*buffer_mutex};
811+ if (buffer)
812+ {
813+ wl_resource_queue_event(buffer, WL_BUFFER_RELEASE);
814+ auto notifier = wl_resource_get_destroy_listener(buffer, &on_buffer_destroyed);
815+ DestructionShim* shim;
816+
817+ shim = wl_container_of(notifier, shim, destruction_listener);
818+
819+ shim->associated_buffer = nullptr;
820+ }
821+ }
822+
823+ void gl_bind_to_texture() override
824+ {
825+ std::unique_lock<std::mutex> lock{*buffer_mutex};
826+ if (buffer == nullptr)
827+ {
828+ mir::log_warning("WaylandBuffer::gl_bind_to_texture() called on a destroyed wl_buffer", this);
829+ return;
830+ }
831+ if (egl_image == EGL_NO_IMAGE_KHR)
832+ {
833+ eglBindAPI(MIR_SERVER_EGL_OPENGL_API);
834+
835+ const EGLint image_attrs[] =
836+ {
837+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
838+ EGL_NONE
839+ };
840+
841+ egl_image = extensions->eglCreateImageKHR(
842+ dpy,
843+ EGL_NO_CONTEXT,
844+ EGL_WAYLAND_BUFFER_WL,
845+ buffer,
846+ image_attrs);
847+
848+ if (egl_image == EGL_NO_IMAGE_KHR)
849+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to create EGLImage"));
850+
851+ on_consumed();
852+ }
853+ lock.unlock();
854+
855+ extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image);
856+ }
857+
858+ void bind() override
859+ {
860+ gl_bind_to_texture();
861+ }
862+
863+ void secure_for_render() override
864+ {
865+ }
866+
867+ std::shared_ptr<mir::graphics::NativeBuffer> native_buffer_handle() const override
868+ {
869+ return nullptr;
870+ }
871+
872+ mir::geometry::Size size() const override
873+ {
874+ return mir::geometry::Size{width, height};
875+ }
876+
877+ MirPixelFormat pixel_format() const override
878+ {
879+ return format;
880+ }
881+
882+ mir::graphics::NativeBufferBase *native_buffer_base() override
883+ {
884+ return this;
885+ }
886+
887+private:
888+ static void on_buffer_destroyed(wl_listener* listener, void*)
889+ {
890+ static_assert(
891+ std::is_standard_layout<DestructionShim>::value,
892+ "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
893+
894+ DestructionShim* shim;
895+ shim = wl_container_of(listener, shim, destruction_listener);
896+
897+ {
898+ std::lock_guard<std::mutex> lock{*shim->mutex};
899+ if (shim->associated_buffer)
900+ {
901+ shim->associated_buffer->buffer = nullptr;
902+ }
903+ }
904+
905+ delete shim;
906+ }
907+
908+ struct DestructionShim
909+ {
910+ std::shared_ptr<std::mutex> const mutex = std::make_shared<std::mutex>();
911+ WaylandBuffer* associated_buffer;
912+ wl_listener destruction_listener;
913+ };
914+
915+ std::shared_ptr<std::mutex> buffer_mutex;
916+ wl_resource* buffer;
917+
918+ EGLDisplay dpy;
919+ EGLImageKHR egl_image;
920+
921+ EGLint width, height;
922+ MirPixelFormat format;
923+
924+ std::shared_ptr<mg::EGLExtensions> const extensions;
925+
926+ std::function<void()> on_consumed;
927+};
928+}
929+
930+void mgm::BufferAllocator::bind_display(wl_display* display)
931+{
932+ dpy = eglGetCurrentDisplay();
933+
934+ if (dpy == EGL_NO_DISPLAY)
935+ BOOST_THROW_EXCEPTION((std::logic_error{"WaylandAllocator::bind_display called without an active EGL Display"}));
936+
937+ if (!egl_extensions->wayland)
938+ {
939+ mir::log_warning("No EGL_WL_bind_wayland_display support");
940+ return;
941+ }
942+
943+ if (egl_extensions->wayland->eglBindWaylandDisplayWL(dpy, display) == EGL_FALSE)
944+ {
945+ BOOST_THROW_EXCEPTION(mg::egl_error("Failed to bind Wayland display"));
946+ }
947+ else
948+ {
949+ mir::log_info("Bound WaylandAllocator display");
950+ }
951+}
952+
953+std::unique_ptr<mg::Buffer> mgm::BufferAllocator::buffer_from_resource (wl_resource* buffer, std::function<void ()>&& on_consumed)
954+{
955+ if (egl_extensions->wayland)
956+ return std::make_unique<WaylandBuffer>(dpy, buffer, egl_extensions, std::move(on_consumed));
957+ return nullptr;
958+}
959
960=== modified file 'src/platforms/mesa/server/buffer_allocator.h'
961--- src/platforms/mesa/server/buffer_allocator.h 2017-07-28 17:00:43 +0000
962+++ src/platforms/mesa/server/buffer_allocator.h 2017-09-07 05:58:57 +0000
963@@ -22,6 +22,7 @@
964 #include "platform_common.h"
965 #include "mir/graphics/graphic_buffer_allocator.h"
966 #include "mir/graphics/buffer_id.h"
967+#include "mir/graphics/wayland_allocator.h"
968 #include "mir_toolkit/mir_native_buffer.h"
969
970 #pragma GCC diagnostic push
971@@ -29,6 +30,8 @@
972 #include <gbm.h>
973 #pragma GCC diagnostic pop
974
975+#include <EGL/egl.h>
976+
977 #include <memory>
978
979 namespace mir
980@@ -46,7 +49,9 @@
981 dma_buf
982 };
983
984-class BufferAllocator: public graphics::GraphicBufferAllocator
985+class BufferAllocator:
986+ public graphics::GraphicBufferAllocator,
987+ public graphics::WaylandAllocator
988 {
989 public:
990 BufferAllocator(gbm_device* device, BypassOption bypass_option, BufferImportMethod const buffer_import_method);
991@@ -57,10 +62,13 @@
992 std::shared_ptr<Buffer> alloc_buffer(graphics::BufferProperties const& buffer_properties) override;
993 std::vector<MirPixelFormat> supported_pixel_formats() override;
994
995+ void bind_display(wl_display* display) override;
996+ std::unique_ptr<Buffer> buffer_from_resource (wl_resource* buffer, std::function<void ()>&& on_consumed) override;
997 private:
998 std::shared_ptr<Buffer> alloc_hardware_buffer(
999 graphics::BufferProperties const& buffer_properties);
1000
1001+ EGLDisplay dpy;
1002 gbm_device* const device;
1003 std::shared_ptr<EGLExtensions> const egl_extensions;
1004
1005
1006=== modified file 'src/platforms/mesa/server/kms/CMakeLists.txt'
1007--- src/platforms/mesa/server/kms/CMakeLists.txt 2017-06-09 19:25:54 +0000
1008+++ src/platforms/mesa/server/kms/CMakeLists.txt 2017-09-07 05:58:57 +0000
1009@@ -9,6 +9,7 @@
1010 ${GBM_INCLUDE_DIRS}
1011 ${EGL_INCLUDE_DIRS}
1012 ${GL_INCLUDE_DIRS}
1013+ ${WAYLAND_SERVER_INCLUDE_DIRS}
1014 ${UDEV_INCLUDE_DIRS}
1015 ${PROJECT_SOURCE_DIR}/include/client
1016 )
1017@@ -65,6 +66,7 @@
1018 ${GBM_LDFLAGS} ${GBM_LIBRARIES}
1019 ${EGL_LDFLAGS} ${EGL_LIBRARIES}
1020 ${GL_LDFLAGS} ${GL_LIBRARIES}
1021+ ${WAYLAND_SERVER_LDFLAGS} ${WAYLAND_SERVER_LIBRARIES}
1022 )
1023
1024 set_target_properties(
1025
1026=== modified file 'src/platforms/mesa/server/kms/platform.cpp'
1027--- src/platforms/mesa/server/kms/platform.cpp 2017-07-28 17:00:43 +0000
1028+++ src/platforms/mesa/server/kms/platform.cpp 2017-09-07 05:58:57 +0000
1029@@ -29,9 +29,23 @@
1030 #include "mir/emergency_cleanup_registry.h"
1031 #include "mir/udev/wrapper.h"
1032 #include "mesa_extensions.h"
1033+#include "mir/renderer/gl/texture_target.h"
1034+#include "mir/graphics/buffer_basic.h"
1035+#include "mir/graphics/egl_error.h"
1036+
1037+#include <EGL/egl.h>
1038+#include <EGL/eglext.h>
1039+#include MIR_SERVER_GL_H
1040+#include MIR_SERVER_GLEXT_H
1041+
1042+#define MIR_LOG_COMPONENT "platform-graphics-mesa"
1043+#include "mir/log.h"
1044
1045 #include <boost/throw_exception.hpp>
1046 #include <stdexcept>
1047+#include <mir/renderer/gl/texture_source.h>
1048+#include <wayland-server-core.h>
1049+#include <wayland-server-protocol.h>
1050
1051 namespace mg = mir::graphics;
1052 namespace mgm = mg::mesa;
1053
1054=== added directory 'src/protocol'
1055=== added file 'src/protocol/CMakeLists.txt'
1056--- src/protocol/CMakeLists.txt 1970-01-01 00:00:00 +0000
1057+++ src/protocol/CMakeLists.txt 2017-09-07 05:58:57 +0000
1058@@ -0,0 +1,28 @@
1059+pkg_check_modules(XMLPP libxml++-2.6 REQUIRED)
1060+
1061+include_directories(SYSTEM ${XMLPP_INCLUDE_DIRS})
1062+
1063+add_executable(wrapper-generator
1064+
1065+ wrapper_generator.cpp
1066+)
1067+
1068+target_link_libraries(wrapper-generator
1069+
1070+ ${XMLPP_LDFLAGS} ${XMLPP_LIBRARIES}
1071+)
1072+
1073+get_filename_component(
1074+ GENERATED_HEADER src/server/frontend/wayland/core_generated_interfaces.h
1075+ ABSOLUTE
1076+ BASE_DIR ${PROJECT_SOURCE_DIR}
1077+)
1078+
1079+add_custom_target(refresh-wayland-wrapper
1080+ COMMAND "sh" "-c" "${CMAKE_BINARY_DIR}/bin/wrapper-generator wl_ /usr/share/wayland/wayland.xml >${GENERATED_HEADER}"
1081+ VERBATIM
1082+ DEPENDS wrapper-generator
1083+ DEPENDS /usr/share/wayland/wayland.xml
1084+ SOURCES ${GENERATED_HEADER}
1085+)
1086+
1087
1088=== added file 'src/protocol/wrapper_generator.cpp'
1089--- src/protocol/wrapper_generator.cpp 1970-01-01 00:00:00 +0000
1090+++ src/protocol/wrapper_generator.cpp 2017-09-07 05:58:57 +0000
1091@@ -0,0 +1,509 @@
1092+/*
1093+ * Copyright © 2017 Canonical Ltd.
1094+ *
1095+ * This program is free software: you can redistribute it and/or modify it
1096+ * under the terms of the GNU General Public License version 2 or 3,
1097+ * as published by the Free Software Foundation.
1098+ *
1099+ * This program is distributed in the hope that it will be useful,
1100+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1101+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1102+ * GNU General Public License for more details.
1103+ *
1104+ * You should have received a copy of the GNU General Public License
1105+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1106+ *
1107+ * Authored By: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
1108+ */
1109+
1110+#include <libxml++/libxml++.h>
1111+#include <iostream>
1112+#include <unordered_map>
1113+#include <unordered_set>
1114+#include <functional>
1115+
1116+#include <experimental/optional>
1117+#include <vector>
1118+#include <locale>
1119+#include <stdio.h>
1120+
1121+void emit_comment_header(std::ostream& out)
1122+{
1123+ out << "/*" << std::endl;
1124+ out << " * AUTOGENERATED - DO NOT EDIT" << std::endl;
1125+ out << " *" << std::endl;
1126+ out << " * This header is generated by src/protocol/wrapper_generator.cpp" << std::endl;
1127+ out << " * To regenerate, run the “refresh-wayland-wrapper” target." << std::endl;
1128+ out << " */" << std::endl;
1129+}
1130+
1131+void emit_required_headers()
1132+{
1133+ std::cout << "#include <experimental/optional>" << std::endl;
1134+ std::cout << "#include <boost/throw_exception.hpp>" << std::endl;
1135+ std::cout << std::endl;
1136+ std::cout << "#include <wayland-server.h>" << std::endl;
1137+ std::cout << "#include <wayland-server-protocol.h>" << std::endl;
1138+ std::cout << std::endl;
1139+ std::cout << "#include \"mir/fd.h\"" << std::endl;
1140+}
1141+
1142+std::string strip_wl_prefix(std::string const& name)
1143+{
1144+ return name.substr(3);
1145+}
1146+
1147+std::string camel_case_string(std::string const& name)
1148+{
1149+ std::string camel_cased_name;
1150+ camel_cased_name = std::string{std::toupper(name[0], std::locale("C"))} + name.substr(1);
1151+ auto next_underscore_offset = name.find('_');
1152+ while (next_underscore_offset != std::string::npos)
1153+ {
1154+ if (next_underscore_offset < camel_cased_name.length())
1155+ {
1156+ camel_cased_name = camel_cased_name.substr(0, next_underscore_offset) +
1157+ std::toupper(camel_cased_name[next_underscore_offset + 1], std::locale("C")) +
1158+ camel_cased_name.substr(next_underscore_offset + 2);
1159+ }
1160+ next_underscore_offset = camel_cased_name.find('_', next_underscore_offset);
1161+ }
1162+ return camel_cased_name;
1163+}
1164+
1165+struct ArgumentTypeDescriptor
1166+{
1167+ std::string cpp_type;
1168+ std::string c_type;
1169+ std::experimental::optional<std::vector<std::string>> converter;
1170+};
1171+
1172+std::vector<std::string> fd_converter{
1173+ "mir::Fd $NAME_resolved{$NAME};"
1174+};
1175+
1176+std::vector<std::string> optional_object_converter{
1177+ "std::experimental::optional<struct wl_resource*> $NAME_resolved;",
1178+ "if ($NAME != nullptr)",
1179+ "{",
1180+ " $NAME_resolved = $NAME;",
1181+ "}"
1182+};
1183+
1184+std::vector<std::string> optional_string_converter{
1185+ "std::experimental::optional<std::string> $NAME_resolved;",
1186+ "if ($NAME != nullptr)",
1187+ "{",
1188+ " $NAME_resolved = std::experimental::make_optional<std::string>($NAME);",
1189+ "}"
1190+};
1191+
1192+std::unordered_map<std::string, ArgumentTypeDescriptor const> type_map = {
1193+ { "uint", { "uint32_t", "uint32_t", {} }},
1194+ { "int", { "int32_t", "int32_t", {} }},
1195+ { "fd", { "mir::Fd", "int", { fd_converter }}},
1196+ { "object", { "struct wl_resource*", "struct wl_resource*", {} }},
1197+ { "string", { "std::string const&", "char const*", {} }},
1198+ { "new_id", { "uint32_t", "uint32_t", {} }}
1199+};
1200+
1201+std::unordered_map<std::string, ArgumentTypeDescriptor const> optional_type_map = {
1202+ { "object", { "std::experimental::optional<struct wl_resource*> const&", "struct wl_resource*", { optional_object_converter }}},
1203+ { "string", { "std::experimental::optional<std::string> const&", "char const*", { optional_string_converter} }},
1204+};
1205+
1206+bool parse_optional(xmlpp::Element const& arg)
1207+{
1208+ if (auto allow_null = arg.get_attribute("allow-null"))
1209+ {
1210+ return allow_null->get_value() == "true";
1211+ }
1212+ return false;
1213+}
1214+
1215+class Interface;
1216+
1217+class Argument
1218+{
1219+public:
1220+ Argument(xmlpp::Element const& node)
1221+ : name{node.get_attribute_value("name")},
1222+ descriptor{parse_optional(node) ? optional_type_map.at(node.get_attribute_value("type"))
1223+ : type_map.at(node.get_attribute_value("type"))}
1224+ {
1225+ }
1226+
1227+ void emit_c_prototype(std::ostream& out) const
1228+ {
1229+ out << descriptor.c_type << " " << name;
1230+ }
1231+ void emit_cpp_prototype(std::ostream& out) const
1232+ {
1233+ out << descriptor.cpp_type << " " << name;
1234+ }
1235+ void emit_thunk_call_fragment(std::ostream& out) const
1236+ {
1237+ out << (descriptor.converter ? (name + "_resolved") : name);
1238+ }
1239+
1240+ void emit_thunk_converter(std::ostream& out, std::string const& indent) const
1241+ {
1242+ for (auto const& line : descriptor.converter.value_or(std::vector<std::string>{}))
1243+ {
1244+ std::string substituted_line = line;
1245+ size_t substitution_pos = substituted_line.find("$NAME");
1246+ while (substitution_pos != std::string::npos)
1247+ {
1248+ substituted_line = substituted_line.replace(substitution_pos, 5, name);
1249+ substitution_pos = substituted_line.find("$NAME");
1250+ }
1251+ out << indent << substituted_line << std::endl;
1252+ }
1253+ }
1254+
1255+private:
1256+ std::string const name;
1257+ ArgumentTypeDescriptor const& descriptor;
1258+};
1259+
1260+class Method
1261+{
1262+public:
1263+ Method(xmlpp::Element const& node)
1264+ : name{node.get_attribute_value("name")}
1265+ {
1266+ for (auto const& child : node.get_children("arg"))
1267+ {
1268+ auto arg_node = dynamic_cast<xmlpp::Element const*>(child);
1269+ arguments.emplace_back(std::ref(*arg_node));
1270+ }
1271+ }
1272+
1273+ // TODO: Decide whether to resolve wl_resource* to wrapped types (ie: Region, Surface, etc).
1274+ void emit_virtual_prototype(std::ostream& out, std::string const& indent, bool is_global) const
1275+ {
1276+ out << indent << "virtual void " << name << "(";
1277+ if (is_global)
1278+ {
1279+ out << "struct wl_client* client, struct wl_resource* resource";
1280+ if (!arguments.empty())
1281+ {
1282+ out << ", ";
1283+ }
1284+ }
1285+ for (size_t i = 0 ; i < arguments.size() ; ++i)
1286+ {
1287+ arguments[i].emit_cpp_prototype(out);
1288+ if (i != arguments.size() - 1)
1289+ {
1290+ out << ", ";
1291+ }
1292+ }
1293+ out << ") = 0;" << std::endl;
1294+ }
1295+
1296+ // TODO: Decide whether to resolve wl_resource* to wrapped types (ie: Region, Surface, etc).
1297+ void emit_thunk(std::ostream& out, std::string const& indent,
1298+ std::string const& interface_type, bool is_global) const
1299+ {
1300+ out << indent << "static void " << name << "_thunk("
1301+ << "struct wl_client*" << (is_global ? " client" : "")
1302+ << ", struct wl_resource* resource";
1303+ for (auto const& arg : arguments)
1304+ {
1305+ out << ", ";
1306+ arg.emit_c_prototype(out);
1307+ }
1308+ out << ")" << std::endl;
1309+
1310+ out << indent << "{" << std::endl;
1311+ out << indent << " auto me = static_cast<" << interface_type << "*>("
1312+ << "wl_resource_get_user_data(resource));" << std::endl;
1313+ for (auto const& arg : arguments)
1314+ {
1315+ arg.emit_thunk_converter(out, indent + " ");
1316+ }
1317+
1318+ out << indent << " me->" << name << "(";
1319+ if (is_global)
1320+ {
1321+ out << "client, resource";
1322+ if (!arguments.empty())
1323+ {
1324+ out << ", ";
1325+ }
1326+ }
1327+ for (size_t i = 0; i < arguments.size(); ++i)
1328+ {
1329+ arguments[i].emit_thunk_call_fragment(out);
1330+ if (i != arguments.size() - 1)
1331+ {
1332+ out << ", ";
1333+ }
1334+ }
1335+ out << ");" << std::endl;
1336+
1337+ out << indent << "}" << std::endl;
1338+ }
1339+
1340+ void emit_vtable_initialiser(std::ostream& out, std::string const& indent) const
1341+ {
1342+ out << indent << name << "_thunk," << std::endl;
1343+ }
1344+
1345+private:
1346+ std::string const name;
1347+ std::vector<Argument> arguments;
1348+};
1349+
1350+void emit_indented_lines(std::ostream& out, std::string const& indent,
1351+ std::initializer_list<std::initializer_list<std::string>> lines)
1352+{
1353+ for (auto const& line : lines)
1354+ {
1355+ out << indent;
1356+ for (auto const& fragment : line)
1357+ {
1358+ out << fragment;
1359+ }
1360+ out << std::endl;
1361+ }
1362+}
1363+
1364+class Interface
1365+{
1366+public:
1367+ Interface(
1368+ xmlpp::Element const& node,
1369+ std::function<std::string(std::string)> const& name_transform,
1370+ std::unordered_set<std::string> const& constructable_interfaces)
1371+ : wl_name{node.get_attribute_value("name")},
1372+ generated_name{name_transform(wl_name)},
1373+ is_global{constructable_interfaces.count(wl_name) == 0}
1374+ {
1375+ for (auto method_node : node.get_children("request"))
1376+ {
1377+ auto method = dynamic_cast<xmlpp::Element*>(method_node);
1378+ methods.emplace_back(std::ref(*method));
1379+ }
1380+ }
1381+
1382+ void emit_constructor(std::ostream& out, std::string const& indent, bool has_vtable)
1383+ {
1384+ if (is_global)
1385+ {
1386+ emit_constructor_for_global(out, indent);
1387+ }
1388+ else
1389+ {
1390+ emit_constructor_for_regular(out, indent, has_vtable);
1391+ }
1392+ }
1393+
1394+ void emit_bind(std::ostream& out, std::string const& indent, bool has_vtable)
1395+ {
1396+ emit_indented_lines(out, indent, {
1397+ {"static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)"},
1398+ {"{"},
1399+ });
1400+ emit_indented_lines(out, indent + " ", {
1401+ {"auto me = static_cast<", generated_name, "*>(data);"},
1402+ {"auto resource = wl_resource_create(client, &", wl_name, "_interface,"},
1403+ {" std::min(version, me->max_version), id);"},
1404+ {"if (resource == nullptr)"},
1405+ {"{"},
1406+ {" wl_client_post_no_memory(client);"},
1407+ {" BOOST_THROW_EXCEPTION((std::bad_alloc{}));"},
1408+ {"}"},
1409+ });
1410+ if (has_vtable)
1411+ {
1412+ emit_indented_lines(out, indent + " ",
1413+ {{"wl_resource_set_implementation(resource, &vtable, me, nullptr);"}});
1414+ }
1415+ emit_indented_lines(out, indent, {
1416+ {"}"}
1417+ });
1418+ }
1419+
1420+ void emit_class(std::ostream& out)
1421+ {
1422+ out << "class " << generated_name << std::endl;
1423+ out << "{" << std::endl;
1424+ out << "protected:" << std::endl;
1425+
1426+ emit_constructor(out, " ", !methods.empty());
1427+ out << " virtual ~" << generated_name << "() = default;" << std::endl;
1428+ out << std::endl;
1429+
1430+ for (auto const& method : methods)
1431+ {
1432+ method.emit_virtual_prototype(out, " ", is_global);
1433+ }
1434+ out << std::endl;
1435+
1436+ if (!is_global)
1437+ {
1438+ emit_indented_lines(out, " ", {
1439+ { "struct wl_client* const client;" },
1440+ { "struct wl_resource* const resource;"}
1441+ });
1442+ out << std::endl;
1443+ }
1444+
1445+ if (!methods.empty())
1446+ {
1447+ out << "private:" << std::endl;
1448+ }
1449+
1450+ for (auto const& method : methods)
1451+ {
1452+ method.emit_thunk(out, " ", generated_name, is_global);
1453+ out << std::endl;
1454+ }
1455+
1456+ if (is_global)
1457+ {
1458+ emit_bind(out, " ", !methods.empty());
1459+ out << std::endl;
1460+ emit_indented_lines(out, " ", {
1461+ { "uint32_t const max_version;" }
1462+ });
1463+ }
1464+
1465+ if (!methods.empty())
1466+ {
1467+ emit_indented_lines(out, " ", {
1468+ { "static struct ", wl_name, "_interface const vtable;" }
1469+ });
1470+ }
1471+
1472+ out << "};" << std::endl;
1473+
1474+ out << std::endl;
1475+
1476+ if (!methods.empty())
1477+ {
1478+ out << "struct " << wl_name << "_interface const " << generated_name << "::vtable = {" << std::endl;
1479+ for (auto const& method : methods)
1480+ {
1481+ method.emit_vtable_initialiser(out, " ");
1482+ }
1483+ out << "};" << std::endl;
1484+ }
1485+ }
1486+
1487+private:
1488+ void emit_constructor_for_global(std::ostream& out, std::string const& indent)
1489+ {
1490+ out << indent << generated_name << "(struct wl_display* display, uint32_t max_version)" << std::endl;
1491+ out << indent << " : max_version{max_version}" << std::endl;
1492+ out << indent << "{" << std::endl;
1493+ out << indent << " if (!wl_global_create(display, " << std::endl;
1494+ out << indent << " &" << wl_name << "_interface, max_version," << std::endl;
1495+ out << indent << " this, &" << generated_name << "::bind))" << std::endl;
1496+ out << indent << " {" << std::endl;
1497+ out << indent << " BOOST_THROW_EXCEPTION((std::runtime_error{\"Failed to export "
1498+ << wl_name << " interface\"}));" << std::endl;
1499+ out << indent << " }" << std::endl;
1500+ out << indent << "}" << std::endl;
1501+ }
1502+
1503+ void emit_constructor_for_regular(std::ostream& out, std::string const& indent, bool has_vtable)
1504+ {
1505+ emit_indented_lines(out, indent, {
1506+ { generated_name, "(struct wl_client* client, struct wl_resource* parent, uint32_t id)" },
1507+ { " : client{client}," },
1508+ { " resource{wl_resource_create(client, &", wl_name, "_interface, wl_resource_get_version(parent), id)}" },
1509+ { "{" }
1510+ });
1511+ emit_indented_lines(out, indent + " ", {
1512+ { "if (resource == nullptr)" },
1513+ { "{" },
1514+ { " wl_resource_post_no_memory(parent);" },
1515+ { " BOOST_THROW_EXCEPTION((std::bad_alloc{}));" },
1516+ { "}" },
1517+ });
1518+ if (has_vtable)
1519+ {
1520+ emit_indented_lines(out, indent + " ",
1521+ {{ "wl_resource_set_implementation(resource, &vtable, this, nullptr);" }});
1522+ }
1523+ emit_indented_lines(out, indent, {
1524+ { "}" }
1525+ });
1526+ }
1527+
1528+ std::string const wl_name;
1529+ std::string const generated_name;
1530+ bool const is_global;
1531+ std::vector<Method> methods;
1532+};
1533+
1534+int main(int argc, char** argv)
1535+{
1536+ if (argc != 3)
1537+ {
1538+ exit(1);
1539+ }
1540+
1541+ std::string const prefix{argv[1]};
1542+
1543+ auto name_transform = [prefix](std::string protocol_name)
1544+ {
1545+ std::string transformed_name = protocol_name;
1546+ if (protocol_name.find(prefix) == 0)
1547+ {
1548+ transformed_name = protocol_name.substr(prefix.length());
1549+ }
1550+ return camel_case_string(transformed_name);
1551+ };
1552+
1553+ xmlpp::DomParser parser(argv[2]);
1554+
1555+ auto document = parser.get_document();
1556+
1557+ auto root_node = document->get_root_node();
1558+
1559+ auto constructor_nodes = root_node->find("//arg[@type='new_id']");
1560+ std::unordered_set<std::string> constructible_interfaces;
1561+ for (auto const node : constructor_nodes)
1562+ {
1563+ auto arg = dynamic_cast<xmlpp::Element const*>(node);
1564+ constructible_interfaces.insert(arg->get_attribute_value("interface"));
1565+ }
1566+
1567+ emit_comment_header(std::cout);
1568+
1569+ std::cout << std::endl;
1570+
1571+ emit_required_headers();
1572+
1573+ std::cout << std::endl;
1574+
1575+ std::cout << "namespace mir" << std::endl;
1576+ std::cout << "{" << std::endl;
1577+ std::cout << "namespace frontend" << std::endl;
1578+ std::cout << "{" << std::endl;
1579+ std::cout << "namespace wayland" << std::endl;
1580+ std::cout << "{" << std::endl;
1581+
1582+ for (auto top_level : root_node->get_children("interface"))
1583+ {
1584+ auto interface = dynamic_cast<xmlpp::Element*>(top_level);
1585+
1586+ if (interface->get_attribute_value("name") == "wl_display" ||
1587+ interface->get_attribute_value("name") == "wl_registry")
1588+ {
1589+ // These are special, and don't need binding.
1590+ continue;
1591+ }
1592+ Interface(*interface, name_transform, constructible_interfaces).emit_class(std::cout);
1593+
1594+ std::cout << std::endl << std::endl;
1595+ }
1596+ std::cout << "}" << std::endl;
1597+ std::cout << "}" << std::endl;
1598+ std::cout << "}" << std::endl;
1599+ return 0;
1600+}
1601
1602=== modified file 'src/server/CMakeLists.txt'
1603--- src/server/CMakeLists.txt 2017-08-02 11:07:50 +0000
1604+++ src/server/CMakeLists.txt 2017-09-07 05:58:57 +0000
1605@@ -76,6 +76,7 @@
1606 $<TARGET_OBJECTS:mircompositor>
1607 $<TARGET_OBJECTS:mirgraphics>
1608 $<TARGET_OBJECTS:mirfrontend>
1609+ $<TARGET_OBJECTS:mirfrontend-wayland>
1610 $<TARGET_OBJECTS:mirshell>
1611 $<TARGET_OBJECTS:mirlttng>
1612 $<TARGET_OBJECTS:mirreport>
1613@@ -120,6 +121,7 @@
1614 ${UDEV_LDFLAGS} ${UDEV_LIBRARIES}
1615 ${GLIB_LDFLAGS} ${GLIB_LIBRARIES}
1616 ${UUID_LDFLAGS} ${UUID_LIBRARIES}
1617+ ${WAYLAND_SERVER_LDFLAGS} ${WAYLAND_SERVER_LIBRARIES}
1618 )
1619
1620 install(TARGETS mirserver
1621
1622=== modified file 'src/server/display_server.cpp'
1623--- src/server/display_server.cpp 2017-09-06 11:14:47 +0000
1624+++ src/server/display_server.cpp 2017-09-07 05:58:57 +0000
1625@@ -50,6 +50,7 @@
1626 input_dispatcher{config.the_input_dispatcher()},
1627 compositor{config.the_compositor()},
1628 connector{config.the_connector()},
1629+ wayland_connector{config.the_wayland_connector()},
1630 prompt_connector{config.the_prompt_connector()},
1631 input_manager{config.the_input_manager()},
1632 main_loop{config.the_main_loop()},
1633@@ -73,9 +74,13 @@
1634 {
1635 auto comm = try_but_revert_if_unwinding(
1636 [this] { connector->stop(); },
1637- [&, this] { connector->start(); });
1638-
1639- auto prompt = try_but_revert_if_unwinding(
1640+ [this] { connector->start(); });
1641+
1642+ auto wayland = try_but_revert_if_unwinding(
1643+ [this] { wayland_connector->stop(); },
1644+ [this] { wayland_connector->start(); });
1645+
1646+ auto prompt = try_but_revert_if_unwinding(
1647 [this] { prompt_connector->stop(); },
1648 [&, this] { prompt_connector->start(); });
1649
1650@@ -161,6 +166,7 @@
1651 std::shared_ptr<mi::InputDispatcher> const input_dispatcher;
1652 std::shared_ptr<mc::Compositor> const compositor;
1653 std::shared_ptr<mf::Connector> const connector;
1654+ std::shared_ptr<mf::Connector> const wayland_connector;
1655 std::shared_ptr<mf::Connector> const prompt_connector;
1656 std::shared_ptr<mi::InputManager> const input_manager;
1657 std::shared_ptr<mir::MainLoop> const main_loop;
1658@@ -196,11 +202,13 @@
1659 server.input_dispatcher->start();
1660 server.prompt_connector->start();
1661 server.connector->start();
1662+ server.wayland_connector->start();
1663
1664 server.server_status_listener->started();
1665
1666 server.main_loop->run();
1667
1668+ server.wayland_connector->stop();
1669 server.connector->stop();
1670 server.prompt_connector->stop();
1671 server.input_dispatcher->stop();
1672
1673=== modified file 'src/server/frontend/CMakeLists.txt'
1674--- src/server/frontend/CMakeLists.txt 2017-07-04 04:38:55 +0000
1675+++ src/server/frontend/CMakeLists.txt 2017-09-07 05:58:57 +0000
1676@@ -36,6 +36,8 @@
1677 ${PROJECT_SOURCE_DIR}/src/include/server/mir/frontend/shell.h
1678 )
1679
1680+add_subdirectory(wayland)
1681+
1682 add_library(
1683 mirfrontend OBJECT
1684
1685
1686=== added directory 'src/server/frontend/wayland'
1687=== added file 'src/server/frontend/wayland/CMakeLists.txt'
1688--- src/server/frontend/wayland/CMakeLists.txt 1970-01-01 00:00:00 +0000
1689+++ src/server/frontend/wayland/CMakeLists.txt 2017-09-07 05:58:57 +0000
1690@@ -0,0 +1,14 @@
1691+set(
1692+ WAYLAND_SOURCES
1693+
1694+ core_generated_interfaces.h
1695+ wayland_default_configuration.cpp
1696+ wayland_connector.cpp
1697+)
1698+
1699+add_library(
1700+ mirfrontend-wayland OBJECT
1701+
1702+ ${WAYLAND_SOURCES}
1703+)
1704+
1705
1706=== added file 'src/server/frontend/wayland/core_generated_interfaces.h'
1707--- src/server/frontend/wayland/core_generated_interfaces.h 1970-01-01 00:00:00 +0000
1708+++ src/server/frontend/wayland/core_generated_interfaces.h 2017-09-07 05:58:57 +0000
1709@@ -0,0 +1,1189 @@
1710+/*
1711+ * AUTOGENERATED - DO NOT EDIT
1712+ *
1713+ * This header is generated by src/protocol/wrapper_generator.cpp
1714+ * To regenerate, run the “refresh-wayland-wrapper” target.
1715+ */
1716+
1717+#include <experimental/optional>
1718+#include <boost/throw_exception.hpp>
1719+
1720+#include <wayland-server.h>
1721+#include <wayland-server-protocol.h>
1722+
1723+#include "mir/fd.h"
1724+
1725+namespace mir
1726+{
1727+namespace frontend
1728+{
1729+namespace wayland
1730+{
1731+class Callback
1732+{
1733+protected:
1734+ Callback(struct wl_client* client, struct wl_resource* parent, uint32_t id)
1735+ : client{client},
1736+ resource{wl_resource_create(client, &wl_callback_interface, wl_resource_get_version(parent), id)}
1737+ {
1738+ if (resource == nullptr)
1739+ {
1740+ wl_resource_post_no_memory(parent);
1741+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1742+ }
1743+ }
1744+ virtual ~Callback() = default;
1745+
1746+
1747+ struct wl_client* const client;
1748+ struct wl_resource* const resource;
1749+
1750+};
1751+
1752+
1753+
1754+class Compositor
1755+{
1756+protected:
1757+ Compositor(struct wl_display* display, uint32_t max_version)
1758+ : max_version{max_version}
1759+ {
1760+ if (!wl_global_create(display,
1761+ &wl_compositor_interface, max_version,
1762+ this, &Compositor::bind))
1763+ {
1764+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_compositor interface"}));
1765+ }
1766+ }
1767+ virtual ~Compositor() = default;
1768+
1769+ virtual void create_surface(struct wl_client* client, struct wl_resource* resource, uint32_t id) = 0;
1770+ virtual void create_region(struct wl_client* client, struct wl_resource* resource, uint32_t id) = 0;
1771+
1772+private:
1773+ static void create_surface_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
1774+ {
1775+ auto me = static_cast<Compositor*>(wl_resource_get_user_data(resource));
1776+ me->create_surface(client, resource, id);
1777+ }
1778+
1779+ static void create_region_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
1780+ {
1781+ auto me = static_cast<Compositor*>(wl_resource_get_user_data(resource));
1782+ me->create_region(client, resource, id);
1783+ }
1784+
1785+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
1786+ {
1787+ auto me = static_cast<Compositor*>(data);
1788+ auto resource = wl_resource_create(client, &wl_compositor_interface,
1789+ std::min(version, me->max_version), id);
1790+ if (resource == nullptr)
1791+ {
1792+ wl_client_post_no_memory(client);
1793+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1794+ }
1795+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
1796+ }
1797+
1798+ uint32_t const max_version;
1799+ static struct wl_compositor_interface const vtable;
1800+};
1801+
1802+struct wl_compositor_interface const Compositor::vtable = {
1803+ create_surface_thunk,
1804+ create_region_thunk,
1805+};
1806+
1807+
1808+class ShmPool
1809+{
1810+protected:
1811+ ShmPool(struct wl_client* client, struct wl_resource* parent, uint32_t id)
1812+ : client{client},
1813+ resource{wl_resource_create(client, &wl_shm_pool_interface, wl_resource_get_version(parent), id)}
1814+ {
1815+ if (resource == nullptr)
1816+ {
1817+ wl_resource_post_no_memory(parent);
1818+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1819+ }
1820+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
1821+ }
1822+ virtual ~ShmPool() = default;
1823+
1824+ virtual void create_buffer(uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) = 0;
1825+ virtual void destroy() = 0;
1826+ virtual void resize(int32_t size) = 0;
1827+
1828+ struct wl_client* const client;
1829+ struct wl_resource* const resource;
1830+
1831+private:
1832+ static void create_buffer_thunk(struct wl_client*, struct wl_resource* resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
1833+ {
1834+ auto me = static_cast<ShmPool*>(wl_resource_get_user_data(resource));
1835+ me->create_buffer(id, offset, width, height, stride, format);
1836+ }
1837+
1838+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
1839+ {
1840+ auto me = static_cast<ShmPool*>(wl_resource_get_user_data(resource));
1841+ me->destroy();
1842+ }
1843+
1844+ static void resize_thunk(struct wl_client*, struct wl_resource* resource, int32_t size)
1845+ {
1846+ auto me = static_cast<ShmPool*>(wl_resource_get_user_data(resource));
1847+ me->resize(size);
1848+ }
1849+
1850+ static struct wl_shm_pool_interface const vtable;
1851+};
1852+
1853+struct wl_shm_pool_interface const ShmPool::vtable = {
1854+ create_buffer_thunk,
1855+ destroy_thunk,
1856+ resize_thunk,
1857+};
1858+
1859+
1860+class Shm
1861+{
1862+protected:
1863+ Shm(struct wl_display* display, uint32_t max_version)
1864+ : max_version{max_version}
1865+ {
1866+ if (!wl_global_create(display,
1867+ &wl_shm_interface, max_version,
1868+ this, &Shm::bind))
1869+ {
1870+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_shm interface"}));
1871+ }
1872+ }
1873+ virtual ~Shm() = default;
1874+
1875+ virtual void create_pool(struct wl_client* client, struct wl_resource* resource, uint32_t id, mir::Fd fd, int32_t size) = 0;
1876+
1877+private:
1878+ static void create_pool_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, int fd, int32_t size)
1879+ {
1880+ auto me = static_cast<Shm*>(wl_resource_get_user_data(resource));
1881+ mir::Fd fd_resolved{fd};
1882+ me->create_pool(client, resource, id, fd_resolved, size);
1883+ }
1884+
1885+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
1886+ {
1887+ auto me = static_cast<Shm*>(data);
1888+ auto resource = wl_resource_create(client, &wl_shm_interface,
1889+ std::min(version, me->max_version), id);
1890+ if (resource == nullptr)
1891+ {
1892+ wl_client_post_no_memory(client);
1893+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1894+ }
1895+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
1896+ }
1897+
1898+ uint32_t const max_version;
1899+ static struct wl_shm_interface const vtable;
1900+};
1901+
1902+struct wl_shm_interface const Shm::vtable = {
1903+ create_pool_thunk,
1904+};
1905+
1906+
1907+class Buffer
1908+{
1909+protected:
1910+ Buffer(struct wl_client* client, struct wl_resource* parent, uint32_t id)
1911+ : client{client},
1912+ resource{wl_resource_create(client, &wl_buffer_interface, wl_resource_get_version(parent), id)}
1913+ {
1914+ if (resource == nullptr)
1915+ {
1916+ wl_resource_post_no_memory(parent);
1917+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1918+ }
1919+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
1920+ }
1921+ virtual ~Buffer() = default;
1922+
1923+ virtual void destroy() = 0;
1924+
1925+ struct wl_client* const client;
1926+ struct wl_resource* const resource;
1927+
1928+private:
1929+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
1930+ {
1931+ auto me = static_cast<Buffer*>(wl_resource_get_user_data(resource));
1932+ me->destroy();
1933+ }
1934+
1935+ static struct wl_buffer_interface const vtable;
1936+};
1937+
1938+struct wl_buffer_interface const Buffer::vtable = {
1939+ destroy_thunk,
1940+};
1941+
1942+
1943+class DataOffer
1944+{
1945+protected:
1946+ DataOffer(struct wl_client* client, struct wl_resource* parent, uint32_t id)
1947+ : client{client},
1948+ resource{wl_resource_create(client, &wl_data_offer_interface, wl_resource_get_version(parent), id)}
1949+ {
1950+ if (resource == nullptr)
1951+ {
1952+ wl_resource_post_no_memory(parent);
1953+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
1954+ }
1955+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
1956+ }
1957+ virtual ~DataOffer() = default;
1958+
1959+ virtual void accept(uint32_t serial, std::experimental::optional<std::string> const& mime_type) = 0;
1960+ virtual void receive(std::string const& mime_type, mir::Fd fd) = 0;
1961+ virtual void destroy() = 0;
1962+ virtual void finish() = 0;
1963+ virtual void set_actions(uint32_t dnd_actions, uint32_t preferred_action) = 0;
1964+
1965+ struct wl_client* const client;
1966+ struct wl_resource* const resource;
1967+
1968+private:
1969+ static void accept_thunk(struct wl_client*, struct wl_resource* resource, uint32_t serial, char const* mime_type)
1970+ {
1971+ auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
1972+ std::experimental::optional<std::string> mime_type_resolved;
1973+ if (mime_type != nullptr)
1974+ {
1975+ mime_type_resolved = std::experimental::make_optional<std::string>(mime_type);
1976+ }
1977+ me->accept(serial, mime_type_resolved);
1978+ }
1979+
1980+ static void receive_thunk(struct wl_client*, struct wl_resource* resource, char const* mime_type, int fd)
1981+ {
1982+ auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
1983+ mir::Fd fd_resolved{fd};
1984+ me->receive(mime_type, fd_resolved);
1985+ }
1986+
1987+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
1988+ {
1989+ auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
1990+ me->destroy();
1991+ }
1992+
1993+ static void finish_thunk(struct wl_client*, struct wl_resource* resource)
1994+ {
1995+ auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
1996+ me->finish();
1997+ }
1998+
1999+ static void set_actions_thunk(struct wl_client*, struct wl_resource* resource, uint32_t dnd_actions, uint32_t preferred_action)
2000+ {
2001+ auto me = static_cast<DataOffer*>(wl_resource_get_user_data(resource));
2002+ me->set_actions(dnd_actions, preferred_action);
2003+ }
2004+
2005+ static struct wl_data_offer_interface const vtable;
2006+};
2007+
2008+struct wl_data_offer_interface const DataOffer::vtable = {
2009+ accept_thunk,
2010+ receive_thunk,
2011+ destroy_thunk,
2012+ finish_thunk,
2013+ set_actions_thunk,
2014+};
2015+
2016+
2017+class DataSource
2018+{
2019+protected:
2020+ DataSource(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2021+ : client{client},
2022+ resource{wl_resource_create(client, &wl_data_source_interface, wl_resource_get_version(parent), id)}
2023+ {
2024+ if (resource == nullptr)
2025+ {
2026+ wl_resource_post_no_memory(parent);
2027+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2028+ }
2029+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2030+ }
2031+ virtual ~DataSource() = default;
2032+
2033+ virtual void offer(std::string const& mime_type) = 0;
2034+ virtual void destroy() = 0;
2035+ virtual void set_actions(uint32_t dnd_actions) = 0;
2036+
2037+ struct wl_client* const client;
2038+ struct wl_resource* const resource;
2039+
2040+private:
2041+ static void offer_thunk(struct wl_client*, struct wl_resource* resource, char const* mime_type)
2042+ {
2043+ auto me = static_cast<DataSource*>(wl_resource_get_user_data(resource));
2044+ me->offer(mime_type);
2045+ }
2046+
2047+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
2048+ {
2049+ auto me = static_cast<DataSource*>(wl_resource_get_user_data(resource));
2050+ me->destroy();
2051+ }
2052+
2053+ static void set_actions_thunk(struct wl_client*, struct wl_resource* resource, uint32_t dnd_actions)
2054+ {
2055+ auto me = static_cast<DataSource*>(wl_resource_get_user_data(resource));
2056+ me->set_actions(dnd_actions);
2057+ }
2058+
2059+ static struct wl_data_source_interface const vtable;
2060+};
2061+
2062+struct wl_data_source_interface const DataSource::vtable = {
2063+ offer_thunk,
2064+ destroy_thunk,
2065+ set_actions_thunk,
2066+};
2067+
2068+
2069+class DataDevice
2070+{
2071+protected:
2072+ DataDevice(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2073+ : client{client},
2074+ resource{wl_resource_create(client, &wl_data_device_interface, wl_resource_get_version(parent), id)}
2075+ {
2076+ if (resource == nullptr)
2077+ {
2078+ wl_resource_post_no_memory(parent);
2079+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2080+ }
2081+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2082+ }
2083+ virtual ~DataDevice() = default;
2084+
2085+ virtual void start_drag(std::experimental::optional<struct wl_resource*> const& source, struct wl_resource* origin, std::experimental::optional<struct wl_resource*> const& icon, uint32_t serial) = 0;
2086+ virtual void set_selection(std::experimental::optional<struct wl_resource*> const& source, uint32_t serial) = 0;
2087+ virtual void release() = 0;
2088+
2089+ struct wl_client* const client;
2090+ struct wl_resource* const resource;
2091+
2092+private:
2093+ static void start_drag_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* source, struct wl_resource* origin, struct wl_resource* icon, uint32_t serial)
2094+ {
2095+ auto me = static_cast<DataDevice*>(wl_resource_get_user_data(resource));
2096+ std::experimental::optional<struct wl_resource*> source_resolved;
2097+ if (source != nullptr)
2098+ {
2099+ source_resolved = source;
2100+ }
2101+ std::experimental::optional<struct wl_resource*> icon_resolved;
2102+ if (icon != nullptr)
2103+ {
2104+ icon_resolved = icon;
2105+ }
2106+ me->start_drag(source_resolved, origin, icon_resolved, serial);
2107+ }
2108+
2109+ static void set_selection_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* source, uint32_t serial)
2110+ {
2111+ auto me = static_cast<DataDevice*>(wl_resource_get_user_data(resource));
2112+ std::experimental::optional<struct wl_resource*> source_resolved;
2113+ if (source != nullptr)
2114+ {
2115+ source_resolved = source;
2116+ }
2117+ me->set_selection(source_resolved, serial);
2118+ }
2119+
2120+ static void release_thunk(struct wl_client*, struct wl_resource* resource)
2121+ {
2122+ auto me = static_cast<DataDevice*>(wl_resource_get_user_data(resource));
2123+ me->release();
2124+ }
2125+
2126+ static struct wl_data_device_interface const vtable;
2127+};
2128+
2129+struct wl_data_device_interface const DataDevice::vtable = {
2130+ start_drag_thunk,
2131+ set_selection_thunk,
2132+ release_thunk,
2133+};
2134+
2135+
2136+class DataDeviceManager
2137+{
2138+protected:
2139+ DataDeviceManager(struct wl_display* display, uint32_t max_version)
2140+ : max_version{max_version}
2141+ {
2142+ if (!wl_global_create(display,
2143+ &wl_data_device_manager_interface, max_version,
2144+ this, &DataDeviceManager::bind))
2145+ {
2146+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_data_device_manager interface"}));
2147+ }
2148+ }
2149+ virtual ~DataDeviceManager() = default;
2150+
2151+ virtual void create_data_source(struct wl_client* client, struct wl_resource* resource, uint32_t id) = 0;
2152+ virtual void get_data_device(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* seat) = 0;
2153+
2154+private:
2155+ static void create_data_source_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
2156+ {
2157+ auto me = static_cast<DataDeviceManager*>(wl_resource_get_user_data(resource));
2158+ me->create_data_source(client, resource, id);
2159+ }
2160+
2161+ static void get_data_device_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* seat)
2162+ {
2163+ auto me = static_cast<DataDeviceManager*>(wl_resource_get_user_data(resource));
2164+ me->get_data_device(client, resource, id, seat);
2165+ }
2166+
2167+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
2168+ {
2169+ auto me = static_cast<DataDeviceManager*>(data);
2170+ auto resource = wl_resource_create(client, &wl_data_device_manager_interface,
2171+ std::min(version, me->max_version), id);
2172+ if (resource == nullptr)
2173+ {
2174+ wl_client_post_no_memory(client);
2175+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2176+ }
2177+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
2178+ }
2179+
2180+ uint32_t const max_version;
2181+ static struct wl_data_device_manager_interface const vtable;
2182+};
2183+
2184+struct wl_data_device_manager_interface const DataDeviceManager::vtable = {
2185+ create_data_source_thunk,
2186+ get_data_device_thunk,
2187+};
2188+
2189+
2190+class Shell
2191+{
2192+protected:
2193+ Shell(struct wl_display* display, uint32_t max_version)
2194+ : max_version{max_version}
2195+ {
2196+ if (!wl_global_create(display,
2197+ &wl_shell_interface, max_version,
2198+ this, &Shell::bind))
2199+ {
2200+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_shell interface"}));
2201+ }
2202+ }
2203+ virtual ~Shell() = default;
2204+
2205+ virtual void get_shell_surface(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* surface) = 0;
2206+
2207+private:
2208+ static void get_shell_surface_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* surface)
2209+ {
2210+ auto me = static_cast<Shell*>(wl_resource_get_user_data(resource));
2211+ me->get_shell_surface(client, resource, id, surface);
2212+ }
2213+
2214+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
2215+ {
2216+ auto me = static_cast<Shell*>(data);
2217+ auto resource = wl_resource_create(client, &wl_shell_interface,
2218+ std::min(version, me->max_version), id);
2219+ if (resource == nullptr)
2220+ {
2221+ wl_client_post_no_memory(client);
2222+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2223+ }
2224+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
2225+ }
2226+
2227+ uint32_t const max_version;
2228+ static struct wl_shell_interface const vtable;
2229+};
2230+
2231+struct wl_shell_interface const Shell::vtable = {
2232+ get_shell_surface_thunk,
2233+};
2234+
2235+
2236+class ShellSurface
2237+{
2238+protected:
2239+ ShellSurface(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2240+ : client{client},
2241+ resource{wl_resource_create(client, &wl_shell_surface_interface, wl_resource_get_version(parent), id)}
2242+ {
2243+ if (resource == nullptr)
2244+ {
2245+ wl_resource_post_no_memory(parent);
2246+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2247+ }
2248+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2249+ }
2250+ virtual ~ShellSurface() = default;
2251+
2252+ virtual void pong(uint32_t serial) = 0;
2253+ virtual void move(struct wl_resource* seat, uint32_t serial) = 0;
2254+ virtual void resize(struct wl_resource* seat, uint32_t serial, uint32_t edges) = 0;
2255+ virtual void set_toplevel() = 0;
2256+ virtual void set_transient(struct wl_resource* parent, int32_t x, int32_t y, uint32_t flags) = 0;
2257+ virtual void set_fullscreen(uint32_t method, uint32_t framerate, std::experimental::optional<struct wl_resource*> const& output) = 0;
2258+ virtual void set_popup(struct wl_resource* seat, uint32_t serial, struct wl_resource* parent, int32_t x, int32_t y, uint32_t flags) = 0;
2259+ virtual void set_maximized(std::experimental::optional<struct wl_resource*> const& output) = 0;
2260+ virtual void set_title(std::string const& title) = 0;
2261+ virtual void set_class(std::string const& class_) = 0;
2262+
2263+ struct wl_client* const client;
2264+ struct wl_resource* const resource;
2265+
2266+private:
2267+ static void pong_thunk(struct wl_client*, struct wl_resource* resource, uint32_t serial)
2268+ {
2269+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2270+ me->pong(serial);
2271+ }
2272+
2273+ static void move_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* seat, uint32_t serial)
2274+ {
2275+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2276+ me->move(seat, serial);
2277+ }
2278+
2279+ static void resize_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* seat, uint32_t serial, uint32_t edges)
2280+ {
2281+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2282+ me->resize(seat, serial, edges);
2283+ }
2284+
2285+ static void set_toplevel_thunk(struct wl_client*, struct wl_resource* resource)
2286+ {
2287+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2288+ me->set_toplevel();
2289+ }
2290+
2291+ static void set_transient_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* parent, int32_t x, int32_t y, uint32_t flags)
2292+ {
2293+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2294+ me->set_transient(parent, x, y, flags);
2295+ }
2296+
2297+ static void set_fullscreen_thunk(struct wl_client*, struct wl_resource* resource, uint32_t method, uint32_t framerate, struct wl_resource* output)
2298+ {
2299+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2300+ std::experimental::optional<struct wl_resource*> output_resolved;
2301+ if (output != nullptr)
2302+ {
2303+ output_resolved = output;
2304+ }
2305+ me->set_fullscreen(method, framerate, output_resolved);
2306+ }
2307+
2308+ static void set_popup_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* seat, uint32_t serial, struct wl_resource* parent, int32_t x, int32_t y, uint32_t flags)
2309+ {
2310+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2311+ me->set_popup(seat, serial, parent, x, y, flags);
2312+ }
2313+
2314+ static void set_maximized_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* output)
2315+ {
2316+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2317+ std::experimental::optional<struct wl_resource*> output_resolved;
2318+ if (output != nullptr)
2319+ {
2320+ output_resolved = output;
2321+ }
2322+ me->set_maximized(output_resolved);
2323+ }
2324+
2325+ static void set_title_thunk(struct wl_client*, struct wl_resource* resource, char const* title)
2326+ {
2327+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2328+ me->set_title(title);
2329+ }
2330+
2331+ static void set_class_thunk(struct wl_client*, struct wl_resource* resource, char const* class_)
2332+ {
2333+ auto me = static_cast<ShellSurface*>(wl_resource_get_user_data(resource));
2334+ me->set_class(class_);
2335+ }
2336+
2337+ static struct wl_shell_surface_interface const vtable;
2338+};
2339+
2340+struct wl_shell_surface_interface const ShellSurface::vtable = {
2341+ pong_thunk,
2342+ move_thunk,
2343+ resize_thunk,
2344+ set_toplevel_thunk,
2345+ set_transient_thunk,
2346+ set_fullscreen_thunk,
2347+ set_popup_thunk,
2348+ set_maximized_thunk,
2349+ set_title_thunk,
2350+ set_class_thunk,
2351+};
2352+
2353+
2354+class Surface
2355+{
2356+protected:
2357+ Surface(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2358+ : client{client},
2359+ resource{wl_resource_create(client, &wl_surface_interface, wl_resource_get_version(parent), id)}
2360+ {
2361+ if (resource == nullptr)
2362+ {
2363+ wl_resource_post_no_memory(parent);
2364+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2365+ }
2366+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2367+ }
2368+ virtual ~Surface() = default;
2369+
2370+ virtual void destroy() = 0;
2371+ virtual void attach(std::experimental::optional<struct wl_resource*> const& buffer, int32_t x, int32_t y) = 0;
2372+ virtual void damage(int32_t x, int32_t y, int32_t width, int32_t height) = 0;
2373+ virtual void frame(uint32_t callback) = 0;
2374+ virtual void set_opaque_region(std::experimental::optional<struct wl_resource*> const& region) = 0;
2375+ virtual void set_input_region(std::experimental::optional<struct wl_resource*> const& region) = 0;
2376+ virtual void commit() = 0;
2377+ virtual void set_buffer_transform(int32_t transform) = 0;
2378+ virtual void set_buffer_scale(int32_t scale) = 0;
2379+ virtual void damage_buffer(int32_t x, int32_t y, int32_t width, int32_t height) = 0;
2380+
2381+ struct wl_client* const client;
2382+ struct wl_resource* const resource;
2383+
2384+private:
2385+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
2386+ {
2387+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2388+ me->destroy();
2389+ }
2390+
2391+ static void attach_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* buffer, int32_t x, int32_t y)
2392+ {
2393+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2394+ std::experimental::optional<struct wl_resource*> buffer_resolved;
2395+ if (buffer != nullptr)
2396+ {
2397+ buffer_resolved = buffer;
2398+ }
2399+ me->attach(buffer_resolved, x, y);
2400+ }
2401+
2402+ static void damage_thunk(struct wl_client*, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
2403+ {
2404+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2405+ me->damage(x, y, width, height);
2406+ }
2407+
2408+ static void frame_thunk(struct wl_client*, struct wl_resource* resource, uint32_t callback)
2409+ {
2410+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2411+ me->frame(callback);
2412+ }
2413+
2414+ static void set_opaque_region_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* region)
2415+ {
2416+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2417+ std::experimental::optional<struct wl_resource*> region_resolved;
2418+ if (region != nullptr)
2419+ {
2420+ region_resolved = region;
2421+ }
2422+ me->set_opaque_region(region_resolved);
2423+ }
2424+
2425+ static void set_input_region_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* region)
2426+ {
2427+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2428+ std::experimental::optional<struct wl_resource*> region_resolved;
2429+ if (region != nullptr)
2430+ {
2431+ region_resolved = region;
2432+ }
2433+ me->set_input_region(region_resolved);
2434+ }
2435+
2436+ static void commit_thunk(struct wl_client*, struct wl_resource* resource)
2437+ {
2438+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2439+ me->commit();
2440+ }
2441+
2442+ static void set_buffer_transform_thunk(struct wl_client*, struct wl_resource* resource, int32_t transform)
2443+ {
2444+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2445+ me->set_buffer_transform(transform);
2446+ }
2447+
2448+ static void set_buffer_scale_thunk(struct wl_client*, struct wl_resource* resource, int32_t scale)
2449+ {
2450+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2451+ me->set_buffer_scale(scale);
2452+ }
2453+
2454+ static void damage_buffer_thunk(struct wl_client*, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
2455+ {
2456+ auto me = static_cast<Surface*>(wl_resource_get_user_data(resource));
2457+ me->damage_buffer(x, y, width, height);
2458+ }
2459+
2460+ static struct wl_surface_interface const vtable;
2461+};
2462+
2463+struct wl_surface_interface const Surface::vtable = {
2464+ destroy_thunk,
2465+ attach_thunk,
2466+ damage_thunk,
2467+ frame_thunk,
2468+ set_opaque_region_thunk,
2469+ set_input_region_thunk,
2470+ commit_thunk,
2471+ set_buffer_transform_thunk,
2472+ set_buffer_scale_thunk,
2473+ damage_buffer_thunk,
2474+};
2475+
2476+
2477+class Seat
2478+{
2479+protected:
2480+ Seat(struct wl_display* display, uint32_t max_version)
2481+ : max_version{max_version}
2482+ {
2483+ if (!wl_global_create(display,
2484+ &wl_seat_interface, max_version,
2485+ this, &Seat::bind))
2486+ {
2487+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_seat interface"}));
2488+ }
2489+ }
2490+ virtual ~Seat() = default;
2491+
2492+ virtual void get_pointer(struct wl_client* client, struct wl_resource* resource, uint32_t id) = 0;
2493+ virtual void get_keyboard(struct wl_client* client, struct wl_resource* resource, uint32_t id) = 0;
2494+ virtual void get_touch(struct wl_client* client, struct wl_resource* resource, uint32_t id) = 0;
2495+ virtual void release(struct wl_client* client, struct wl_resource* resource) = 0;
2496+
2497+private:
2498+ static void get_pointer_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
2499+ {
2500+ auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
2501+ me->get_pointer(client, resource, id);
2502+ }
2503+
2504+ static void get_keyboard_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
2505+ {
2506+ auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
2507+ me->get_keyboard(client, resource, id);
2508+ }
2509+
2510+ static void get_touch_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id)
2511+ {
2512+ auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
2513+ me->get_touch(client, resource, id);
2514+ }
2515+
2516+ static void release_thunk(struct wl_client* client, struct wl_resource* resource)
2517+ {
2518+ auto me = static_cast<Seat*>(wl_resource_get_user_data(resource));
2519+ me->release(client, resource);
2520+ }
2521+
2522+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
2523+ {
2524+ auto me = static_cast<Seat*>(data);
2525+ auto resource = wl_resource_create(client, &wl_seat_interface,
2526+ std::min(version, me->max_version), id);
2527+ if (resource == nullptr)
2528+ {
2529+ wl_client_post_no_memory(client);
2530+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2531+ }
2532+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
2533+ }
2534+
2535+ uint32_t const max_version;
2536+ static struct wl_seat_interface const vtable;
2537+};
2538+
2539+struct wl_seat_interface const Seat::vtable = {
2540+ get_pointer_thunk,
2541+ get_keyboard_thunk,
2542+ get_touch_thunk,
2543+ release_thunk,
2544+};
2545+
2546+
2547+class Pointer
2548+{
2549+protected:
2550+ Pointer(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2551+ : client{client},
2552+ resource{wl_resource_create(client, &wl_pointer_interface, wl_resource_get_version(parent), id)}
2553+ {
2554+ if (resource == nullptr)
2555+ {
2556+ wl_resource_post_no_memory(parent);
2557+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2558+ }
2559+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2560+ }
2561+ virtual ~Pointer() = default;
2562+
2563+ virtual void set_cursor(uint32_t serial, std::experimental::optional<struct wl_resource*> const& surface, int32_t hotspot_x, int32_t hotspot_y) = 0;
2564+ virtual void release() = 0;
2565+
2566+ struct wl_client* const client;
2567+ struct wl_resource* const resource;
2568+
2569+private:
2570+ static void set_cursor_thunk(struct wl_client*, struct wl_resource* resource, uint32_t serial, struct wl_resource* surface, int32_t hotspot_x, int32_t hotspot_y)
2571+ {
2572+ auto me = static_cast<Pointer*>(wl_resource_get_user_data(resource));
2573+ std::experimental::optional<struct wl_resource*> surface_resolved;
2574+ if (surface != nullptr)
2575+ {
2576+ surface_resolved = surface;
2577+ }
2578+ me->set_cursor(serial, surface_resolved, hotspot_x, hotspot_y);
2579+ }
2580+
2581+ static void release_thunk(struct wl_client*, struct wl_resource* resource)
2582+ {
2583+ auto me = static_cast<Pointer*>(wl_resource_get_user_data(resource));
2584+ me->release();
2585+ }
2586+
2587+ static struct wl_pointer_interface const vtable;
2588+};
2589+
2590+struct wl_pointer_interface const Pointer::vtable = {
2591+ set_cursor_thunk,
2592+ release_thunk,
2593+};
2594+
2595+
2596+class Keyboard
2597+{
2598+protected:
2599+ Keyboard(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2600+ : client{client},
2601+ resource{wl_resource_create(client, &wl_keyboard_interface, wl_resource_get_version(parent), id)}
2602+ {
2603+ if (resource == nullptr)
2604+ {
2605+ wl_resource_post_no_memory(parent);
2606+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2607+ }
2608+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2609+ }
2610+ virtual ~Keyboard() = default;
2611+
2612+ virtual void release() = 0;
2613+
2614+ struct wl_client* const client;
2615+ struct wl_resource* const resource;
2616+
2617+private:
2618+ static void release_thunk(struct wl_client*, struct wl_resource* resource)
2619+ {
2620+ auto me = static_cast<Keyboard*>(wl_resource_get_user_data(resource));
2621+ me->release();
2622+ }
2623+
2624+ static struct wl_keyboard_interface const vtable;
2625+};
2626+
2627+struct wl_keyboard_interface const Keyboard::vtable = {
2628+ release_thunk,
2629+};
2630+
2631+
2632+class Touch
2633+{
2634+protected:
2635+ Touch(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2636+ : client{client},
2637+ resource{wl_resource_create(client, &wl_touch_interface, wl_resource_get_version(parent), id)}
2638+ {
2639+ if (resource == nullptr)
2640+ {
2641+ wl_resource_post_no_memory(parent);
2642+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2643+ }
2644+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2645+ }
2646+ virtual ~Touch() = default;
2647+
2648+ virtual void release() = 0;
2649+
2650+ struct wl_client* const client;
2651+ struct wl_resource* const resource;
2652+
2653+private:
2654+ static void release_thunk(struct wl_client*, struct wl_resource* resource)
2655+ {
2656+ auto me = static_cast<Touch*>(wl_resource_get_user_data(resource));
2657+ me->release();
2658+ }
2659+
2660+ static struct wl_touch_interface const vtable;
2661+};
2662+
2663+struct wl_touch_interface const Touch::vtable = {
2664+ release_thunk,
2665+};
2666+
2667+
2668+class Output
2669+{
2670+protected:
2671+ Output(struct wl_display* display, uint32_t max_version)
2672+ : max_version{max_version}
2673+ {
2674+ if (!wl_global_create(display,
2675+ &wl_output_interface, max_version,
2676+ this, &Output::bind))
2677+ {
2678+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_output interface"}));
2679+ }
2680+ }
2681+ virtual ~Output() = default;
2682+
2683+ virtual void release(struct wl_client* client, struct wl_resource* resource) = 0;
2684+
2685+private:
2686+ static void release_thunk(struct wl_client* client, struct wl_resource* resource)
2687+ {
2688+ auto me = static_cast<Output*>(wl_resource_get_user_data(resource));
2689+ me->release(client, resource);
2690+ }
2691+
2692+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
2693+ {
2694+ auto me = static_cast<Output*>(data);
2695+ auto resource = wl_resource_create(client, &wl_output_interface,
2696+ std::min(version, me->max_version), id);
2697+ if (resource == nullptr)
2698+ {
2699+ wl_client_post_no_memory(client);
2700+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2701+ }
2702+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
2703+ }
2704+
2705+ uint32_t const max_version;
2706+ static struct wl_output_interface const vtable;
2707+};
2708+
2709+struct wl_output_interface const Output::vtable = {
2710+ release_thunk,
2711+};
2712+
2713+
2714+class Region
2715+{
2716+protected:
2717+ Region(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2718+ : client{client},
2719+ resource{wl_resource_create(client, &wl_region_interface, wl_resource_get_version(parent), id)}
2720+ {
2721+ if (resource == nullptr)
2722+ {
2723+ wl_resource_post_no_memory(parent);
2724+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2725+ }
2726+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2727+ }
2728+ virtual ~Region() = default;
2729+
2730+ virtual void destroy() = 0;
2731+ virtual void add(int32_t x, int32_t y, int32_t width, int32_t height) = 0;
2732+ virtual void subtract(int32_t x, int32_t y, int32_t width, int32_t height) = 0;
2733+
2734+ struct wl_client* const client;
2735+ struct wl_resource* const resource;
2736+
2737+private:
2738+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
2739+ {
2740+ auto me = static_cast<Region*>(wl_resource_get_user_data(resource));
2741+ me->destroy();
2742+ }
2743+
2744+ static void add_thunk(struct wl_client*, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
2745+ {
2746+ auto me = static_cast<Region*>(wl_resource_get_user_data(resource));
2747+ me->add(x, y, width, height);
2748+ }
2749+
2750+ static void subtract_thunk(struct wl_client*, struct wl_resource* resource, int32_t x, int32_t y, int32_t width, int32_t height)
2751+ {
2752+ auto me = static_cast<Region*>(wl_resource_get_user_data(resource));
2753+ me->subtract(x, y, width, height);
2754+ }
2755+
2756+ static struct wl_region_interface const vtable;
2757+};
2758+
2759+struct wl_region_interface const Region::vtable = {
2760+ destroy_thunk,
2761+ add_thunk,
2762+ subtract_thunk,
2763+};
2764+
2765+
2766+class Subcompositor
2767+{
2768+protected:
2769+ Subcompositor(struct wl_display* display, uint32_t max_version)
2770+ : max_version{max_version}
2771+ {
2772+ if (!wl_global_create(display,
2773+ &wl_subcompositor_interface, max_version,
2774+ this, &Subcompositor::bind))
2775+ {
2776+ BOOST_THROW_EXCEPTION((std::runtime_error{"Failed to export wl_subcompositor interface"}));
2777+ }
2778+ }
2779+ virtual ~Subcompositor() = default;
2780+
2781+ virtual void destroy(struct wl_client* client, struct wl_resource* resource) = 0;
2782+ virtual void get_subsurface(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* surface, struct wl_resource* parent) = 0;
2783+
2784+private:
2785+ static void destroy_thunk(struct wl_client* client, struct wl_resource* resource)
2786+ {
2787+ auto me = static_cast<Subcompositor*>(wl_resource_get_user_data(resource));
2788+ me->destroy(client, resource);
2789+ }
2790+
2791+ static void get_subsurface_thunk(struct wl_client* client, struct wl_resource* resource, uint32_t id, struct wl_resource* surface, struct wl_resource* parent)
2792+ {
2793+ auto me = static_cast<Subcompositor*>(wl_resource_get_user_data(resource));
2794+ me->get_subsurface(client, resource, id, surface, parent);
2795+ }
2796+
2797+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
2798+ {
2799+ auto me = static_cast<Subcompositor*>(data);
2800+ auto resource = wl_resource_create(client, &wl_subcompositor_interface,
2801+ std::min(version, me->max_version), id);
2802+ if (resource == nullptr)
2803+ {
2804+ wl_client_post_no_memory(client);
2805+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2806+ }
2807+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
2808+ }
2809+
2810+ uint32_t const max_version;
2811+ static struct wl_subcompositor_interface const vtable;
2812+};
2813+
2814+struct wl_subcompositor_interface const Subcompositor::vtable = {
2815+ destroy_thunk,
2816+ get_subsurface_thunk,
2817+};
2818+
2819+
2820+class Subsurface
2821+{
2822+protected:
2823+ Subsurface(struct wl_client* client, struct wl_resource* parent, uint32_t id)
2824+ : client{client},
2825+ resource{wl_resource_create(client, &wl_subsurface_interface, wl_resource_get_version(parent), id)}
2826+ {
2827+ if (resource == nullptr)
2828+ {
2829+ wl_resource_post_no_memory(parent);
2830+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
2831+ }
2832+ wl_resource_set_implementation(resource, &vtable, this, nullptr);
2833+ }
2834+ virtual ~Subsurface() = default;
2835+
2836+ virtual void destroy() = 0;
2837+ virtual void set_position(int32_t x, int32_t y) = 0;
2838+ virtual void place_above(struct wl_resource* sibling) = 0;
2839+ virtual void place_below(struct wl_resource* sibling) = 0;
2840+ virtual void set_sync() = 0;
2841+ virtual void set_desync() = 0;
2842+
2843+ struct wl_client* const client;
2844+ struct wl_resource* const resource;
2845+
2846+private:
2847+ static void destroy_thunk(struct wl_client*, struct wl_resource* resource)
2848+ {
2849+ auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
2850+ me->destroy();
2851+ }
2852+
2853+ static void set_position_thunk(struct wl_client*, struct wl_resource* resource, int32_t x, int32_t y)
2854+ {
2855+ auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
2856+ me->set_position(x, y);
2857+ }
2858+
2859+ static void place_above_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* sibling)
2860+ {
2861+ auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
2862+ me->place_above(sibling);
2863+ }
2864+
2865+ static void place_below_thunk(struct wl_client*, struct wl_resource* resource, struct wl_resource* sibling)
2866+ {
2867+ auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
2868+ me->place_below(sibling);
2869+ }
2870+
2871+ static void set_sync_thunk(struct wl_client*, struct wl_resource* resource)
2872+ {
2873+ auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
2874+ me->set_sync();
2875+ }
2876+
2877+ static void set_desync_thunk(struct wl_client*, struct wl_resource* resource)
2878+ {
2879+ auto me = static_cast<Subsurface*>(wl_resource_get_user_data(resource));
2880+ me->set_desync();
2881+ }
2882+
2883+ static struct wl_subsurface_interface const vtable;
2884+};
2885+
2886+struct wl_subsurface_interface const Subsurface::vtable = {
2887+ destroy_thunk,
2888+ set_position_thunk,
2889+ place_above_thunk,
2890+ place_below_thunk,
2891+ set_sync_thunk,
2892+ set_desync_thunk,
2893+};
2894+
2895+
2896+}
2897+}
2898+}
2899
2900=== added file 'src/server/frontend/wayland/wayland_connector.cpp'
2901--- src/server/frontend/wayland/wayland_connector.cpp 1970-01-01 00:00:00 +0000
2902+++ src/server/frontend/wayland/wayland_connector.cpp 2017-09-07 05:58:57 +0000
2903@@ -0,0 +1,1785 @@
2904+/*
2905+ * Copyright © 2015 Canonical Ltd.
2906+ *
2907+ * This program is free software: you can redistribute it and/or modify it
2908+ * under the terms of the GNU General Public License version 3,
2909+ * as published by the Free Software Foundation.
2910+ *
2911+ * This program is distributed in the hope that it will be useful,
2912+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2913+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2914+ * GNU General Public License for more details.
2915+ *
2916+ * You should have received a copy of the GNU General Public License
2917+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2918+ *
2919+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
2920+ */
2921+
2922+#include "wayland_connector.h"
2923+
2924+#include "core_generated_interfaces.h"
2925+
2926+#include "mir/frontend/shell.h"
2927+
2928+#include "mir/compositor/buffer_stream.h"
2929+
2930+#include "mir/frontend/session.h"
2931+#include "mir/frontend/event_sink.h"
2932+#include "mir/scene/surface_creation_parameters.h"
2933+
2934+#include "mir/graphics/buffer_properties.h"
2935+#include "mir/graphics/buffer.h"
2936+#include "mir/graphics/display_configuration.h"
2937+#include "mir/graphics/graphic_buffer_allocator.h"
2938+#include "mir/graphics/wayland_allocator.h"
2939+
2940+#include "mir/renderer/gl/texture_target.h"
2941+#include "mir/frontend/buffer_stream_id.h"
2942+#include "mir/frontend/display_changer.h"
2943+
2944+#include "mir/executor.h"
2945+
2946+#include <system_error>
2947+#include <sys/eventfd.h>
2948+#include <wayland-server-core.h>
2949+#include <unordered_map>
2950+#include <boost/throw_exception.hpp>
2951+
2952+#include <future>
2953+#include <functional>
2954+#include <type_traits>
2955+
2956+#include <algorithm>
2957+#include <iostream>
2958+#include <mir/log.h>
2959+#include <cstring>
2960+#include <deque>
2961+#include MIR_SERVER_GL_H
2962+#include MIR_SERVER_GLEXT_H
2963+
2964+#include "mir/fd.h"
2965+#include "../../../platforms/common/server/shm_buffer.h"
2966+
2967+namespace mf = mir::frontend;
2968+namespace mg = mir::graphics;
2969+namespace mc = mir::compositor;
2970+namespace ms = mir::scene;
2971+namespace geom = mir::geometry;
2972+
2973+namespace mir
2974+{
2975+namespace frontend
2976+{
2977+
2978+class WaylandEventSink : public mf::EventSink
2979+{
2980+public:
2981+ WaylandEventSink(std::function<void(MirLifecycleState)> const& lifecycle_handler)
2982+ : lifecycle_handler{lifecycle_handler}
2983+ {
2984+ }
2985+
2986+ void handle_event(const MirEvent& e) override;
2987+ void handle_lifecycle_event(MirLifecycleState state) override;
2988+ void handle_display_config_change(graphics::DisplayConfiguration const& config) override;
2989+ void send_ping(int32_t serial) override;
2990+ void send_buffer(BufferStreamId id, graphics::Buffer& buffer, graphics::BufferIpcMsgType type) override;
2991+ void handle_input_config_change(MirInputConfig const&) override {}
2992+ void handle_error(ClientVisibleError const&) override {}
2993+
2994+ void add_buffer(graphics::Buffer&) override {}
2995+ void error_buffer(geometry::Size, MirPixelFormat, std::string const& ) override {}
2996+ void update_buffer(graphics::Buffer&) override {}
2997+
2998+private:
2999+ std::function<void(MirLifecycleState)> const lifecycle_handler;
3000+};
3001+
3002+namespace
3003+{
3004+bool get_gl_pixel_format(
3005+ MirPixelFormat mir_format,
3006+ GLenum& gl_format,
3007+ GLenum& gl_type)
3008+{
3009+#if __BYTE_ORDER == __LITTLE_ENDIAN
3010+ GLenum const argb = GL_BGRA_EXT;
3011+ GLenum const abgr = GL_RGBA;
3012+#elif __BYTE_ORDER == __BIG_ENDIAN
3013+ // TODO: Big endian support
3014+GLenum const argb = GL_INVALID_ENUM;
3015+GLenum const abgr = GL_INVALID_ENUM;
3016+//GLenum const rgba = GL_RGBA;
3017+//GLenum const bgra = GL_BGRA_EXT;
3018+#endif
3019+
3020+ static const struct
3021+ {
3022+ MirPixelFormat mir_format;
3023+ GLenum gl_format, gl_type;
3024+ } mapping[mir_pixel_formats] =
3025+ {
3026+ {mir_pixel_format_invalid, GL_INVALID_ENUM, GL_INVALID_ENUM},
3027+ {mir_pixel_format_abgr_8888, abgr, GL_UNSIGNED_BYTE},
3028+ {mir_pixel_format_xbgr_8888, abgr, GL_UNSIGNED_BYTE},
3029+ {mir_pixel_format_argb_8888, argb, GL_UNSIGNED_BYTE},
3030+ {mir_pixel_format_xrgb_8888, argb, GL_UNSIGNED_BYTE},
3031+ {mir_pixel_format_bgr_888, GL_INVALID_ENUM, GL_INVALID_ENUM},
3032+ {mir_pixel_format_rgb_888, GL_RGB, GL_UNSIGNED_BYTE},
3033+ {mir_pixel_format_rgb_565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
3034+ {mir_pixel_format_rgba_5551, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1},
3035+ {mir_pixel_format_rgba_4444, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4},
3036+ };
3037+
3038+ if (mir_format > mir_pixel_format_invalid &&
3039+ mir_format < mir_pixel_formats &&
3040+ mapping[mir_format].mir_format == mir_format) // just a sanity check
3041+ {
3042+ gl_format = mapping[mir_format].gl_format;
3043+ gl_type = mapping[mir_format].gl_type;
3044+ }
3045+ else
3046+ {
3047+ gl_format = GL_INVALID_ENUM;
3048+ gl_type = GL_INVALID_ENUM;
3049+ }
3050+
3051+ return gl_format != GL_INVALID_ENUM && gl_type != GL_INVALID_ENUM;
3052+}
3053+
3054+
3055+struct ClientPrivate
3056+{
3057+ wl_listener destroy_listener;
3058+ std::shared_ptr<mf::Session> session;
3059+};
3060+
3061+static_assert(
3062+ std::is_standard_layout<ClientPrivate>::value,
3063+ "ClientPrivate must be standard layout for wl_container_of to be defined behaviour");
3064+
3065+
3066+ClientPrivate* private_from_listener(wl_listener* listener)
3067+{
3068+ ClientPrivate* userdata;
3069+ return wl_container_of(listener, userdata, destroy_listener);
3070+}
3071+
3072+void cleanup_private(wl_listener* listener, void* /*data*/)
3073+{
3074+ delete private_from_listener(listener);
3075+}
3076+
3077+std::shared_ptr<mf::Session> session_for_client(wl_client* client)
3078+{
3079+ auto listener = wl_client_get_destroy_listener(client, &cleanup_private);
3080+
3081+ assert(listener && "Client session requested for malformed client");
3082+
3083+ return private_from_listener(listener)->session;
3084+}
3085+
3086+struct ClientSessionConstructor
3087+{
3088+ ClientSessionConstructor(std::shared_ptr<mf::Shell> const& shell)
3089+ : shell{shell}
3090+ {
3091+ }
3092+
3093+ wl_listener construction_listener;
3094+ wl_listener destruction_listener;
3095+ std::shared_ptr<mf::Shell> const shell;
3096+};
3097+
3098+static_assert(
3099+ std::is_standard_layout<ClientSessionConstructor>::value,
3100+ "ClientSessionConstructor must be standard layout for wl_container_of to be "
3101+ "defined behaviour.");
3102+
3103+void create_client_session(wl_listener* listener, void* data)
3104+{
3105+ auto client = reinterpret_cast<wl_client*>(data);
3106+
3107+ ClientSessionConstructor* construction_context;
3108+ construction_context =
3109+ wl_container_of(listener, construction_context, construction_listener);
3110+
3111+ pid_t client_pid;
3112+ wl_client_get_credentials(client, &client_pid, nullptr, nullptr);
3113+
3114+ auto session = construction_context->shell->open_session(
3115+ client_pid,
3116+ "",
3117+ std::make_shared<WaylandEventSink>([](auto){}));
3118+
3119+ auto client_context = new ClientPrivate;
3120+ client_context->destroy_listener.notify = &cleanup_private;
3121+ client_context->session = session;
3122+ wl_client_add_destroy_listener(client, &client_context->destroy_listener);
3123+}
3124+
3125+void cleanup_client_handler(wl_listener* listener, void*)
3126+{
3127+ ClientSessionConstructor* construction_context;
3128+ construction_context = wl_container_of(listener, construction_context, destruction_listener);
3129+
3130+ delete construction_context;
3131+}
3132+
3133+void setup_new_client_handler(wl_display* display, std::shared_ptr<mf::Shell> const& shell)
3134+{
3135+ auto context = new ClientSessionConstructor{shell};
3136+ context->construction_listener.notify = &create_client_session;
3137+
3138+ wl_display_add_client_created_listener(display, &context->construction_listener);
3139+
3140+ context->destruction_listener.notify = &cleanup_client_handler;
3141+ wl_display_add_destroy_listener(display, &context->destruction_listener);
3142+}
3143+
3144+/*
3145+std::shared_ptr<mf::BufferStream> create_buffer_stream(mf::Session& session)
3146+{
3147+ mg::BufferProperties const props{
3148+ geom::Size{geom::Width{0}, geom::Height{0}},
3149+ mir_pixel_format_invalid,
3150+ mg::BufferUsage::undefined
3151+ };
3152+
3153+ auto const id = session.create_buffer_stream(props);
3154+ return session.get_buffer_stream(id);
3155+}
3156+*/
3157+MirPixelFormat wl_format_to_mir_format(uint32_t format)
3158+{
3159+ switch (format)
3160+ {
3161+ case WL_SHM_FORMAT_ARGB8888:
3162+ return mir_pixel_format_argb_8888;
3163+ case WL_SHM_FORMAT_XRGB8888:
3164+ return mir_pixel_format_xrgb_8888;
3165+ case WL_SHM_FORMAT_RGBA4444:
3166+ return mir_pixel_format_rgba_4444;
3167+ case WL_SHM_FORMAT_RGBA5551:
3168+ return mir_pixel_format_rgba_5551;
3169+ case WL_SHM_FORMAT_RGB565:
3170+ return mir_pixel_format_rgb_565;
3171+ case WL_SHM_FORMAT_RGB888:
3172+ return mir_pixel_format_rgb_888;
3173+ case WL_SHM_FORMAT_BGR888:
3174+ return mir_pixel_format_bgr_888;
3175+ case WL_SHM_FORMAT_XBGR8888:
3176+ return mir_pixel_format_xbgr_8888;
3177+ case WL_SHM_FORMAT_ABGR8888:
3178+ return mir_pixel_format_abgr_8888;
3179+ default:
3180+ return mir_pixel_format_invalid;
3181+ }
3182+}
3183+
3184+wl_shm_buffer* shm_buffer_from_resource_checked(wl_resource* resource)
3185+{
3186+ auto const buffer = wl_shm_buffer_get(resource);
3187+ if (!buffer)
3188+ {
3189+ BOOST_THROW_EXCEPTION((std::logic_error{"Tried to create WlShmBuffer from non-shm resource"}));
3190+ }
3191+
3192+ return buffer;
3193+}
3194+}
3195+
3196+class WlShmBuffer :
3197+ public mg::BufferBasic,
3198+ public mg::NativeBufferBase,
3199+ public mir::renderer::gl::TextureSource,
3200+ public mir::renderer::software::PixelSource
3201+{
3202+public:
3203+ ~WlShmBuffer()
3204+ {
3205+ std::lock_guard<std::mutex> lock{*buffer_mutex};
3206+ if (buffer)
3207+ {
3208+ wl_resource_queue_event(resource, WL_BUFFER_RELEASE);
3209+ }
3210+ }
3211+
3212+ static std::shared_ptr<graphics::Buffer> mir_buffer_from_wl_buffer(
3213+ wl_resource* buffer,
3214+ std::function<void()>&& on_consumed)
3215+ {
3216+ std::shared_ptr<WlShmBuffer> mir_buffer;
3217+ DestructionShim* shim;
3218+
3219+ if (auto notifier = wl_resource_get_destroy_listener(buffer, &on_buffer_destroyed))
3220+ {
3221+ // We've already constructed a shim for this buffer, update it.
3222+ shim = wl_container_of(notifier, shim, destruction_listener);
3223+
3224+ if (!(mir_buffer = shim->associated_buffer.lock()))
3225+ {
3226+ /*
3227+ * We've seen this wl_buffer before, but all the WlShmBuffers associated with it
3228+ * have been destroyed.
3229+ *
3230+ * Recreate a new WlShmBuffer to track the new compositor lifetime.
3231+ */
3232+ mir_buffer = std::shared_ptr<WlShmBuffer>{new WlShmBuffer{buffer, std::move(on_consumed)}};
3233+ shim->associated_buffer = mir_buffer;
3234+ }
3235+ }
3236+ else
3237+ {
3238+ mir_buffer = std::shared_ptr<WlShmBuffer>{new WlShmBuffer{buffer, std::move(on_consumed)}};
3239+ shim = new DestructionShim;
3240+ shim->destruction_listener.notify = &on_buffer_destroyed;
3241+ shim->associated_buffer = mir_buffer;
3242+
3243+ wl_resource_add_destroy_listener(buffer, &shim->destruction_listener);
3244+ }
3245+
3246+ mir_buffer->buffer_mutex = shim->mutex;
3247+ return mir_buffer;
3248+ }
3249+
3250+ std::shared_ptr<graphics::NativeBuffer> native_buffer_handle() const override
3251+ {
3252+ return nullptr;
3253+ }
3254+
3255+ geometry::Size size() const override
3256+ {
3257+ return size_;
3258+ }
3259+
3260+ MirPixelFormat pixel_format() const override
3261+ {
3262+ return format_;
3263+ }
3264+
3265+ graphics::NativeBufferBase *native_buffer_base() override
3266+ {
3267+ return this;
3268+ }
3269+
3270+ void gl_bind_to_texture() override
3271+ {
3272+ GLenum format, type;
3273+
3274+ if (get_gl_pixel_format(
3275+ format_,
3276+ format,
3277+ type))
3278+ {
3279+ /*
3280+ * All existing Mir logic assumes that strides are whole multiples of
3281+ * pixels. And OpenGL defaults to expecting strides are multiples of
3282+ * 4 bytes. These assumptions used to be compatible when we only had
3283+ * 4-byte pixels but now we support 2/3-byte pixels we need to be more
3284+ * careful...
3285+ */
3286+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
3287+
3288+ read(
3289+ [this, format, type](unsigned char const* pixels)
3290+ {
3291+ auto const size = this->size();
3292+ glTexImage2D(GL_TEXTURE_2D, 0, format,
3293+ size.width.as_int(), size.height.as_int(),
3294+ 0, format, type, pixels);
3295+ });
3296+ }
3297+ }
3298+
3299+ void bind() override
3300+ {
3301+ gl_bind_to_texture();
3302+ }
3303+
3304+ void secure_for_render() override
3305+ {
3306+ }
3307+
3308+ void write(unsigned char const *pixels, size_t size) override
3309+ {
3310+ std::lock_guard<std::mutex> lock{*buffer_mutex};
3311+ wl_shm_buffer_begin_access(buffer);
3312+ auto data = wl_shm_buffer_get_data(buffer);
3313+ ::memcpy(data, pixels, size);
3314+ wl_shm_buffer_end_access(buffer);
3315+ }
3316+
3317+ void read(std::function<void(unsigned char const *)> const &do_with_pixels) override
3318+ {
3319+ std::lock_guard<std::mutex> lock{*buffer_mutex};
3320+ if (!buffer)
3321+ {
3322+ mir::log_warning("Attempt to read from WlShmBuffer after the wl_buffer has been destroyed");
3323+ return;
3324+ }
3325+
3326+ if (!consumed)
3327+ {
3328+ on_consumed();
3329+ consumed = true;
3330+ }
3331+
3332+ wl_shm_buffer_begin_access(buffer);
3333+ auto data = wl_shm_buffer_get_data(buffer);
3334+ do_with_pixels(static_cast<unsigned char const*>(data));
3335+ wl_shm_buffer_end_access(buffer);
3336+ }
3337+
3338+ geometry::Stride stride() const override
3339+ {
3340+ return stride_;
3341+ }
3342+
3343+private:
3344+ WlShmBuffer(
3345+ wl_resource* buffer,
3346+ std::function<void()>&& on_consumed)
3347+ : buffer{shm_buffer_from_resource_checked(buffer)},
3348+ resource{buffer},
3349+ size_{wl_shm_buffer_get_width(this->buffer), wl_shm_buffer_get_height(this->buffer)},
3350+ stride_{wl_shm_buffer_get_stride(this->buffer)},
3351+ format_{wl_format_to_mir_format(wl_shm_buffer_get_format(this->buffer))},
3352+ consumed{false},
3353+ on_consumed{std::move(on_consumed)}
3354+ {
3355+ }
3356+
3357+ static void on_buffer_destroyed(wl_listener* listener, void*)
3358+ {
3359+ static_assert(
3360+ std::is_standard_layout<DestructionShim>::value,
3361+ "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
3362+
3363+ DestructionShim* shim;
3364+ shim = wl_container_of(listener, shim, destruction_listener);
3365+
3366+ {
3367+ std::lock_guard<std::mutex> lock{*shim->mutex};
3368+ if (auto mir_buffer = shim->associated_buffer.lock())
3369+ {
3370+ mir_buffer->buffer = nullptr;
3371+ }
3372+ }
3373+
3374+ delete shim;
3375+ }
3376+
3377+ struct DestructionShim
3378+ {
3379+ std::shared_ptr<std::mutex> const mutex = std::make_shared<std::mutex>();
3380+ std::weak_ptr<WlShmBuffer> associated_buffer;
3381+ wl_listener destruction_listener;
3382+ };
3383+
3384+ std::shared_ptr<std::mutex> buffer_mutex;
3385+
3386+ wl_shm_buffer* buffer;
3387+ wl_resource* const resource;
3388+
3389+ geom::Size const size_;
3390+ geom::Stride const stride_;
3391+ MirPixelFormat const format_;
3392+
3393+ bool consumed;
3394+ std::function<void()> on_consumed;
3395+};
3396+
3397+class WlSurface : public wayland::Surface
3398+{
3399+public:
3400+ WlSurface(
3401+ wl_client* client,
3402+ wl_resource* parent,
3403+ uint32_t id,
3404+ std::shared_ptr<mir::Executor> const& executor,
3405+ std::shared_ptr<mg::WaylandAllocator> const& allocator)
3406+ : Surface(client, parent, id),
3407+ allocator{allocator},
3408+ executor{executor},
3409+ pending_buffer{nullptr},
3410+ pending_frames{std::make_shared<std::vector<wl_resource*>>()}
3411+ {
3412+ auto session = session_for_client(client);
3413+ mg::BufferProperties const props{
3414+ geom::Size{geom::Width{0}, geom::Height{0}},
3415+ mir_pixel_format_invalid,
3416+ mg::BufferUsage::undefined
3417+ };
3418+
3419+ stream_id = session->create_buffer_stream(props);
3420+ stream = session->get_buffer_stream(stream_id);
3421+
3422+ // wl_surface is specified to act in mailbox mode
3423+ stream->allow_framedropping(true);
3424+ }
3425+
3426+ void set_resize_handler(std::function<void(geom::Size)> const& handler)
3427+ {
3428+ resize_handler = handler;
3429+ }
3430+
3431+ void set_hide_handler(std::function<void()> const& handler)
3432+ {
3433+ hide_handler = handler;
3434+ }
3435+
3436+ mf::BufferStreamId stream_id;
3437+ std::shared_ptr<mf::BufferStream> stream;
3438+private:
3439+ std::shared_ptr<mg::WaylandAllocator> const allocator;
3440+ std::shared_ptr<mir::Executor> const executor;
3441+
3442+ std::function<void(geom::Size)> resize_handler;
3443+ std::function<void()> hide_handler;
3444+
3445+ wl_resource* pending_buffer;
3446+ std::shared_ptr<std::vector<wl_resource*>> const pending_frames;
3447+
3448+ void destroy();
3449+ void attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y);
3450+ void damage(int32_t x, int32_t y, int32_t width, int32_t height);
3451+ void frame(uint32_t callback);
3452+ void set_opaque_region(std::experimental::optional<wl_resource*> const& region);
3453+ void set_input_region(std::experimental::optional<wl_resource*> const& region);
3454+ void commit();
3455+ void damage_buffer(int32_t x, int32_t y, int32_t width, int32_t height);
3456+ void set_buffer_transform(int32_t transform);
3457+ void set_buffer_scale(int32_t scale);
3458+};
3459+
3460+void WlSurface::destroy()
3461+{
3462+ delete this;
3463+}
3464+
3465+void WlSurface::attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y)
3466+{
3467+ if (x != 0 || y != 0)
3468+ {
3469+ mir::log_warning("Client requested unimplemented non-zero attach offset. Rendering will be incorrect.");
3470+ }
3471+
3472+ if(!buffer && hide_handler)
3473+ {
3474+ hide_handler();
3475+ }
3476+
3477+ pending_buffer = *buffer;
3478+}
3479+
3480+void WlSurface::damage(int32_t x, int32_t y, int32_t width, int32_t height)
3481+{
3482+ (void)x;
3483+ (void)y;
3484+ (void)width;
3485+ (void)height;
3486+}
3487+
3488+void WlSurface::damage_buffer(int32_t x, int32_t y, int32_t width, int32_t height)
3489+{
3490+ (void)x;
3491+ (void)y;
3492+ (void)width;
3493+ (void)height;
3494+}
3495+
3496+void WlSurface::frame(uint32_t callback)
3497+{
3498+ pending_frames->emplace_back(
3499+ wl_resource_create(client, &wl_callback_interface, 1, callback));
3500+}
3501+
3502+void WlSurface::set_opaque_region(const std::experimental::optional<wl_resource*>& region)
3503+{
3504+ (void)region;
3505+}
3506+
3507+void WlSurface::set_input_region(const std::experimental::optional<wl_resource*>& region)
3508+{
3509+ (void)region;
3510+}
3511+
3512+void WlSurface::commit()
3513+{
3514+ if (pending_buffer)
3515+ {
3516+ std::shared_ptr<mg::Buffer> mir_buffer;
3517+ auto shm_buffer = wl_shm_buffer_get(pending_buffer);
3518+ auto send_frame_notifications =
3519+ [executor = executor, frames = pending_frames]()
3520+ {
3521+ executor->spawn(
3522+ [frames]()
3523+ {
3524+ /*
3525+ * There is no synchronisation required here -
3526+ * This is run on the WaylandExecutor, and is guaranteed to run on the
3527+ * wl_event_loop's thread.
3528+ *
3529+ * The only other accessors of WlSurface are also on the wl_event_loop,
3530+ * so this is guaranteed not to be reentrant.
3531+ */
3532+ for (auto frame : *frames)
3533+ {
3534+ wl_callback_send_done(frame, 0);
3535+ wl_resource_destroy(frame);
3536+ }
3537+ frames->clear();
3538+ });
3539+ };
3540+
3541+ if (shm_buffer)
3542+ {
3543+ mir_buffer = WlShmBuffer::mir_buffer_from_wl_buffer(
3544+ pending_buffer,
3545+ std::move(send_frame_notifications));
3546+ }
3547+ else if (
3548+ allocator &&
3549+ (mir_buffer = allocator->buffer_from_resource(
3550+ pending_buffer,
3551+ std::move(send_frame_notifications))))
3552+ {
3553+ }
3554+ else
3555+ {
3556+ BOOST_THROW_EXCEPTION((std::runtime_error{"Received unhandled buffer type"}));
3557+ }
3558+
3559+ /*
3560+ * This is technically incorrect - the resize and submit_buffer *should* be atomic,
3561+ * but are not, so a client in the process of resizing can have buffers rendered at
3562+ * an unexpected size.
3563+ *
3564+ * It should be good enough for now, though.
3565+ *
3566+ * TODO: Provide a mg::Buffer::logical_size() to do this properly.
3567+ */
3568+ stream->resize(mir_buffer->size());
3569+ if (resize_handler)
3570+ {
3571+ resize_handler(mir_buffer->size());
3572+ }
3573+ stream->submit_buffer(mir_buffer);
3574+
3575+ pending_buffer = nullptr;
3576+ }
3577+}
3578+
3579+void WlSurface::set_buffer_transform(int32_t transform)
3580+{
3581+ (void)transform;
3582+}
3583+
3584+void WlSurface::set_buffer_scale(int32_t scale)
3585+{
3586+ (void)scale;
3587+}
3588+
3589+class WlCompositor : public wayland::Compositor
3590+{
3591+public:
3592+ WlCompositor(
3593+ struct wl_display* display,
3594+ std::shared_ptr<mir::Executor> const& executor,
3595+ std::shared_ptr<mg::WaylandAllocator> const& allocator)
3596+ : Compositor(display, 3),
3597+ allocator{allocator},
3598+ executor{executor}
3599+ {
3600+ }
3601+
3602+private:
3603+ std::shared_ptr<mg::WaylandAllocator> const allocator;
3604+ std::shared_ptr<mir::Executor> const executor;
3605+
3606+ void create_surface(wl_client* client, wl_resource* resource, uint32_t id) override;
3607+ void create_region(wl_client* client, wl_resource* resource, uint32_t id) override;
3608+};
3609+
3610+void WlCompositor::create_surface(wl_client* client, wl_resource* resource, uint32_t id)
3611+{
3612+ new WlSurface{client, resource, id, executor, allocator};
3613+}
3614+
3615+class Region : public wayland::Region
3616+{
3617+public:
3618+ Region(wl_client* client, wl_resource* parent, uint32_t id)
3619+ : wayland::Region(client, parent, id)
3620+ {
3621+ }
3622+protected:
3623+
3624+ void destroy() override
3625+ {
3626+ }
3627+ void add(int32_t /*x*/, int32_t /*y*/, int32_t /*width*/, int32_t /*height*/) override
3628+ {
3629+ }
3630+ void subtract(int32_t /*x*/, int32_t /*y*/, int32_t /*width*/, int32_t /*height*/) override
3631+ {
3632+ }
3633+
3634+};
3635+
3636+void WlCompositor::create_region(wl_client* client, wl_resource* resource, uint32_t id)
3637+{
3638+ new Region{client, resource, id};
3639+}
3640+
3641+class WlPointer;
3642+class WlTouch;
3643+
3644+class WlKeyboard : public wayland::Keyboard
3645+{
3646+public:
3647+ WlKeyboard(
3648+ wl_client* client,
3649+ wl_resource* parent,
3650+ uint32_t id,
3651+ std::shared_ptr<mir::Executor> const& executor)
3652+ : Keyboard(client, parent, id),
3653+ executor{executor}
3654+ {
3655+ }
3656+
3657+ void handle_event(MirInputEvent const* event, wl_resource* /*target*/)
3658+ {
3659+ executor->spawn(
3660+ [ev = mir_event_ref(mir_input_event_get_event(event)), this] ()
3661+ {
3662+ int const serial = wl_display_next_serial(wl_client_get_display(client));
3663+ auto event = mir_event_get_input_event(ev);
3664+ auto key_event = mir_input_event_get_keyboard_event(event);
3665+
3666+ switch (mir_keyboard_event_action(key_event))
3667+ {
3668+ case mir_keyboard_action_up:
3669+ wl_keyboard_send_key(resource,
3670+ serial,
3671+ mir_input_event_get_event_time(event) / 1000,
3672+ mir_keyboard_event_scan_code(key_event),
3673+ WL_KEYBOARD_KEY_STATE_RELEASED);
3674+ break;
3675+ case mir_keyboard_action_down:
3676+ wl_keyboard_send_key(resource,
3677+ serial,
3678+ mir_input_event_get_event_time(event) / 1000,
3679+ mir_keyboard_event_scan_code(key_event),
3680+ WL_KEYBOARD_KEY_STATE_PRESSED);
3681+ break;
3682+ default:
3683+ break;
3684+ }
3685+ mir_event_unref(ev);
3686+ });
3687+ }
3688+
3689+private:
3690+ std::shared_ptr<mir::Executor> const executor;
3691+
3692+ void release() override;
3693+};
3694+
3695+void WlKeyboard::release()
3696+{
3697+}
3698+
3699+namespace
3700+{
3701+uint32_t calc_button_difference(MirPointerButtons old, MirPointerButtons updated)
3702+{
3703+ switch (old ^ updated)
3704+ {
3705+ case mir_pointer_button_primary:
3706+ return 272; // No, I have *no* idea why GTK expects 271 to be the primary button.
3707+ case mir_pointer_button_secondary:
3708+ return 274;
3709+ case mir_pointer_button_tertiary:
3710+ return 273;
3711+ case mir_pointer_button_back:
3712+ return 275; // I dunno. It's a number, I guess.
3713+ case mir_pointer_button_forward:
3714+ return 276; // I dunno. It's a number, I guess.
3715+ default:
3716+ throw std::logic_error("Whoops, I misunderstand how Mir pointer events work");
3717+ }
3718+}
3719+}
3720+
3721+class WlPointer : public wayland::Pointer
3722+{
3723+public:
3724+
3725+ WlPointer(
3726+ wl_client* client,
3727+ wl_resource* parent,
3728+ uint32_t id,
3729+ std::shared_ptr<mir::Executor> const& executor)
3730+ : Pointer(client, parent, id),
3731+ display{wl_client_get_display(client)},
3732+ executor{executor}
3733+ {
3734+ }
3735+
3736+ void handle_event(MirInputEvent const* event, wl_resource* target)
3737+ {
3738+ executor->spawn(
3739+ [ev = mir_event_ref(mir_input_event_get_event(event)), target, this]()
3740+ {
3741+ auto const serial = wl_display_next_serial(display);
3742+ auto const event = mir_event_get_input_event(ev);
3743+ auto const pointer_event = mir_input_event_get_pointer_event(event);
3744+
3745+ switch(mir_pointer_event_action(pointer_event))
3746+ {
3747+ case mir_pointer_action_button_down:
3748+ {
3749+ auto button = calc_button_difference(last_set, mir_pointer_event_buttons(pointer_event));
3750+ wl_pointer_send_button(
3751+ resource,
3752+ serial,
3753+ mir_input_event_get_event_time(event) / 1000,
3754+ button,
3755+ WL_POINTER_BUTTON_STATE_PRESSED);
3756+ last_set = mir_pointer_event_buttons(pointer_event);
3757+ break;
3758+ }
3759+ case mir_pointer_action_button_up:
3760+ {
3761+ auto button = calc_button_difference(last_set, mir_pointer_event_buttons(pointer_event));
3762+ wl_pointer_send_button(
3763+ resource,
3764+ serial,
3765+ mir_input_event_get_event_time(event) / 1000,
3766+ button,
3767+ WL_POINTER_BUTTON_STATE_RELEASED);
3768+ last_set = mir_pointer_event_buttons(pointer_event);
3769+ break;
3770+ }
3771+ case mir_pointer_action_enter:
3772+ {
3773+ wl_pointer_send_enter(
3774+ resource,
3775+ serial,
3776+ target,
3777+ wl_fixed_from_double(mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x)),
3778+ wl_fixed_from_double(mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y)));
3779+ break;
3780+ }
3781+ case mir_pointer_action_leave:
3782+ {
3783+ wl_pointer_send_leave(
3784+ resource,
3785+ serial,
3786+ target);
3787+ break;
3788+ }
3789+ case mir_pointer_action_motion:
3790+ {
3791+ auto x = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_x);
3792+ auto y = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_y);
3793+ auto vscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_vscroll);
3794+ auto hscroll = mir_pointer_event_axis_value(pointer_event, mir_pointer_axis_hscroll);
3795+
3796+ if ((x != last_x) || (y != last_y))
3797+ {
3798+ wl_pointer_send_motion(
3799+ resource,
3800+ mir_input_event_get_event_time(event) / 1000,
3801+ wl_fixed_from_double(x),
3802+ wl_fixed_from_double(y));
3803+
3804+ last_x = x;
3805+ last_y = y;
3806+ }
3807+ if (vscroll != last_vscroll)
3808+ {
3809+ wl_pointer_send_axis(
3810+ resource,
3811+ mir_input_event_get_event_time(event) / 1000,
3812+ WL_POINTER_AXIS_VERTICAL_SCROLL,
3813+ wl_fixed_from_double(vscroll));
3814+ last_vscroll = vscroll;
3815+ }
3816+ if (hscroll != last_hscroll)
3817+ {
3818+ wl_pointer_send_axis(
3819+ resource,
3820+ mir_input_event_get_event_time(event) / 1000,
3821+ WL_POINTER_AXIS_HORIZONTAL_SCROLL,
3822+ wl_fixed_from_double(hscroll));
3823+ last_hscroll = hscroll;
3824+ }
3825+ break;
3826+ }
3827+ case mir_pointer_actions:
3828+ break;
3829+ }
3830+ });
3831+ }
3832+
3833+ // Pointer interface
3834+private:
3835+ wl_display* const display;
3836+ std::shared_ptr<mir::Executor> const executor;
3837+
3838+ MirPointerButtons last_set{0};
3839+ float last_x, last_y, last_vscroll, last_hscroll;
3840+
3841+ void set_cursor(uint32_t serial, std::experimental::optional<wl_resource*> const& surface, int32_t hotspot_x, int32_t hotspot_y) override;
3842+ void release() override;
3843+};
3844+
3845+void WlPointer::set_cursor(uint32_t serial, std::experimental::optional<wl_resource*> const& surface, int32_t hotspot_x, int32_t hotspot_y)
3846+{
3847+ (void)serial;
3848+ (void)surface;
3849+ (void)hotspot_x;
3850+ (void)hotspot_y;
3851+}
3852+
3853+void WlPointer::release()
3854+{
3855+ delete this;
3856+}
3857+
3858+class WlTouch : public wayland::Touch
3859+{
3860+public:
3861+ WlTouch(
3862+ wl_client* client,
3863+ wl_resource* parent,
3864+ uint32_t id,
3865+ std::shared_ptr<mir::Executor> const& /*executor*/)
3866+ : Touch(client, parent, id)
3867+ {
3868+ }
3869+
3870+ void handle_event(MirInputEvent const* /*event*/, wl_resource* /*target*/)
3871+ {
3872+ }
3873+
3874+ // Touch interface
3875+private:
3876+ void release() override;
3877+};
3878+
3879+void WlTouch::release()
3880+{
3881+}
3882+
3883+template<class InputInterface>
3884+class InputCtx
3885+{
3886+public:
3887+ InputCtx() = default;
3888+
3889+ InputCtx(InputCtx&&) = delete;
3890+ InputCtx(InputCtx const&) = delete;
3891+ InputCtx& operator=(InputCtx const&) = delete;
3892+
3893+ void register_listener(std::shared_ptr<InputInterface> const& listener)
3894+ {
3895+ listeners.push_back(listener);
3896+ }
3897+
3898+ void unregister_listener(InputInterface const* listener)
3899+ {
3900+ std::remove_if(
3901+ listeners.begin(),
3902+ listeners.end(),
3903+ [listener](auto candidate)
3904+ {
3905+ return candidate.get() == listener;
3906+ });
3907+ }
3908+
3909+ void handle_event(MirInputEvent const* event, wl_resource* target) const
3910+ {
3911+ for (auto& listener : listeners)
3912+ {
3913+ listener->handle_event(event, target);
3914+ }
3915+ }
3916+
3917+private:
3918+ std::vector<std::shared_ptr<InputInterface>> listeners;
3919+};
3920+
3921+class WlSeat
3922+{
3923+public:
3924+ WlSeat(wl_display* display, std::shared_ptr<mir::Executor> const& executor)
3925+ : executor{executor},
3926+ global{wl_global_create(
3927+ display,
3928+ &wl_seat_interface,
3929+ 5,
3930+ this,
3931+ &WlSeat::bind)}
3932+ {
3933+ if (!global)
3934+ {
3935+ BOOST_THROW_EXCEPTION(std::runtime_error("Failed to export wl_seat interface"));
3936+ }
3937+ }
3938+
3939+ ~WlSeat()
3940+ {
3941+ wl_global_destroy(global);
3942+ }
3943+
3944+ InputCtx<WlPointer> const& acquire_pointer_reference(wl_client* client) const;
3945+ InputCtx<WlKeyboard> const& acquire_keyboard_reference(wl_client* client) const;
3946+ InputCtx<WlTouch> const& acquire_touch_reference(wl_client* client) const;
3947+
3948+private:
3949+ std::unordered_map<wl_client*, InputCtx<WlPointer>> mutable pointer;
3950+ std::unordered_map<wl_client*, InputCtx<WlKeyboard>> mutable keyboard;
3951+ std::unordered_map<wl_client*, InputCtx<WlTouch>> mutable touch;
3952+ std::shared_ptr<mir::Executor> const executor;
3953+
3954+ static void bind(struct wl_client* client, void* data, uint32_t version, uint32_t id)
3955+ {
3956+ auto me = reinterpret_cast<WlSeat*>(data);
3957+ auto resource = wl_resource_create(client, &wl_seat_interface,
3958+ std::min(version, 6u), id);
3959+ if (resource == nullptr)
3960+ {
3961+ wl_client_post_no_memory(client);
3962+ BOOST_THROW_EXCEPTION((std::bad_alloc{}));
3963+ }
3964+ wl_resource_set_implementation(resource, &vtable, me, nullptr);
3965+
3966+ /*
3967+ * TODO: Read the actual capabilities. Do we have a keyboard? Mouse? Touch?
3968+ */
3969+ wl_seat_send_capabilities(
3970+ resource,
3971+ WL_SEAT_CAPABILITY_POINTER |
3972+ WL_SEAT_CAPABILITY_KEYBOARD);
3973+ wl_seat_send_name(
3974+ resource,
3975+ "seat0");
3976+
3977+ wl_resource_set_user_data(resource, me);
3978+ }
3979+
3980+ static void get_pointer(wl_client* client, wl_resource* resource, uint32_t id)
3981+ {
3982+ auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));
3983+ me->pointer[client].register_listener(
3984+ std::make_shared<WlPointer>(
3985+ client,
3986+ resource,
3987+ id,
3988+ me->executor));
3989+ }
3990+ static void get_keyboard(wl_client* client, wl_resource* resource, uint32_t id)
3991+ {
3992+ auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));
3993+ me->keyboard[client].register_listener(
3994+ std::make_shared<WlKeyboard>(
3995+ client,
3996+ resource,
3997+ id,
3998+ me->executor));
3999+ }
4000+ static void get_touch(wl_client* client, wl_resource* resource, uint32_t id)
4001+ {
4002+ auto me = reinterpret_cast<WlSeat*>(wl_resource_get_user_data(resource));
4003+ me->touch[client].register_listener(
4004+ std::make_shared<WlTouch>(
4005+ client,
4006+ resource,
4007+ id,
4008+ me->executor));
4009+ }
4010+ static void release(struct wl_client* /*client*/, struct wl_resource* /*resource*/) {}
4011+
4012+
4013+ wl_global* const global;
4014+ static struct wl_seat_interface const vtable;
4015+};
4016+
4017+struct wl_seat_interface const WlSeat::vtable = {
4018+ WlSeat::get_pointer,
4019+ WlSeat::get_keyboard,
4020+ WlSeat::get_touch,
4021+ WlSeat::release
4022+};
4023+
4024+InputCtx<WlKeyboard> const& WlSeat::acquire_keyboard_reference(wl_client* client) const
4025+{
4026+ return keyboard[client];
4027+}
4028+
4029+InputCtx<WlPointer> const& WlSeat::acquire_pointer_reference(wl_client* client) const
4030+{
4031+ return pointer[client];
4032+}
4033+
4034+InputCtx<WlTouch> const& WlSeat::acquire_touch_reference(wl_client* client) const
4035+{
4036+ return touch[client];
4037+}
4038+
4039+void WaylandEventSink::send_buffer(BufferStreamId /*id*/, graphics::Buffer& /*buffer*/, graphics::BufferIpcMsgType)
4040+{
4041+}
4042+
4043+void WaylandEventSink::handle_event(MirEvent const& e)
4044+{
4045+ switch(mir_event_get_type(&e))
4046+ {
4047+ default:
4048+ // Do nothing
4049+ break;
4050+ }
4051+}
4052+
4053+void WaylandEventSink::handle_lifecycle_event(MirLifecycleState state)
4054+{
4055+ lifecycle_handler(state);
4056+}
4057+
4058+void WaylandEventSink::handle_display_config_change(graphics::DisplayConfiguration const& /*config*/)
4059+{
4060+}
4061+
4062+void WaylandEventSink::send_ping(int32_t)
4063+{
4064+}
4065+
4066+class SurfaceInputSink : public mf::EventSink
4067+{
4068+public:
4069+ SurfaceInputSink(WlSeat* seat, wl_client* client, wl_resource* target)
4070+ : seat{seat},
4071+ client{client},
4072+ target{target}
4073+ {
4074+ }
4075+
4076+ void handle_event(MirEvent const& e) override;
4077+ void handle_lifecycle_event(MirLifecycleState) override {}
4078+ void handle_display_config_change(graphics::DisplayConfiguration const&) override {}
4079+ void send_ping(int32_t) override {}
4080+ void handle_input_config_change(MirInputConfig const&) override {}
4081+ void handle_error(ClientVisibleError const&) override {}
4082+
4083+ void send_buffer(frontend::BufferStreamId, graphics::Buffer&, graphics::BufferIpcMsgType) override {}
4084+ void add_buffer(graphics::Buffer&) override {}
4085+ void error_buffer(geometry::Size, MirPixelFormat, std::string const& ) override {}
4086+ void update_buffer(graphics::Buffer&) override {}
4087+
4088+private:
4089+ WlSeat* const seat;
4090+ wl_client* const client;
4091+ wl_resource* const target;
4092+};
4093+
4094+void SurfaceInputSink::handle_event(MirEvent const& event)
4095+{
4096+ switch (mir_event_get_type(&event))
4097+ {
4098+ case mir_event_type_input:
4099+ {
4100+ auto input_event = mir_event_get_input_event(&event);
4101+ switch (mir_input_event_get_type(input_event))
4102+ {
4103+ case mir_input_event_type_key:
4104+ seat->acquire_keyboard_reference(client).handle_event(input_event, target);
4105+ break;
4106+ case mir_input_event_type_pointer:
4107+ seat->acquire_pointer_reference(client).handle_event(input_event, target);
4108+ break;
4109+ case mir_input_event_type_touch:
4110+ seat->acquire_touch_reference(client).handle_event(input_event, target);
4111+ break;
4112+ default:
4113+ break;
4114+ }
4115+ }
4116+ default:
4117+ break;
4118+ }
4119+}
4120+
4121+class Output
4122+{
4123+public:
4124+ Output(
4125+ wl_display* display,
4126+ mg::DisplayConfigurationOutput const& initial_configuration)
4127+ : output{make_output(display)},
4128+ current_config{initial_configuration}
4129+ {
4130+ }
4131+
4132+ ~Output()
4133+ {
4134+ wl_global_destroy(output);
4135+ }
4136+
4137+ void handle_configuration_changed(mg::DisplayConfigurationOutput const& /*config*/)
4138+ {
4139+
4140+ }
4141+
4142+private:
4143+ static void send_initial_config(
4144+ wl_resource* client_resource,
4145+ mg::DisplayConfigurationOutput const& config)
4146+ {
4147+ wl_output_send_geometry(
4148+ client_resource,
4149+ config.top_left.x.as_int(),
4150+ config.top_left.y.as_int(),
4151+ config.physical_size_mm.width.as_int(),
4152+ config.physical_size_mm.height.as_int(),
4153+ WL_OUTPUT_SUBPIXEL_UNKNOWN,
4154+ "Fake manufacturer",
4155+ "Fake model",
4156+ WL_OUTPUT_TRANSFORM_NORMAL);
4157+ for (size_t i = 0; i < config.modes.size(); ++i)
4158+ {
4159+ auto const& mode = config.modes[i];
4160+ wl_output_send_mode(
4161+ client_resource,
4162+ ((i == config.preferred_mode_index ? WL_OUTPUT_MODE_PREFERRED : 0) |
4163+ (i == config.current_mode_index ? WL_OUTPUT_MODE_CURRENT : 0)),
4164+ mode.size.width.as_int(),
4165+ mode.size.height.as_int(),
4166+ mode.vrefresh_hz * 1000);
4167+ }
4168+ wl_output_send_scale(client_resource, 1);
4169+ wl_output_send_done(client_resource);
4170+ }
4171+
4172+ wl_global* make_output(wl_display* display)
4173+ {
4174+ return wl_global_create(
4175+ display,
4176+ &wl_output_interface,
4177+ 2,
4178+ this, &on_bind);
4179+ }
4180+
4181+ static void on_bind(wl_client* client, void* data, uint32_t version, uint32_t id)
4182+ {
4183+ auto output = reinterpret_cast<Output*>(data);
4184+ auto resource = wl_resource_create(client, &wl_output_interface,
4185+ std::min(version, 2u), id);
4186+ if (resource == NULL) {
4187+ wl_client_post_no_memory(client);
4188+ return;
4189+ }
4190+
4191+ output->resource_map[client].push_back(resource);
4192+ wl_resource_set_destructor(resource, &resource_destructor);
4193+ wl_resource_set_user_data(resource, &(output->resource_map));
4194+
4195+ send_initial_config(resource, output->current_config);
4196+ }
4197+
4198+ static void resource_destructor(wl_resource* resource)
4199+ {
4200+ auto& map = *reinterpret_cast<decltype(resource_map)*>(
4201+ wl_resource_get_user_data(resource));
4202+
4203+ auto& client_resource_list = map[wl_resource_get_client(resource)];
4204+ std::remove_if(
4205+ client_resource_list.begin(),
4206+ client_resource_list.end(),
4207+ [resource](auto candidate) { return candidate == resource; });
4208+ }
4209+
4210+private:
4211+ wl_global* const output;
4212+ mg::DisplayConfigurationOutput current_config;
4213+ std::unordered_map<wl_client*, std::vector<wl_resource*>> resource_map;
4214+};
4215+
4216+class OutputManager
4217+{
4218+public:
4219+ OutputManager(
4220+ wl_display* display,
4221+ mf::DisplayChanger& display_config)
4222+ : display{display}
4223+ {
4224+ // TODO: Also register display configuration listeners
4225+ display_config.base_configuration()->for_each_output(std::bind(&OutputManager::create_output, this, std::placeholders::_1));
4226+ }
4227+
4228+private:
4229+ void create_output(mg::DisplayConfigurationOutput const& initial_config)
4230+ {
4231+ if (initial_config.used)
4232+ {
4233+ outputs.emplace(
4234+ initial_config.id,
4235+ std::make_unique<Output>(
4236+ display,
4237+ initial_config));
4238+ }
4239+ }
4240+
4241+ void handle_configuration_change(mg::DisplayConfiguration const& config)
4242+ {
4243+ config.for_each_output([this](mg::DisplayConfigurationOutput const& output_config)
4244+ {
4245+ auto output_iter = outputs.find(output_config.id);
4246+ if (output_iter != outputs.end())
4247+ {
4248+ if (output_config.used)
4249+ {
4250+ output_iter->second->handle_configuration_changed(output_config);
4251+ }
4252+ else
4253+ {
4254+ outputs.erase(output_iter);
4255+ }
4256+ }
4257+ else if (output_config.used)
4258+ {
4259+ outputs[output_config.id] = std::make_unique<Output>(display, output_config);
4260+ }
4261+ });
4262+ }
4263+
4264+ wl_display* const display;
4265+ std::unordered_map<mg::DisplayConfigurationOutputId, std::unique_ptr<Output>> outputs;
4266+};
4267+
4268+class WlShellSurface : public wayland::ShellSurface
4269+{
4270+public:
4271+ WlShellSurface(
4272+ wl_client* client,
4273+ wl_resource* parent,
4274+ uint32_t id,
4275+ wl_resource* surface,
4276+ std::shared_ptr<mf::Shell> const& shell,
4277+ WlSeat& seat)
4278+ : ShellSurface(client, parent, id),
4279+ shell{shell}
4280+ {
4281+ auto* tmp = wl_resource_get_user_data(surface);
4282+ auto& mir_surface = *static_cast<WlSurface*>(reinterpret_cast<wayland::Surface*>(tmp));
4283+
4284+ auto const session = session_for_client(client);
4285+
4286+ auto params = ms::SurfaceCreationParameters()
4287+ .of_type(mir_window_type_freestyle)
4288+ .of_size(geom::Size{100, 100})
4289+ .with_buffer_stream(mir_surface.stream_id);
4290+
4291+ surface_id = shell->create_surface(
4292+ session,
4293+ params,
4294+ std::make_shared<SurfaceInputSink>(&seat, client, surface));
4295+
4296+ mir_surface.set_resize_handler(
4297+ [shell, session, id = surface_id](geom::Size new_size)
4298+ {
4299+ shell::SurfaceSpecification new_size_spec;
4300+ new_size_spec.width = new_size.width;
4301+ new_size_spec.height = new_size.height;
4302+ shell->modify_surface(session, id, new_size_spec);
4303+ });
4304+
4305+ mir_surface.set_hide_handler(
4306+ [shell, session, id = surface_id]()
4307+ {
4308+ shell::SurfaceSpecification hide_spec;
4309+ hide_spec.state = mir_window_state_hidden;
4310+ shell->modify_surface(session, id, hide_spec);
4311+ });
4312+
4313+ auto shim = new DestructionShim{session, shell, surface_id};
4314+ shim->destruction_listener.notify = &cleanup_surface;
4315+ wl_resource_add_destroy_listener(
4316+ resource,
4317+ &shim->destruction_listener);
4318+ }
4319+
4320+ ~WlShellSurface() override = default;
4321+protected:
4322+ void pong(uint32_t /*serial*/) override
4323+ {
4324+ }
4325+
4326+ void move(struct wl_resource* /*seat*/, uint32_t /*serial*/) override
4327+ {
4328+ }
4329+
4330+ void resize(struct wl_resource* /*seat*/, uint32_t /*serial*/, uint32_t /*edges*/) override
4331+ {
4332+ }
4333+
4334+ void set_toplevel() override
4335+ {
4336+ }
4337+
4338+ void set_transient(
4339+ struct wl_resource* /*parent*/,
4340+ int32_t /*x*/,
4341+ int32_t /*y*/,
4342+ uint32_t /*flags*/) override
4343+ {
4344+ }
4345+
4346+ void set_fullscreen(
4347+ uint32_t /*method*/,
4348+ uint32_t /*framerate*/,
4349+ std::experimental::optional<struct wl_resource*> const& /*output*/) override
4350+ {
4351+ }
4352+
4353+ void set_popup(
4354+ struct wl_resource* /*seat*/,
4355+ uint32_t /*serial*/,
4356+ struct wl_resource* /*parent*/,
4357+ int32_t /*x*/,
4358+ int32_t /*y*/,
4359+ uint32_t /*flags*/) override
4360+ {
4361+ }
4362+
4363+ void set_maximized(std::experimental::optional<struct wl_resource*> const& /*output*/) override
4364+ {
4365+ }
4366+
4367+ void set_title(std::string const& /*title*/) override
4368+ {
4369+ }
4370+
4371+ void set_class(std::string const& /*class_*/) override
4372+ {
4373+ }
4374+private:
4375+ struct DestructionShim
4376+ {
4377+ DestructionShim(
4378+ std::shared_ptr<mf::Session> const& session,
4379+ std::shared_ptr<mf::Shell> const& shell,
4380+ mf::SurfaceId id)
4381+ : session{session},
4382+ shell{shell},
4383+ surface_id{id}
4384+ {
4385+ }
4386+
4387+ std::shared_ptr<mf::Session> const session;
4388+ std::shared_ptr<mf::Shell> const shell;
4389+ mf::SurfaceId const surface_id;
4390+ wl_listener destruction_listener;
4391+ };
4392+
4393+ static_assert(
4394+ std::is_standard_layout<DestructionShim>::value,
4395+ "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
4396+
4397+ static void cleanup_surface(wl_listener* listener, void*)
4398+ {
4399+ DestructionShim* shim;
4400+ shim = wl_container_of(listener, shim, destruction_listener);
4401+
4402+ shim->shell->destroy_surface(shim->session, shim->surface_id);
4403+
4404+ delete shim;
4405+ }
4406+
4407+ std::shared_ptr<mf::Shell> const shell;
4408+ mf::SurfaceId surface_id;
4409+};
4410+
4411+class WlShell : public wayland::Shell
4412+{
4413+public:
4414+ WlShell(
4415+ wl_display* display,
4416+ std::shared_ptr<mf::Shell> const& shell,
4417+ WlSeat& seat)
4418+ : Shell(display, 1),
4419+ shell{shell},
4420+ seat{seat}
4421+ {
4422+ }
4423+
4424+ void get_shell_surface(
4425+ wl_client* client,
4426+ wl_resource* resource,
4427+ uint32_t id,
4428+ wl_resource* surface) override
4429+ {
4430+ new WlShellSurface(client, resource, id, surface, shell, seat);
4431+ }
4432+private:
4433+ std::shared_ptr<mf::Shell> const shell;
4434+ WlSeat& seat;
4435+};
4436+}
4437+}
4438+
4439+namespace
4440+{
4441+int halt_eventloop(int fd, uint32_t /*mask*/, void* data)
4442+{
4443+ auto display = reinterpret_cast<wl_display*>(data);
4444+ wl_display_terminate(display);
4445+
4446+ eventfd_t ignored;
4447+ if (eventfd_read(fd, &ignored) < 0)
4448+ {
4449+ BOOST_THROW_EXCEPTION((std::system_error{
4450+ errno,
4451+ std::system_category(),
4452+ "Failed to consume pause event notification"}));
4453+ }
4454+ return 0;
4455+}
4456+}
4457+
4458+namespace
4459+{
4460+void cleanup_display(wl_display *display)
4461+{
4462+ wl_display_flush_clients(display);
4463+ wl_display_destroy(display);
4464+}
4465+
4466+class WaylandExecutor : public mir::Executor
4467+{
4468+public:
4469+ void spawn (std::function<void ()>&& work) override
4470+ {
4471+ {
4472+ std::lock_guard<std::recursive_mutex> lock{mutex};
4473+ workqueue.emplace_back(std::move(work));
4474+ }
4475+ if (auto err = eventfd_write(notify_fd, 1))
4476+ {
4477+ BOOST_THROW_EXCEPTION((std::system_error{err, std::system_category(), "eventfd_write failed to notify event loop"}));
4478+ }
4479+ }
4480+
4481+ /**
4482+ * Get an Executor which dispatches onto a wl_event_loop
4483+ *
4484+ * \note The executor may outlive the wl_event_loop, but no tasks will be dispatched
4485+ * after the wl_event_loop is destroyed.
4486+ *
4487+ * \param [in] loop The event loop to dispatch on
4488+ * \return An Executor that queues onto the wl_event_loop
4489+ */
4490+ static std::shared_ptr<mir::Executor> executor_for_event_loop(wl_event_loop* loop)
4491+ {
4492+ if (auto notifier = wl_event_loop_get_destroy_listener(loop, &on_display_destruction))
4493+ {
4494+ DestructionShim* shim;
4495+ shim = wl_container_of(notifier, shim, destruction_listener);
4496+
4497+ return shim->executor;
4498+ }
4499+ else
4500+ {
4501+ auto const executor = std::shared_ptr<WaylandExecutor>{new WaylandExecutor{loop}};
4502+ auto shim = std::make_unique<DestructionShim>(executor);
4503+
4504+ shim->destruction_listener.notify = &on_display_destruction;
4505+ wl_event_loop_add_destroy_listener(loop, &(shim.release())->destruction_listener);
4506+
4507+ return executor;
4508+ }
4509+ }
4510+
4511+private:
4512+ WaylandExecutor(wl_event_loop* loop)
4513+ : notify_fd{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE | EFD_NONBLOCK)},
4514+ notify_source{wl_event_loop_add_fd(loop, notify_fd, WL_EVENT_READABLE, &on_notify, this)}
4515+ {
4516+ if (notify_fd == mir::Fd::invalid)
4517+ {
4518+ BOOST_THROW_EXCEPTION((std::system_error{
4519+ errno,
4520+ std::system_category(),
4521+ "Failed to create IPC pause notification eventfd"}));
4522+ }
4523+ }
4524+
4525+ static int on_notify(int fd, uint32_t, void* data)
4526+ {
4527+ auto executor = static_cast<WaylandExecutor*>(data);
4528+
4529+ eventfd_t unused;
4530+ if (auto err = eventfd_read(fd, &unused))
4531+ {
4532+ mir::log_error(
4533+ "eventfd_read failed to consume wakeup notification: %s (%i)",
4534+ strerror(err),
4535+ err);
4536+ }
4537+
4538+ std::lock_guard<std::recursive_mutex> lock{executor->mutex};
4539+ while (!executor->workqueue.empty())
4540+ {
4541+ auto work = std::move(executor->workqueue.front());
4542+ work();
4543+ executor->workqueue.pop_front();
4544+ }
4545+
4546+ return 0;
4547+ }
4548+
4549+ static void on_display_destruction(wl_listener* listener, void*)
4550+ {
4551+ DestructionShim* shim;
4552+ shim = wl_container_of(listener, shim, destruction_listener);
4553+
4554+ {
4555+ std::lock_guard<std::recursive_mutex> lock{shim->executor->mutex};
4556+ wl_event_source_remove(shim->executor->notify_source);
4557+ }
4558+ delete shim;
4559+ }
4560+
4561+ std::recursive_mutex mutex;
4562+ mir::Fd const notify_fd;
4563+ std::deque<std::function<void()>> workqueue;
4564+
4565+ wl_event_source* const notify_source;
4566+
4567+ struct DestructionShim
4568+ {
4569+ explicit DestructionShim(std::shared_ptr<WaylandExecutor> const& executor)
4570+ : executor{executor}
4571+ {
4572+ }
4573+
4574+ std::shared_ptr<WaylandExecutor> const executor;
4575+ wl_listener destruction_listener;
4576+ };
4577+ static_assert(
4578+ std::is_standard_layout<DestructionShim>::value,
4579+ "DestructionShim must be Standard Layout for wl_container_of to be defined behaviour");
4580+};
4581+}
4582+
4583+mf::WaylandConnector::WaylandConnector(
4584+ std::shared_ptr<mf::Shell> const& shell,
4585+ DisplayChanger& display_config,
4586+ std::shared_ptr<mg::GraphicBufferAllocator> const& allocator)
4587+ : display{wl_display_create(), &cleanup_display},
4588+ pause_signal{eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE)},
4589+ allocator{std::dynamic_pointer_cast<mg::WaylandAllocator>(allocator)}
4590+{
4591+ if (pause_signal == mir::Fd::invalid)
4592+ {
4593+ BOOST_THROW_EXCEPTION((std::system_error{
4594+ errno,
4595+ std::system_category(),
4596+ "Failed to create IPC pause notification eventfd"}));
4597+ }
4598+
4599+ if (!display)
4600+ {
4601+ BOOST_THROW_EXCEPTION(std::runtime_error{"Failed to create wl_display"});
4602+ }
4603+
4604+ /*
4605+ * Here be Dragons!
4606+ *
4607+ * Some clients expect a certain order in the publication of globals, and will
4608+ * crash with a different order. Yay!
4609+ *
4610+ * So far I've only found ones which expect wl_compositor before anything else,
4611+ * so stick that first.
4612+ */
4613+ auto const executor = WaylandExecutor::executor_for_event_loop(wl_display_get_event_loop(display.get()));
4614+
4615+ compositor_global = std::make_unique<mf::WlCompositor>(
4616+ display.get(),
4617+ executor,
4618+ this->allocator);
4619+ seat_global = std::make_unique<mf::WlSeat>(display.get(), executor);
4620+ output_manager = std::make_unique<mf::OutputManager>(
4621+ display.get(),
4622+ display_config);
4623+ shell_global = std::make_unique<mf::WlShell>(display.get(), shell, *seat_global);
4624+
4625+ wl_display_init_shm(display.get());
4626+
4627+ if (this->allocator)
4628+ {
4629+ this->allocator->bind_display(display.get());
4630+ }
4631+ else
4632+ {
4633+ mir::log_warning("No WaylandAllocator EGL support!");
4634+ }
4635+
4636+ wl_display_add_socket_auto(display.get());
4637+
4638+ auto wayland_loop = wl_display_get_event_loop(display.get());
4639+
4640+ setup_new_client_handler(display.get(), shell);
4641+
4642+ pause_source = wl_event_loop_add_fd(wayland_loop, pause_signal, WL_EVENT_READABLE, &halt_eventloop, display.get());
4643+}
4644+
4645+mf::WaylandConnector::~WaylandConnector()
4646+{
4647+ if (dispatch_thread.joinable())
4648+ {
4649+ stop();
4650+ }
4651+ wl_event_source_remove(pause_source);
4652+}
4653+
4654+void mf::WaylandConnector::start()
4655+{
4656+ dispatch_thread = std::thread{wl_display_run, display.get()};
4657+}
4658+
4659+void mf::WaylandConnector::stop()
4660+{
4661+ if (eventfd_write(pause_signal, 1) < 0)
4662+ {
4663+ BOOST_THROW_EXCEPTION((std::system_error{
4664+ errno,
4665+ std::system_category(),
4666+ "Failed to send IPC eventloop pause signal"}));
4667+ }
4668+ if (dispatch_thread.joinable())
4669+ {
4670+ dispatch_thread.join();
4671+ dispatch_thread = std::thread{};
4672+ }
4673+ else
4674+ {
4675+ mir::log_warning("WaylandConnector::stop() called on not-running connector?");
4676+ }
4677+}
4678+
4679+int mf::WaylandConnector::client_socket_fd() const
4680+{
4681+ return -1;
4682+}
4683+
4684+int mf::WaylandConnector::client_socket_fd(
4685+ std::function<void(std::shared_ptr<Session> const& session)> const& /*connect_handler*/) const
4686+{
4687+ return -1;
4688+}
4689
4690=== added file 'src/server/frontend/wayland/wayland_connector.h'
4691--- src/server/frontend/wayland/wayland_connector.h 1970-01-01 00:00:00 +0000
4692+++ src/server/frontend/wayland/wayland_connector.h 2017-09-07 05:58:57 +0000
4693@@ -0,0 +1,83 @@
4694+/*
4695+ * Copyright © 2015 Canonical Ltd.
4696+ *
4697+ * This program is free software: you can redistribute it and/or modify it
4698+ * under the terms of the GNU General Public License version 3,
4699+ * as published by the Free Software Foundation.
4700+ *
4701+ * This program is distributed in the hope that it will be useful,
4702+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4703+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4704+ * GNU General Public License for more details.
4705+ *
4706+ * You should have received a copy of the GNU General Public License
4707+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4708+ *
4709+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
4710+ */
4711+
4712+#ifndef MIR_FRONTEND_WAYLAND_CONNECTOR_H_
4713+#define MIR_FRONTEND_WAYLAND_CONNECTOR_H_
4714+
4715+#include "mir/frontend/connector.h"
4716+#include "mir/fd.h"
4717+
4718+#include <wayland-server-core.h>
4719+#include <thread>
4720+
4721+namespace mir
4722+{
4723+
4724+
4725+namespace graphics
4726+{
4727+class GraphicBufferAllocator;
4728+class WaylandAllocator;
4729+}
4730+
4731+namespace frontend
4732+{
4733+class WlCompositor;
4734+class WlApplication;
4735+class WlShell;
4736+class WlSeat;
4737+class OutputManager;
4738+
4739+class Shell;
4740+class DisplayChanger;
4741+
4742+class WaylandConnector : public Connector
4743+{
4744+public:
4745+ WaylandConnector(
4746+ std::shared_ptr<Shell> const& shell,
4747+ DisplayChanger& display_config,
4748+ std::shared_ptr<graphics::GraphicBufferAllocator> const& allocator);
4749+
4750+ ~WaylandConnector() override;
4751+
4752+ void start() override;
4753+ void stop() override;
4754+
4755+ int client_socket_fd() const override;
4756+
4757+ int client_socket_fd(
4758+ std::function<void(std::shared_ptr<Session> const& session)> const& connect_handler) const override;
4759+
4760+private:
4761+ std::unique_ptr<wl_display, void(*)(wl_display*)> const display;
4762+ mir::Fd const pause_signal;
4763+ std::unique_ptr<WlCompositor> compositor_global;
4764+ std::unique_ptr<WlSeat> seat_global;
4765+ std::unique_ptr<OutputManager> output_manager;
4766+ std::shared_ptr<graphics::WaylandAllocator> const allocator;
4767+ std::unique_ptr<WlShell> shell_global;
4768+ std::thread dispatch_thread;
4769+ wl_event_source* pause_source;
4770+};
4771+
4772+
4773+}
4774+}
4775+
4776+#endif // MIR_FRONTEND_WAYLAND_CONNECTOR_H_
4777
4778=== added file 'src/server/frontend/wayland/wayland_default_configuration.cpp'
4779--- src/server/frontend/wayland/wayland_default_configuration.cpp 1970-01-01 00:00:00 +0000
4780+++ src/server/frontend/wayland/wayland_default_configuration.cpp 2017-09-07 05:58:57 +0000
4781@@ -0,0 +1,39 @@
4782+/*
4783+ * Copyright © 2015, 2017 Canonical Ltd.
4784+ *
4785+ * This program is free software: you can redistribute it and/or modify it
4786+ * under the terms of the GNU General Public License version 2 or 3,
4787+ * as published by the Free Software Foundation.
4788+ *
4789+ * This program is distributed in the hope that it will be useful,
4790+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4791+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4792+ * GNU General Public License for more details.
4793+ *
4794+ * You should have received a copy of the GNU General Public License
4795+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4796+ *
4797+ * Authored by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
4798+ */
4799+
4800+#include "mir/default_server_configuration.h"
4801+#include "wayland_connector.h"
4802+
4803+#include "../../scene/mediating_display_changer.h"
4804+#include "mir/graphics/platform.h"
4805+
4806+namespace mf = mir::frontend;
4807+
4808+std::shared_ptr<mf::Connector>
4809+ mir::DefaultServerConfiguration::the_wayland_connector()
4810+{
4811+ return wayland_connector(
4812+ [this]() -> std::shared_ptr<mf::Connector>
4813+ {
4814+ return std::make_shared<mf::WaylandConnector>(
4815+ the_frontend_shell(),
4816+ *the_mediating_display_changer(),
4817+ the_buffer_allocator());
4818+ });
4819+}
4820+
4821
4822=== modified file 'src/server/symbols.map'
4823--- src/server/symbols.map 2017-08-02 11:07:50 +0000
4824+++ src/server/symbols.map 2017-09-07 05:58:57 +0000
4825@@ -913,6 +913,7 @@
4826 mir::DefaultServerConfiguration::the_surface_factory*;
4827 mir::DefaultServerConfiguration::the_surface_stack_model*;
4828 mir::DefaultServerConfiguration::the_touch_visualizer*;
4829+ mir::DefaultServerConfiguration::the_wayland_connector*;
4830 mir::DefaultServerConfiguration::the_window_manager_builder*;
4831 mir::DefaultServerConfiguration::wrap_cursor*;
4832 mir::DefaultServerConfiguration::wrap_cursor_listener*;
4833
4834=== modified file 'tests/mir_test_doubles/mock_egl.cpp'
4835--- tests/mir_test_doubles/mock_egl.cpp 2017-07-28 17:00:43 +0000
4836+++ tests/mir_test_doubles/mock_egl.cpp 2017-09-07 05:58:57 +0000
4837@@ -51,6 +51,16 @@
4838 EGLint extension_eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
4839 EGLBoolean extension_eglGetSyncValuesCHROMIUM(EGLDisplay dpy,
4840 EGLSurface surface, int64_t *ust, int64_t *msc, int64_t *sbc);
4841+EGLBoolean extension_eglBindWaylandDisplayWL(
4842+ EGLDisplay dpy,
4843+ struct wl_display *display);
4844+EGLBoolean extension_eglUnbindWaylandDisplayWL(
4845+ EGLDisplay dpy,
4846+ struct wl_display *display);
4847+EGLBoolean extension_eglQueryWaylandBufferWL(
4848+ EGLDisplay dpy,
4849+ struct wl_resource *buffer,
4850+ EGLint attribute, EGLint *value);
4851
4852 /* EGL{Surface,Display,Config,Context} are all opaque types, so we can put whatever
4853 we want in them for testing */
4854@@ -150,13 +160,24 @@
4855 .WillByDefault(Return(
4856 reinterpret_cast<func_ptr_t>(extension_eglGetSyncValuesCHROMIUM)
4857 ));
4858+ ON_CALL(*this, eglGetProcAddress(StrEq("eglQueryWaylandBufferWL")))
4859+ .WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglQueryWaylandBufferWL)));
4860+ ON_CALL(*this, eglGetProcAddress(StrEq("eglBindWaylandDisplayWL")))
4861+ .WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglBindWaylandDisplayWL)));
4862+ ON_CALL(*this, eglGetProcAddress(StrEq("eglUnbindWaylandDisplayWL")))
4863+ .WillByDefault(Return(reinterpret_cast<func_ptr_t>(&extension_eglUnbindWaylandDisplayWL)));
4864 }
4865
4866 void mtd::MockEGL::provide_egl_extensions()
4867 {
4868 using namespace testing;
4869
4870- const char* egl_exts = "EGL_KHR_image EGL_KHR_image_base EGL_KHR_image_pixmap EGL_EXT_image_dma_buf_import";
4871+ const char* egl_exts =
4872+ "EGL_KHR_image "
4873+ "EGL_KHR_image_base "
4874+ "EGL_KHR_image_pixmap "
4875+ "EGL_EXT_image_dma_buf_import "
4876+ "EGL_WL_bind_wayland_display";
4877 ON_CALL(*this, eglQueryString(_,EGL_EXTENSIONS))
4878 .WillByDefault(Return(egl_exts));
4879 }
4880@@ -430,3 +451,29 @@
4881 return global_mock_egl->eglGetSyncValuesCHROMIUM(dpy, surface,
4882 ust, msc, sbc);
4883 }
4884+
4885+EGLBoolean extension_eglBindWaylandDisplayWL(
4886+ EGLDisplay dpy,
4887+ struct wl_display *display)
4888+{
4889+ CHECK_GLOBAL_MOCK(EGLBoolean);
4890+ return global_mock_egl->eglBindWaylandDisplayWL(dpy, display);
4891+}
4892+
4893+EGLBoolean extension_eglUnbindWaylandDisplayWL(
4894+ EGLDisplay dpy,
4895+ struct wl_display *display)
4896+{
4897+ CHECK_GLOBAL_MOCK(EGLBoolean);
4898+ return global_mock_egl->eglUnbindWaylandDisplayWL(dpy, display);
4899+}
4900+
4901+EGLBoolean extension_eglQueryWaylandBufferWL(
4902+ EGLDisplay dpy,
4903+ struct wl_resource* buffer,
4904+ EGLint attribute, EGLint* value)
4905+{
4906+ CHECK_GLOBAL_MOCK(EGLBoolean);
4907+ return global_mock_egl->eglQueryWaylandBufferWL(
4908+ dpy, buffer, attribute, value);
4909+}
4910
4911=== modified file 'tests/mir_test_doubles/nested_mock_egl.cpp'
4912--- tests/mir_test_doubles/nested_mock_egl.cpp 2017-07-28 17:00:43 +0000
4913+++ tests/mir_test_doubles/nested_mock_egl.cpp 2017-09-07 05:58:57 +0000
4914@@ -30,21 +30,12 @@
4915 EXPECT_CALL(*this, eglTerminate(_)).Times(1);
4916 }
4917
4918- EXPECT_CALL(*this, eglCreateWindowSurface(_, _, _, _)).Times(AnyNumber());
4919- EXPECT_CALL(*this, eglMakeCurrent(_, _, _, _)).Times(AnyNumber());
4920- EXPECT_CALL(*this, eglDestroySurface(_, _)).Times(AnyNumber());
4921- EXPECT_CALL(*this, eglQueryString(_, _)).Times(AnyNumber());
4922-
4923 provide_egl_extensions();
4924 provide_stub_platform_buffer_swapping();
4925
4926- EXPECT_CALL(*this, eglChooseConfig(_, _, _, _, _)).Times(AnyNumber()).WillRepeatedly(
4927+
4928+ ON_CALL(*this, eglChooseConfig(_, _, _, _, _)).WillByDefault(
4929 DoAll(WithArgs<2, 4>(Invoke(this, &NestedMockEGL::egl_choose_config)), Return(EGL_TRUE)));
4930- EXPECT_CALL(*this, eglGetCurrentContext()).Times(AnyNumber());
4931- EXPECT_CALL(*this, eglCreatePbufferSurface(_, _, _)).Times(AnyNumber());
4932- EXPECT_CALL(*this, eglGetProcAddress(StrEq("eglCreateImageKHR"))).Times(AnyNumber());
4933- EXPECT_CALL(*this, eglGetProcAddress(StrEq("eglDestroyImageKHR"))).Times(AnyNumber());
4934- EXPECT_CALL(*this, eglGetProcAddress(StrEq("glEGLImageTargetTexture2DOES"))).Times(AnyNumber());
4935
4936 {
4937 InSequence context_lifecycle;

Subscribers

People subscribed via source and target branches