From adae06ad56d8742d7f4f577ddf77876efa56e866 Mon Sep 17 00:00:00 2001 From: "bors[bot]" Date: Mon, 17 Dec 2018 11:24:35 +0000 Subject: [PATCH] Merge #670 670: [miral-shell] DecorationProvider: Respond to output events r=gerboland a=AlanGriffiths This fixes the background when the screen is rotated left or right: miral-app (in the session) mirout output 1 rotate left The client wasn't receiving notifications of output reconfiguration because it wasn't running an event loop. Co-authored-by: Alan Griffiths Co-authored-by: Christopher James Halse Rogers --- .../decoration_provider.cpp | 159 +++++++++++------- .../example-server-lib/decoration_provider.h | 7 +- .../example-server-lib/wayland_helpers.cpp | 14 +- examples/example-server-lib/wayland_helpers.h | 8 + 4 files changed, 118 insertions(+), 70 deletions(-) diff --git a/examples/example-server-lib/decoration_provider.cpp b/examples/example-server-lib/decoration_provider.cpp index 8aa06a79dd..7fbcbb6772 100644 --- a/examples/example-server-lib/decoration_provider.cpp +++ b/examples/example-server-lib/decoration_provider.cpp @@ -25,6 +25,8 @@ #include #include FT_FREETYPE_H +#include +#include #include #include #include @@ -32,8 +34,9 @@ #include #include +#include +#include #include -#include namespace { @@ -120,6 +123,10 @@ void Printer::printhelp(BackgroundInfo const& region) if (!working) return; + bool rotated = region.output.transform == WL_OUTPUT_TRANSFORM_90 || region.output.transform == WL_OUTPUT_TRANSFORM_270; + auto const width = rotated ? region.output.height : region.output.width; + auto const height = rotated ? region.output.width : region.output.height; + static char const* const helptext[] = { "Welcome to miral-shell", @@ -152,7 +159,7 @@ void Printer::printhelp(BackgroundInfo const& region) auto const line = converter.from_bytes(rawline); - auto const fwidth = std::min(region.output.width / 60, 20); + auto const fwidth = std::min(width / 60, 20); FT_Set_Pixel_Sizes(face, fwidth, 0); @@ -170,12 +177,12 @@ void Printer::printhelp(BackgroundInfo const& region) help_height += line_height; } - int base_y = (region.output.height - help_height)/2; + int base_y = (height - help_height) / 2; auto* const region_address = reinterpret_cast(region.content_area); for (auto const* rawline : helptext) { - int base_x = (region.output.width - help_width)/2; + int base_x = (width - help_width) / 2; auto const line = converter.from_bytes(rawline); @@ -188,12 +195,12 @@ void Printer::printhelp(BackgroundInfo const& region) auto const& bitmap = glyph->bitmap; auto const x = base_x + glyph->bitmap_left; - if (static_cast(x + bitmap.width) <= region.output.width) + if (static_cast(x + bitmap.width) <= width) { unsigned char* src = bitmap.buffer; auto const y = base_y - glyph->bitmap_top; - auto* dest = region_address + y * 4*region.output.width + 4 * x; + auto* dest = region_address + y * 4 * width + 4 * x; for (auto row = 0u; row != bitmap.rows; ++row) { @@ -203,9 +210,9 @@ void Printer::printhelp(BackgroundInfo const& region) } src += bitmap.pitch; - dest += 4*region.output.width; + dest += 4 * width; - if (dest > region_address + region.output.height * 4*region.output.width) + if (dest > region_address + height * 4 * width) break; } } @@ -218,17 +225,11 @@ void Printer::printhelp(BackgroundInfo const& region) using Outputs = std::map; -} - -using namespace mir::geometry; - -struct DecorationProvider::Self +struct DecorationProviderClient { public: - Self(); - - void init(wl_display* display); - void teardown(); + DecorationProviderClient(wl_display* display); + ~DecorationProviderClient(); private: void draw_background(BackgroundInfo& ctx) const; @@ -241,42 +242,39 @@ struct DecorationProvider::Self Outputs outputs; }; -DecorationProvider::Self::Self() : +DecorationProviderClient::DecorationProviderClient(wl_display* display) : globals{ [this](Output const& output) { on_new_output(&output); }, [this](Output const& output) { on_output_changed(&output); }, [this](Output const& output) { on_output_gone(&output); } } { + this->display = display; + globals.init(display); } -void DecorationProvider::Self::on_output_changed(Output const* output) +void DecorationProviderClient::on_output_changed(Output const* output) { auto const p = outputs.find(output); if (p != end(outputs)) draw_background(p->second); } -void DecorationProvider::Self::on_output_gone(Output const* output) +void DecorationProviderClient::on_output_gone(Output const* output) { outputs.erase(output); } -void DecorationProvider::Self::on_new_output(Output const* output) +void DecorationProviderClient::on_new_output(Output const* output) { draw_background(outputs.insert({output, BackgroundInfo{*output}}).first->second); } -void DecorationProvider::Self::init(wl_display* display) +void DecorationProviderClient::draw_background(BackgroundInfo& ctx) const { - this->display = display; - globals.init(display); -} - -void DecorationProvider::Self::draw_background(BackgroundInfo& ctx) const -{ - auto const width = ctx.output.width; - auto const height = ctx.output.height; + bool rotated = ctx.output.transform == WL_OUTPUT_TRANSFORM_90 || ctx.output.transform == WL_OUTPUT_TRANSFORM_270; + auto const width = rotated ? ctx.output.height : ctx.output.width; + auto const height = rotated ? ctx.output.width : ctx.output.height; if (width <= 0 || height <= 0) return; @@ -309,10 +307,10 @@ void DecorationProvider::Self::draw_background(BackgroundInfo& ctx) const &wl_shm_pool_destroy); ctx.buffer = wl_shm_pool_create_buffer( - shm_pool.get(), - 0, - width, height, stride, - WL_SHM_FORMAT_ARGB8888); + shm_pool.get(), + 0, + width, height, stride, + WL_SHM_FORMAT_ARGB8888); } uint8_t const bottom_colour[] = { 0x20, 0x54, 0xe9 }; // Ubuntu orange @@ -321,19 +319,19 @@ void DecorationProvider::Self::draw_background(BackgroundInfo& ctx) const char* row = static_cast(ctx.content_area); for (int j = 0; j < height; j++) - { - uint8_t pattern[4]; + { + uint8_t pattern[4]; - for (auto i = 0; i != 3; ++i) - pattern[i] = (j*bottom_colour[i] + (height-j)*top_colour[i])/height; - pattern[3] = 0xff; + for (auto i = 0; i != 3; ++i) + pattern[i] = (j*bottom_colour[i] + (height-j)*top_colour[i])/height; + pattern[3] = 0xff; - uint32_t* pixel = (uint32_t*)row; - for (int i = 0; i < width; i++) - memcpy(pixel + i, pattern, sizeof pixel[i]); + uint32_t* pixel = (uint32_t*)row; + for (int i = 0; i < width; i++) + memcpy(pixel + i, pattern, sizeof pixel[i]); - row += stride; - } + row += stride; + } static Printer printer; @@ -344,38 +342,85 @@ void DecorationProvider::Self::draw_background(BackgroundInfo& ctx) const wl_display_roundtrip(display); } -void DecorationProvider::Self::teardown() +DecorationProviderClient::~DecorationProviderClient() { outputs.clear(); globals.teardown(); + wl_display_roundtrip(display); +} } +using namespace mir::geometry; + DecorationProvider::DecorationProvider() : - self{std::make_shared()} + shutdown_signal{::eventfd(0, EFD_CLOEXEC)} { + if (shutdown_signal == mir::Fd::invalid) + { + BOOST_THROW_EXCEPTION(( + std::system_error{errno, std::system_category(), "Failed to create shutdown notifier"})); + } } DecorationProvider::~DecorationProvider() = default; void DecorationProvider::stop() { - std::lock_guard lock{mutex}; - running = false; - running_cv.notify_one(); + if (eventfd_write(shutdown_signal, 1) == -1) + { + BOOST_THROW_EXCEPTION(( + std::system_error{ + errno, + std::system_category(), + "Failed to shutdown internal decoration client"})); + } } - -void DecorationProvider::operator()(struct wl_display* display) +void DecorationProvider::operator()(wl_display* display) { - self->init(display); + DecorationProviderClient self(display); - std::unique_lock lock{mutex}; - running = true; + enum FdIndices { + display_fd = 0, + shutdown, + indices + }; - running_cv.wait(lock, [this] { return !running; }); + pollfd fds[indices]; + fds[display_fd] = {wl_display_get_fd(display), POLLIN, 0}; + fds[shutdown] = {shutdown_signal, POLLIN, 0}; - self->teardown(); - wl_display_roundtrip(display); + while (!(fds[shutdown].revents & (POLLIN | POLLERR))) + { + while (wl_display_prepare_read(display) != 0) + { + if (wl_display_dispatch_pending(display) == -1) + { + BOOST_THROW_EXCEPTION(( + std::system_error{errno, std::system_category(), "Failed to dispatch Wayland events"})); + } + } + + if (poll(fds, indices, -1) == -1) + { + wl_display_cancel_read(display); + BOOST_THROW_EXCEPTION(( + std::system_error{errno, std::system_category(), "Failed to wait for event"})); + } + + if (fds[display_fd].revents & (POLLIN | POLLERR)) + { + if (wl_display_read_events(display)) + { + BOOST_THROW_EXCEPTION(( + std::system_error{errno, std::system_category(), "Failed to read Wayland events"})); + } + } + else + { + wl_display_cancel_read(display); + } + } } void DecorationProvider::operator()(std::weak_ptr const& session) diff --git a/examples/example-server-lib/decoration_provider.h b/examples/example-server-lib/decoration_provider.h index bd91086b04..e7c18527fe 100644 --- a/examples/example-server-lib/decoration_provider.h +++ b/examples/example-server-lib/decoration_provider.h @@ -21,8 +21,8 @@ #include +#include -#include #include class DecorationProvider @@ -41,12 +41,9 @@ class DecorationProvider bool is_decoration(miral::Window const& window) const; private: - struct Self; - std::shared_ptr const self; + mir::Fd const shutdown_signal; std::mutex mutable mutex; - bool running{false}; - std::condition_variable running_cv; std::weak_ptr weak_session; }; diff --git a/examples/example-server-lib/wayland_helpers.cpp b/examples/example-server-lib/wayland_helpers.cpp index 5cdbe6e5c4..d423d1e756 100644 --- a/examples/example-server-lib/wayland_helpers.cpp +++ b/examples/example-server-lib/wayland_helpers.cpp @@ -75,12 +75,13 @@ void output_geometry( int32_t /*subpixel*/, const char */*make*/, const char */*model*/, - int32_t /*transform*/) + int32_t transform) { auto output = static_cast(data); output->x = x; output->y = y; + output->transform = transform; } @@ -138,7 +139,8 @@ Globals::Globals( std::function on_new_output, std::function on_output_changed, std::function on_output_gone) - : on_new_output{std::move(on_new_output)}, + : registry{nullptr, [](auto){}}, + on_new_output{std::move(on_new_output)}, on_output_changed{std::move(on_output_changed)}, on_output_gone{std::move(on_output_gone)} { @@ -205,12 +207,7 @@ void Globals::global_remove( void Globals::init(struct wl_display* display) { - wl_registry_listener const registry_listener = { - new_global, - global_remove - }; - - auto const registry = make_scoped(wl_display_get_registry(display), &wl_registry_destroy); + registry = {wl_display_get_registry(display), &wl_registry_destroy}; wl_registry_add_listener(registry.get(), ®istry_listener, this); wl_display_roundtrip(display); @@ -220,4 +217,5 @@ void Globals::init(struct wl_display* display) void Globals::teardown() { bound_outputs.clear(); + registry.reset(); } diff --git a/examples/example-server-lib/wayland_helpers.h b/examples/example-server-lib/wayland_helpers.h index 0430dcbfc7..acb6a9d8b3 100644 --- a/examples/example-server-lib/wayland_helpers.h +++ b/examples/example-server-lib/wayland_helpers.h @@ -50,6 +50,7 @@ class Output int32_t x, y; int32_t width, height; + int32_t transform; wl_output* output; private: static void output_done(void* data, wl_output* output); @@ -89,6 +90,13 @@ class Globals struct wl_registry* registry, uint32_t name); + wl_registry_listener const registry_listener = { + new_global, + global_remove + }; + + std::unique_ptr registry; + std::unordered_map> bound_outputs; std::function const on_new_output;