Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

decoration-strategy-rework #3712

Merged
merged 14 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions src/server/shell/decoration/basic_decoration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ struct PropertyComparison
{
}

template<typename TYPE>
PropertyComparison(TYPE (OBJ::*member))
: comp{[=](OBJ const* a, OBJ const* b)
{
return (a->*member) == (b->*member);
}}
{
}

auto operator()(OBJ const* a, OBJ const* b) const -> bool
{
return comp(a, b);
Expand Down Expand Up @@ -138,16 +147,15 @@ msd::BasicDecoration::BasicDecoration(
std::shared_ptr<DecorationStrategy> decoration_strategy)
: threadsafe_self{std::make_shared<ThreadsafeAccess<BasicDecoration>>(executor)},
decoration_strategy{decoration_strategy},
static_geometry{decoration_strategy->static_geometry()},
shell{shell},
buffer_allocator{buffer_allocator},
cursor_images{cursor_images},
session{window_surface->session().lock()},
buffer_streams{std::make_unique<BufferStreams>(session, static_geometry->buffer_format)},
buffer_streams{std::make_unique<BufferStreams>(session, decoration_strategy->buffer_format())},
renderer{std::make_unique<Renderer>(buffer_allocator, decoration_strategy->render_strategy())},
window_surface{window_surface},
decoration_surface{create_surface()},
window_state{new_window_state()},
window_state{decoration_strategy->new_window_state(window_surface, scale)},
window_surface_observer_manager{std::make_unique<WindowSurfaceObserverManager>(
window_surface,
threadsafe_self)},
Expand Down Expand Up @@ -193,7 +201,7 @@ msd::BasicDecoration::~BasicDecoration()
void msd::BasicDecoration::window_state_updated()
{
auto previous_window_state = std::move(window_state);
window_state = new_window_state();
window_state = decoration_strategy->new_window_state(window_surface, scale);

input_manager->update_window_state(*window_state);

Expand Down Expand Up @@ -259,11 +267,6 @@ void msd::BasicDecoration::set_scale(float new_scale)
window_state_updated();
}

auto msd::BasicDecoration::new_window_state() const -> std::unique_ptr<WindowState>
{
return std::make_unique<WindowState>(static_geometry, window_surface, scale);
}

auto msd::BasicDecoration::create_surface() const -> std::shared_ptr<scene::Surface>
{
msh::SurfaceSpecification params;
Expand All @@ -280,7 +283,7 @@ auto msd::BasicDecoration::create_surface() const -> std::shared_ptr<scene::Surf
params.streams = {{
session->create_buffer_stream(mg::BufferProperties{
geom::Size{1, 1},
static_geometry->buffer_format,
decoration_strategy->buffer_format(),
mg::BufferUsage::software}),
{},
}};
Expand Down Expand Up @@ -318,7 +321,7 @@ void msd::BasicDecoration::update(
if (input_updated({
&InputState::input_shape}))
{
spec.input_shape = input_state->input_shape();
spec.input_shape = input_state->input_shape;
}

if (window_updated({
Expand Down
5 changes: 0 additions & 5 deletions src/server/shell/decoration/basic_decoration.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class StreamSpecification;
namespace decoration
{
template<typename T> class ThreadsafeAccess;
class StaticGeometry;
class WindowState;
class WindowSurfaceObserverManager;
class InputManager;
Expand Down Expand Up @@ -90,9 +89,6 @@ class BasicDecoration
void set_scale(float scale) override;

protected:
/// Creates an up-to-date WindowState object
auto new_window_state() const -> std::unique_ptr<WindowState>;

/// Returns paramaters to create the decoration surface
auto create_surface() const -> std::shared_ptr<scene::Surface>;

Expand All @@ -106,7 +102,6 @@ class BasicDecoration

std::shared_ptr<ThreadsafeAccess<BasicDecoration>> const threadsafe_self;
std::shared_ptr<DecorationStrategy> const decoration_strategy;
std::shared_ptr<StaticGeometry> const static_geometry;

std::shared_ptr<shell::Shell> const shell;
std::shared_ptr<graphics::GraphicBufferAllocator> const buffer_allocator;
Expand Down
17 changes: 1 addition & 16 deletions src/server/shell/decoration/basic_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,22 +136,7 @@ using mir::geometry::Size;
auto msd::BasicManager::compute_size_with_decorations(Size content_size,
MirWindowType type, MirWindowState state) -> Size
{
auto const geometry = decoration_strategy->static_geometry();

switch (border_type_for(type, state))
{
case msd::BorderType::Full:
content_size.width += geometry->side_border_width * 2;
content_size.height += geometry->titlebar_height + geometry->bottom_border_height;
break;
case msd::BorderType::Titlebar:
content_size.height += geometry->titlebar_height;
break;
case msd::BorderType::None:
break;
}

return content_size;
return decoration_strategy->compute_size_with_decorations(content_size, type, state);
}

void msd::BasicManager::set_scale(float new_scale)
Expand Down
136 changes: 107 additions & 29 deletions src/server/shell/decoration/decoration_strategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,30 @@ namespace geom = mir::geometry;
namespace msh = mir::shell;
namespace msd = mir::shell::decoration;

using msd::StaticGeometry;
using msd::WindowState;
using msd::Pixel;
using msd::InputState;

namespace
{
/// Decoration geometry properties that don't change
struct StaticGeometry
{
geom::Height const titlebar_height; ///< Visible height of the top titlebar with the window's name and buttons
geom::Width const side_border_width; ///< Visible width of the side borders
geom::Height const bottom_border_height; ///< Visible height of the bottom border
geom::Size const resize_corner_input_size; ///< The size of the input area of a resizable corner
///< (does not effect surface input area, only where in the surface is
///< considered a resize corner)
geom::Width const button_width; ///< The width of window control buttons
geom::Width const padding_between_buttons; ///< The gep between titlebar buttons
geom::Height const title_font_height; ///< Height of the text used to render the window title
geom::Point const title_font_top_left; ///< Where to render the window title
geom::Displacement const icon_padding; ///< Padding inside buttons around icons
geom::Width const icon_line_width; ///< Width for lines in button icons

MirPixelFormat const buffer_format = mir_pixel_format_argb_8888;
};

static constexpr auto color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0xFF) -> uint32_t
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
Expand Down Expand Up @@ -213,12 +230,14 @@ struct RendererStrategy : public msd::RendererStrategy
RendererStrategy(std::shared_ptr<StaticGeometry> const& static_geometry);

void update_state(WindowState const& window_state, InputState const& input_state) override;
auto render_titlebar() -> std::optional<RenderedPixels> override;
auto render_left_border() -> std::optional<RenderedPixels> override;
auto render_right_border() -> std::optional<RenderedPixels> override;
auto render_bottom_border() -> std::optional<RenderedPixels> override;
auto render_titlebar(msd::BufferMaker const* buffer_maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>> override;
auto render_left_border(msd::BufferMaker const* buffer_maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>> override;
auto render_right_border(msd::BufferMaker const* buffer_maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>> override;
auto render_bottom_border(msd::BufferMaker const* buffer_maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>> override;

private:
using Pixel = msd::BufferMaker::Pixel;

std::shared_ptr<StaticGeometry> const static_geometry;

/// A visual theme for a decoration
Expand Down Expand Up @@ -269,7 +288,7 @@ struct RendererStrategy : public msd::RendererStrategy
geom::Width line_width,
Pixel color)> const render_icon; ///< Draws button's icon to the given buffer
};
std::map<msd::ButtonFunction, Icon const> button_icons;
std::map<msd::Button::Function, Icon const> button_icons;

float scale{1.0f};
std::string name;
Expand All @@ -289,7 +308,7 @@ struct RendererStrategy : public msd::RendererStrategy
bool needs_titlebar_redraw{true};
bool needs_titlebar_buttons_redraw{true};

std::vector<msd::ButtonInfo> buttons;
std::vector<msd::Button> buttons;

void update_solid_color_pixels();

Expand All @@ -298,15 +317,74 @@ struct RendererStrategy : public msd::RendererStrategy
void redraw_titlebar_background(geom::Size scaled_titlebar_size);
void redraw_titlebar_text(geom::Size scaled_titlebar_size);
void redraw_titlebar_buttons(geom::Size scaled_titlebar_size);

static auto alloc_pixels(geom::Size size) -> std::unique_ptr<Pixel[]>;
};

class DecorationStrategy : public msd::DecorationStrategy
{
public:
auto static_geometry() const -> std::shared_ptr<StaticGeometry> override;
~DecorationStrategy() override = default;

auto static_geometry() const -> std::shared_ptr<StaticGeometry>;
auto render_strategy() const -> std::unique_ptr<mir::shell::decoration::RendererStrategy> override;
auto button_placement(unsigned n, const WindowState& ws) const -> mir::geometry::Rectangle override;
auto button_placement(unsigned n, const WindowState& ws) const -> geom::Rectangle override;
auto compute_size_with_decorations(geom::Size content_size, MirWindowType type, MirWindowState state) const
-> geom::Size override;
auto buffer_format() const -> MirPixelFormat override;
auto new_window_state(const std::shared_ptr<mir::scene::Surface>& window_surface,
float scale) const -> std::unique_ptr<WindowState> override;
auto resize_corner_input_size() const -> geom::Size override;
};

auto DecorationStrategy::resize_corner_input_size() const -> geom::Size
{
return static_geometry()->resize_corner_input_size;
}

auto DecorationStrategy::buffer_format() const -> MirPixelFormat
{
return static_geometry()->buffer_format;
}

auto DecorationStrategy::new_window_state(const std::shared_ptr<mir::scene::Surface>& window_surface,
float scale) const -> std::unique_ptr<WindowState>

{
return std::make_unique<WindowState>(
window_surface,
static_geometry()->titlebar_height,
static_geometry()->side_border_width,
static_geometry()->bottom_border_height,
scale);
}

auto DecorationStrategy::compute_size_with_decorations(
geom::Size content_size, MirWindowType type, MirWindowState state) const -> geom::Size
{
switch (msd::border_type_for(type, state))
{
case msd::BorderType::Full:
content_size.width += static_geometry()->side_border_width * 2;
content_size.height += static_geometry()->titlebar_height + static_geometry()->bottom_border_height;
break;
case msd::BorderType::Titlebar:
content_size.height += static_geometry()->titlebar_height;
break;
case msd::BorderType::None:
break;
}

return content_size;
}

auto RendererStrategy::alloc_pixels(geom::Size size) -> std::unique_ptr<Pixel[]>
{
if (size_t const buf_size = area(size) * sizeof(Pixel))
return std::unique_ptr<Pixel[]>{new Pixel[buf_size]};
else
return {};
}
}

auto msd::border_type_for(MirWindowType type, MirWindowState state) -> msd::BorderType
Expand Down Expand Up @@ -354,9 +432,9 @@ auto msd::border_type_for(MirWindowType type, MirWindowState state) -> msd::Bord
return {};
}

auto msd::DecorationStrategy::default_decoration_strategy() -> std::unique_ptr<DecorationStrategy>
auto msd::DecorationStrategy::default_decoration_strategy() -> std::shared_ptr<DecorationStrategy>
{
return std::make_unique<::DecorationStrategy>();
return std::make_shared<::DecorationStrategy>();
}

class RendererStrategy::Text::Impl
Expand Down Expand Up @@ -637,17 +715,17 @@ RendererStrategy::RendererStrategy(std::shared_ptr<StaticGeometry> const& static
current_theme{nullptr},
text{Text::instance()},
button_icons{
{msd::ButtonFunction::Close, {
{msd::Button::Close, {
default_close_normal_button,
default_close_active_button,
default_button_icon,
render_close_icon}},
{msd::ButtonFunction::Maximize, {
{msd::Button::Maximize, {
default_normal_button,
default_active_button,
default_button_icon,
render_maximize_icon}},
{msd::ButtonFunction::Minimize, {
{msd::Button::Minimize, {
default_normal_button,
default_active_button,
default_button_icon,
Expand Down Expand Up @@ -704,28 +782,28 @@ void RendererStrategy::update_state(WindowState const& window_state, InputState
needs_titlebar_redraw = true;
}

if (input_state.buttons() != buttons)
if (input_state.buttons != buttons)
{
// If the number of buttons or their location changed, redraw the whole titlebar
// Otherwise if the buttons are in the same place, just redraw them
if (input_state.buttons().size() != buttons.size())
if (input_state.buttons.size() != buttons.size())
{
needs_titlebar_redraw = true;
}
else
{
for (unsigned i = 0; i < buttons.size(); i++)
{
if (input_state.buttons()[i].rect != buttons[i].rect)
if (input_state.buttons[i].rect != buttons[i].rect)
needs_titlebar_redraw = true;
}
}
buttons = input_state.buttons();
buttons = input_state.buttons;
needs_titlebar_buttons_redraw = true;
}
}

auto RendererStrategy::render_titlebar() -> std::optional<RenderedPixels>
auto RendererStrategy::render_titlebar(msd::BufferMaker const* maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>>
{
auto const scaled_titlebar_size{titlebar_size * scale};

Expand Down Expand Up @@ -753,34 +831,34 @@ auto RendererStrategy::render_titlebar() -> std::optional<RenderedPixels>
needs_titlebar_redraw = false;
needs_titlebar_buttons_redraw = false;

return RenderedPixels{static_geometry->buffer_format, scaled_titlebar_size, titlebar_pixels.get()};
return maker->make_buffer(static_geometry->buffer_format, scaled_titlebar_size, titlebar_pixels.get());
}

auto RendererStrategy::render_left_border() -> std::optional<RenderedPixels>
auto RendererStrategy::render_left_border(msd::BufferMaker const* maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>>
{
auto const scaled_left_border_size{left_border_size * scale};
if (!area(scaled_left_border_size))
return std::nullopt;
update_solid_color_pixels();
return RenderedPixels{static_geometry->buffer_format, scaled_left_border_size, solid_color_pixels.get()};
return maker->make_buffer(static_geometry->buffer_format, scaled_left_border_size, solid_color_pixels.get());
}

auto RendererStrategy::render_right_border() -> std::optional<RenderedPixels>
auto RendererStrategy::render_right_border(msd::BufferMaker const* maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>>
{
auto const scaled_right_border_size{right_border_size * scale};
if (!area(scaled_right_border_size))
return std::nullopt;
update_solid_color_pixels();
return RenderedPixels{static_geometry->buffer_format, scaled_right_border_size, solid_color_pixels.get()};
return maker->make_buffer(static_geometry->buffer_format, scaled_right_border_size, solid_color_pixels.get());
}

auto RendererStrategy::render_bottom_border() -> std::optional<RenderedPixels>
auto RendererStrategy::render_bottom_border(msd::BufferMaker const* maker) -> std::optional<std::shared_ptr<mir::graphics::Buffer>>
{
auto const scaled_bottom_border_size{bottom_border_size * scale};
if (!area(scaled_bottom_border_size))
return std::nullopt;
update_solid_color_pixels();
return RenderedPixels{static_geometry->buffer_format, scaled_bottom_border_size, solid_color_pixels.get()};
return maker->make_buffer(static_geometry->buffer_format, scaled_bottom_border_size, solid_color_pixels.get());
}

void RendererStrategy::update_solid_color_pixels()
Expand Down Expand Up @@ -839,7 +917,7 @@ void RendererStrategy::redraw_titlebar_buttons(geom::Size const scaled_titlebar_
if (icon != button_icons.end())
{
Pixel button_color = icon->second.normal_color;
if (button.state == msd::ButtonState::Hovered)
if (button.state == msd::Button::Hovered)
button_color = icon->second.active_color;
for (geom::Y y{scaled_button_rect.top()}; y < scaled_button_rect.bottom(); y += geom::DeltaY{1})
{
Expand Down Expand Up @@ -906,7 +984,7 @@ auto DecorationStrategy::render_strategy() const -> std::unique_ptr<mir::shell::
return std::make_unique<::RendererStrategy>(static_geometry());
}

auto DecorationStrategy::button_placement(unsigned n, const WindowState& ws) const -> mir::geometry::Rectangle
auto DecorationStrategy::button_placement(unsigned n, const WindowState& ws) const -> geom::Rectangle
{
auto const titlebar = ws.titlebar_rect();
auto const geometry = static_geometry();
Expand Down
Loading
Loading