diff --git a/examples/miral-shell/decoration/decoration.cpp b/examples/miral-shell/decoration/decoration.cpp index 285bf14557..e7f279259b 100644 --- a/examples/miral-shell/decoration/decoration.cpp +++ b/examples/miral-shell/decoration/decoration.cpp @@ -50,16 +50,7 @@ auto UserDecoration::InputManager::buttons() const -> std::vector std::shared_ptr { @@ -398,15 +390,15 @@ auto UserDecoration::create_manager(mir::Server& server) }, [decoration](auto const& left_border_buffer) { - decoration->fill_solid_color(left_border_buffer, decoration->current_titlebar_color); + Renderer::fill_solid_color(left_border_buffer, decoration->current_titlebar_color); }, [decoration](auto const& right_border_buffer) { - decoration->fill_solid_color(right_border_buffer, decoration->current_titlebar_color); + Renderer::fill_solid_color(right_border_buffer, decoration->current_titlebar_color); }, [decoration](auto const& bottom_border_buffer) { - decoration->fill_solid_color(bottom_border_buffer, decoration->current_titlebar_color); + Renderer::fill_solid_color(bottom_border_buffer, decoration->current_titlebar_color); }, [decoration](auto... args) { @@ -467,6 +459,11 @@ auto UserDecoration::create_manager(mir::Server& server) { decoration->redraw_notifier()->notify(); }, + [decoration](auto new_scale) + { + decoration->scale_changed(new_scale); + decoration->redraw_notifier()->notify(); + }, [decoration](auto window_state) { decoration->input_manager.update_window_state(*window_state); diff --git a/examples/miral-shell/decoration/decoration.h b/examples/miral-shell/decoration/decoration.h index 8b29410fbe..a716854068 100644 --- a/examples/miral-shell/decoration/decoration.h +++ b/examples/miral-shell/decoration/decoration.h @@ -49,7 +49,6 @@ class UserDecoration : public miral::Decoration using Renderer = miral::decoration::Renderer; void render_titlebar(Renderer::Buffer const& titlebar_buffer); - void fill_solid_color(Renderer::Buffer const& left_border_buffer, Renderer::Pixel color); static auto create_manager(mir::Server&) -> std::shared_ptr; @@ -129,12 +128,11 @@ class UserDecoration : public miral::Decoration void focused(); void unfocused(); - void minimized(); - void maximized(); - void normal(); + void scale_changed(float new_scale); InputManager input_manager; static Renderer::Pixel const focused_titlebar_color = 0xFF323232; static Renderer::Pixel const unfocused_titlebar_color = 0xFF525252; Renderer::Pixel current_titlebar_color = focused_titlebar_color; + float scale = 1.0; }; diff --git a/include/miral/miral/decoration_adapter.h b/include/miral/miral/decoration_adapter.h index 1f767b1199..f3e19df575 100644 --- a/include/miral/miral/decoration_adapter.h +++ b/include/miral/miral/decoration_adapter.h @@ -87,6 +87,7 @@ using OnWindowResized = std::function; using OnWindowRenamed = std::function; using OnWindowStateUpdated = std::function)>; +using OnScaleChanged = std::function; struct InputContext { @@ -167,16 +168,26 @@ class Renderer Renderer::RenderingCallback render_right_border, Renderer::RenderingCallback render_bottom_border); - static void render_row(Buffer const& buffer, geometry::Point left, geometry::Width length, uint32_t color); + static void fill_solid_color(Renderer::Buffer const& left_border_buffer, Renderer::Pixel color); + + // Renders in display-scale-space, takes into account the display scale + static void render_rect_scaled(Buffer const& buffer, geometry::Rectangle unscaled_rect, float scale, Pixel color); void update_state(miral::decoration::WindowState const& window_state); auto streams_to_spec(std::shared_ptr const& window_state) const -> msh::SurfaceSpecification; void update_render_submit(std::shared_ptr const& window_state); + void scale_changed(float new_scale); + auto scale() const -> float; + private: auto make_graphics_buffer(Buffer const&) -> std::optional>; + // Renders in buffer pixel-scale-space, independent of the actual display scale + static void render_row_unscaled(Buffer const& buffer, geometry::Point left, geometry::Width length, uint32_t color); + + std::shared_ptr const session; std::shared_ptr const buffer_allocator; @@ -189,26 +200,39 @@ class Renderer RenderingCallback const render_left_border; RenderingCallback const render_right_border; RenderingCallback const render_bottom_border; + + float scale_ = 1.0; }; struct DecorationAdapter { DecorationAdapter( + // Notifies Mir that decorations should be redrawn std::shared_ptr const& redraw_notifier, + + // Called by user code in response to input events Renderer::RenderingCallback render_titlebar, Renderer::RenderingCallback render_left_border, Renderer::RenderingCallback render_right_border, Renderer::RenderingCallback render_bottom_border, + // Called by Mir to inform user code of input events OnProcessEnter process_enter, OnProcessLeave process_leave, OnProcessDown process_down, OnProcessUp process_up, OnProcessMove process_move, OnProcessDrag process_drag, + + // Called by Mir to inform user code of changes to the window being decorated OnWindowAttribChanged attrib_changed, OnWindowResized window_resized_to, OnWindowRenamed window_renamed, + + // Called by Mir to inform user code that the display scale changed + OnScaleChanged scale_changed, + + // Called whenever the internal WindowState is updated OnWindowStateUpdated update_decoration_window_state); void set_custom_geometry(std::shared_ptr geometry); diff --git a/src/include/server/mir/shell/decoration/basic_manager.h b/src/include/server/mir/shell/decoration/basic_manager.h index 5fe737cbb3..6217c2cf26 100644 --- a/src/include/server/mir/shell/decoration/basic_manager.h +++ b/src/include/server/mir/shell/decoration/basic_manager.h @@ -52,7 +52,7 @@ class BasicManager : std::shared_ptr const& surface)>; BasicManager( - /* mir::ObserverRegistrar& display_configuration_observers, */ + mir::ObserverRegistrar& display_configuration_observers, DecorationBuilder&& decoration_builder); ~BasicManager(); diff --git a/src/miral/decoration_adapter.cpp b/src/miral/decoration_adapter.cpp index a93e8ca655..2a4df8b8de 100644 --- a/src/miral/decoration_adapter.cpp +++ b/src/miral/decoration_adapter.cpp @@ -233,7 +233,7 @@ auto md::Renderer::Buffer::stream() const -> std::shared_ptr return stream_; } -void md::Renderer::render_row(Buffer const& buffer, geometry::Point left, geometry::Width length, uint32_t color) +void md::Renderer::render_row_unscaled(Buffer const& buffer, geometry::Point left, geometry::Width length, uint32_t color) { auto buf_size = buffer.size(); if (left.y < geometry::Y{} || left.y >= as_y(buf_size.height)) @@ -246,6 +246,26 @@ void md::Renderer::render_row(Buffer const& buffer, geometry::Point left, geomet *i = color; } +void md::Renderer::fill_solid_color(Renderer::Buffer const& left_border_buffer, Renderer::Pixel color) +{ + for (geometry::Y y{0}; y < as_y(left_border_buffer.size().height); y += geometry::DeltaY{1}) + { + Renderer::render_row_unscaled(left_border_buffer, {0, y}, left_border_buffer.size().width, color); + } +} + +void md::Renderer::render_rect_scaled(Buffer const& buffer, geometry::Rectangle unscaled_rect, float scale, Pixel color) +{ + auto tl = unscaled_rect.top_left; + auto start = mir::geometry::Point{tl.x.as_value() * scale, tl.y.as_value() * scale}; + + auto br = unscaled_rect.bottom_right(); + auto end = mir::geometry::Point{br.x.as_value() * scale, br.y.as_value() * scale}; + + for (auto y = start.y; y < end.y; y += geometry::DeltaY{1}) + Renderer::render_row_unscaled(buffer, {start.x, y}, geometry::as_width(end.x - start.x), color); +} + auto md::Renderer::make_graphics_buffer(Buffer const& buffer) -> std::optional> { @@ -274,10 +294,11 @@ auto md::Renderer::make_graphics_buffer(Buffer const& buffer) void md::Renderer::update_state(md::WindowState const& window_state) { auto const conditional_resize = - [](auto& buffer, auto const& rect) + [scale = this->scale_](auto& buffer, auto const& rect) { - if (rect.size != buffer.size()) - buffer.resize(rect.size); + auto scaled_rect_size = rect.size * scale; + if (scaled_rect_size != buffer.size()) + buffer.resize(scaled_rect_size); }; conditional_resize(titlebar_buffer, window_state.titlebar_rect()); @@ -356,7 +377,7 @@ void md::Renderer::update_render_submit(std::shared_ptr const& break; } - float inv_scale = 1.0f; // 1.0f / window_state->scale(); + float inv_scale = 1.0f / scale_; for (auto const& [stream, buffer_opt] : new_buffers) { if (buffer_opt) @@ -367,6 +388,16 @@ void md::Renderer::update_render_submit(std::shared_ptr const& } } +void md::Renderer::scale_changed(float new_scale) +{ + scale_ = new_scale; +} + +auto md::Renderer::scale() const -> float +{ + return scale_; +} + class WindowSurfaceObserver : public ms::NullSurfaceObserver { public: @@ -437,6 +468,7 @@ struct md::DecorationAdapter::Impl : public msd::Decoration OnWindowAttribChanged attrib_changed, OnWindowResized window_resized_to, OnWindowRenamed window_renamed, + OnScaleChanged scale_changed, OnWindowStateUpdated update_decoration_window_state) : redraw_notifier_{redraw_notifier}, render_titlebar{render_titlebar}, @@ -468,6 +500,7 @@ struct md::DecorationAdapter::Impl : public msd::Decoration window_renamed(args...); on_update_decoration_window_state(window_state); }}, + on_scale_changed{scale_changed}, geometry{std::make_shared(default_geometry)} { } @@ -487,7 +520,7 @@ struct md::DecorationAdapter::Impl : public msd::Decoration auto redraw_notifier() { return redraw_notifier_; } - void set_scale(float) override {} + void set_scale(float new_scale) override; ~Impl(); @@ -519,6 +552,7 @@ struct md::DecorationAdapter::Impl : public msd::Decoration OnWindowAttribChanged on_attrib_changed; OnWindowResized on_window_resized_to; OnWindowRenamed on_window_renamed; + OnScaleChanged on_scale_changed; std::shared_ptr geometry; }; @@ -538,6 +572,7 @@ md::DecorationAdapter::DecorationAdapter( OnWindowAttribChanged attrib_changed, OnWindowResized window_resized_to, OnWindowRenamed window_renamed, + OnScaleChanged scale_changed, OnWindowStateUpdated update_decoration_window_state) : impl{std::make_shared( redraw_notifier, @@ -554,6 +589,7 @@ md::DecorationAdapter::DecorationAdapter( attrib_changed, window_resized_to, window_renamed, + scale_changed, update_decoration_window_state)} { } @@ -677,6 +713,15 @@ void md::DecorationAdapter::Impl::window_state_updated(std::shared_ptr(geometry, window_surface.get()); } +void md::DecorationAdapter::Impl::set_scale(float new_scale) +{ + if(new_scale == renderer->scale()) + return; + + renderer->scale_changed(new_scale); + on_scale_changed(new_scale); +} + md::DecorationAdapter::DecorationAdapter::Impl::~Impl() { window_surface->unregister_interest(*window_surface_observer); diff --git a/src/miral/decoration_basic_manager.cpp b/src/miral/decoration_basic_manager.cpp index ea773a7e10..5795e5840c 100644 --- a/src/miral/decoration_basic_manager.cpp +++ b/src/miral/decoration_basic_manager.cpp @@ -61,7 +61,8 @@ struct miral::DecorationBasicManager::Self : public mir::shell::decoration::Basi { Self(mir::Server& server, Decoration::DecorationBuilder&& decoration_builder) : mir::shell::decoration::BasicManager( - [&server,decoration_builder](auto shell, auto window_surface) + *server.the_display_configuration_observer_registrar(), + [&server, decoration_builder](auto shell, auto window_surface) { auto session = window_surface->session().lock(); auto decoration_surface = create_surface(window_surface, shell); diff --git a/src/miral/symbols.map b/src/miral/symbols.map index e2438a0534..149a214bf3 100644 --- a/src/miral/symbols.map +++ b/src/miral/symbols.map @@ -576,7 +576,12 @@ global: miral::decoration::Renderer::area*; miral::decoration::Renderer::buffer_format*; miral::decoration::Renderer::bytes_per_pixel*; + miral::decoration::Renderer::fill_solid_color*; + miral::decoration::Renderer::render_rect_scaled*; miral::decoration::Renderer::render_row*; + miral::decoration::Renderer::render_row_unscaled*; + miral::decoration::Renderer::scale*; + miral::decoration::Renderer::scale_changed*; miral::decoration::Renderer::streams_to_spec*; miral::decoration::Renderer::update_render_submit*; miral::decoration::Renderer::update_state*; @@ -590,6 +595,7 @@ global: miral::decoration::WindowState::left_border_rect*; miral::decoration::WindowState::resize_corner_input_size*; miral::decoration::WindowState::right_border_rect*; + miral::decoration::WindowState::scale*; miral::decoration::WindowState::side_border_height*; miral::decoration::WindowState::side_border_width*; miral::decoration::WindowState::titlebar_height*; diff --git a/src/server/shell/decoration/basic_manager.cpp b/src/server/shell/decoration/basic_manager.cpp index 00e36f1333..1bc51edef8 100644 --- a/src/server/shell/decoration/basic_manager.cpp +++ b/src/server/shell/decoration/basic_manager.cpp @@ -49,27 +49,26 @@ class msd::DisplayConfigurationListener : public mg::NullDisplayConfigurationOb }; msd::BasicManager::BasicManager( - /* ObserverRegistrar& display_configuration_observers, */ + ObserverRegistrar& display_configuration_observers, DecorationBuilder&& decoration_builder) : - decoration_builder{std::move(decoration_builder)} - /* , */ - /* display_config_monitor{std::make_shared( */ - /* [&](mg::DisplayConfiguration const& config) */ - /* { */ - /* // Use the maximum scale to ensure sharp-looking decorations on all outputs */ - /* auto max_output_scale{0.0f}; */ - /* config.for_each_output( */ - /* [&](mg::DisplayConfigurationOutput const& output) */ - /* { */ - /* if (!output.used || !output.connected) return; */ - /* if (!output.valid() || (output.current_mode_index >= output.modes.size())) return; */ - /* */ - /* max_output_scale = std::max(max_output_scale, output.scale); */ - /* }); */ - /* set_scale(max_output_scale); */ - /* })} */ + decoration_builder{std::move(decoration_builder)}, + display_config_monitor{std::make_shared( + [&](mg::DisplayConfiguration const& config) + { + // Use the maximum scale to ensure sharp-looking decorations on all outputs + auto max_output_scale{0.0f}; + config.for_each_output( + [&](mg::DisplayConfigurationOutput const& output) + { + if (!output.used || !output.connected) return; + if (!output.valid() || (output.current_mode_index >= output.modes.size())) return; + + max_output_scale = std::max(max_output_scale, output.scale); + }); + set_scale(max_output_scale); + })} { - /* display_configuration_observers.register_interest(display_config_monitor); */ + display_configuration_observers.register_interest(display_config_monitor); } msd::BasicManager::~BasicManager() diff --git a/src/server/shell/default_configuration.cpp b/src/server/shell/default_configuration.cpp index 3de2520872..38e5a309b9 100644 --- a/src/server/shell/default_configuration.cpp +++ b/src/server/shell/default_configuration.cpp @@ -70,7 +70,7 @@ auto mir::DefaultServerConfiguration::the_decoration_manager() -> std::shared_pt [this] { return wrap_decoration_manager(std::make_shared( - /* *the_display_configuration_observer_registrar(), */ + *the_display_configuration_observer_registrar(), [buffer_allocator = the_buffer_allocator(), executor = the_main_loop(), cursor_images = the_cursor_images()]( diff --git a/tests/unit-tests/shell/test_decoration_basic_manager.cpp b/tests/unit-tests/shell/test_decoration_basic_manager.cpp index 986cc3cbff..dd676a1fee 100644 --- a/tests/unit-tests/shell/test_decoration_basic_manager.cpp +++ b/tests/unit-tests/shell/test_decoration_basic_manager.cpp @@ -59,7 +59,7 @@ struct DecorationBasicManager registrar{std::make_shared>()}; msd::BasicManager manager{ - /* *registrar, */ + *registrar, [this]( std::shared_ptr const&, std::shared_ptr const&) -> std::unique_ptr