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

Subsurface ordering #2491

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/server/frontend_wayland/wl_subcompositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,22 @@ void mf::WlSubsurface::set_position(int32_t x, int32_t y)

void mf::WlSubsurface::place_above(struct wl_resource* sibling)
{
(void)sibling;
log_warning("TODO: wl_subsurface.place_above not implemented");
if (parent)
{
auto const sibling_surface = WlSurface::from(sibling);
parent.value().reorder_subsurface(this, sibling_surface, true);
}
surface->pending_invalidate_surface_data();
}

void mf::WlSubsurface::place_below(struct wl_resource* sibling)
{
(void)sibling;
log_warning("TODO: wl_subsurface.place_below not implemented");
if (parent)
{
auto const sibling_surface = WlSurface::from(sibling);
parent.value().reorder_subsurface(this, sibling_surface, false);
}
surface->pending_invalidate_surface_data();
}

void mf::WlSubsurface::set_sync()
Expand Down
3 changes: 2 additions & 1 deletion src/server/frontend_wayland/wl_subcompositor.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ class WlSubsurface: public WlSurfaceRole, wayland::Subsurface

auto subsurface_at(geometry::Point point) -> std::optional<WlSurface*>;

WlSurface* const surface;

private:
void set_position(int32_t x, int32_t y) override;
void place_above(struct wl_resource* sibling) override;
Expand All @@ -78,7 +80,6 @@ class WlSubsurface: public WlSurfaceRole, wayland::Subsurface
virtual void commit(WlSurfaceState const& state) override;
void surface_destroyed() override;

WlSurface* const surface;
/// This class is responsible for removing itself from the parent's children list when needed
wayland::Weak<WlSurface> const parent;
bool synchronized_;
Expand Down
60 changes: 54 additions & 6 deletions src/server/frontend_wayland/wl_surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ mf::WlSurface::WlSurface(
null_role{this},
role{&null_role}
{
children.push_back(nullptr);
// wl_surface is specified to act in mailbox mode
stream->allow_framedropping(true);
}
Expand Down Expand Up @@ -131,10 +132,15 @@ auto mf::WlSurface::subsurface_at(geom::Point point) -> std::optional<WlSurface*
}
point = point - offset_;
// loop backwards so the first subsurface we find that accepts the input is the topmost one
for (auto child_it = children.rbegin(); child_it != children.rend(); ++child_it)
for (auto const& child : children)
{
if (auto result = (*child_it)->subsurface_at(point))
return result;
if (child)
{
if (auto const result = child->subsurface_at(point))
{
return result;
}
}
}
geom::Rectangle surface_rect = {geom::Point{}, buffer_size_.value_or(geom::Size{})};
for (auto& rect : input_shape.value_or(std::vector<geom::Rectangle>{surface_rect}))
Expand Down Expand Up @@ -181,6 +187,11 @@ void mf::WlSurface::set_pending_offset(std::optional<geom::Displacement> const&

void mf::WlSurface::add_subsurface(WlSubsurface* child)
{
if (!child)
{
// Unlikely, but resulting error would be hard to catch otherwise
fatal_error("subsurface null");
}
if (std::find(children.begin(), children.end(), child) != children.end())
{
log_warning("Subsurface %p added to surface %p multiple times", static_cast<void*>(child), static_cast<void*>(this));
Expand All @@ -192,6 +203,11 @@ void mf::WlSurface::add_subsurface(WlSubsurface* child)

void mf::WlSurface::remove_subsurface(WlSubsurface* child)
{
if (!child)
{
// Unlikely, but resulting error would be hard to catch otherwise
fatal_error("subsurface null");
}
children.erase(
std::remove(
children.begin(),
Expand All @@ -200,6 +216,26 @@ void mf::WlSurface::remove_subsurface(WlSubsurface* child)
children.end());
}

void mf::WlSurface::reorder_subsurface(WlSubsurface* child, WlSurface* sibling, bool above)
{
if (!child)
{
// Unlikely, but resulting error would be hard to catch otherwise
fatal_error("subsurface null");
}
auto iter = std::find_if(begin(children), end(children), [&](WlSubsurface* subsurface)
{
auto const surface = subsurface ? subsurface->surface : this;
return surface == sibling;
});
if (!above)
{
// place below
iter--;
}
children.insert(iter, child);
}

void mf::WlSurface::refresh_surface_data_now()
{
role->refresh_surface_data_now();
Expand All @@ -211,6 +247,14 @@ void mf::WlSurface::populate_surface_data(std::vector<shell::StreamSpecification
{
geometry::Displacement offset = parent_offset + offset_;

// Loops through all children until the nullptr that represents the current (parent) surface
auto child_it = begin(children);
for (; *child_it; child_it++)
{
(*child_it)->populate_surface_data(buffer_streams, input_shape_accumulator, offset);
}
child_it++;

buffer_streams.push_back(msh::StreamSpecification{stream, offset, {}});
geom::Rectangle surface_rect = {geom::Point{} + offset, buffer_size_.value_or(geom::Size{})};
if (input_shape)
Expand All @@ -236,9 +280,10 @@ void mf::WlSurface::populate_surface_data(std::vector<shell::StreamSpecification
input_shape_accumulator.push_back(surface_rect);
}

for (WlSubsurface* subsurface : children)
// Loop through remaining subsurfaces
for (; child_it != end(children); child_it++)
{
subsurface->populate_surface_data(buffer_streams, input_shape_accumulator, offset);
(*child_it)->populate_surface_data(buffer_streams, input_shape_accumulator, offset);
}
}

Expand Down Expand Up @@ -412,7 +457,10 @@ void mf::WlSurface::commit(WlSurfaceState const& state)

for (WlSubsurface* child: children)
{
child->parent_has_committed();
if (child)
{
child->parent_has_committed();
}
}
}

Expand Down
5 changes: 4 additions & 1 deletion src/server/frontend_wayland/wl_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ class WlSurface : public wayland::Surface
void set_pending_offset(std::optional<geometry::Displacement> const& offset);
void add_subsurface(WlSubsurface* child);
void remove_subsurface(WlSubsurface* child);
/// Place a subsurface directly above or below the sibling surface
void reorder_subsurface(WlSubsurface* child, WlSurface* sibling, bool above);
void refresh_surface_data_now();
void pending_invalidate_surface_data() { pending.invalidate_surface_data(); }
void populate_surface_data(std::vector<shell::StreamSpecification>& buffer_streams,
Expand All @@ -150,7 +152,8 @@ class WlSurface : public wayland::Surface

NullWlSurfaceRole null_role;
WlSurfaceRole* role;
std::vector<WlSubsurface*> children; // ordering is from bottom to top
/// Ordering is from bottom to top. A null value represents the parent (this surface)
std::vector<WlSubsurface*> children;

WlSurfaceState pending;
geometry::Displacement offset_;
Expand Down