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 input (finally) #346

Merged
merged 5 commits into from
Apr 27, 2018
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
77 changes: 54 additions & 23 deletions src/server/frontend_wayland/wl_pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ using namespace mir::geometry;

struct mf::WlPointer::Cursor
{
virtual void apply_to(wl_resource* target) = 0;
virtual void apply_to(WlSurface* surface) = 0;
virtual ~Cursor() = default;
Cursor() = default;

Expand All @@ -47,7 +47,7 @@ namespace
{
struct NullCursor : mf::WlPointer::Cursor
{
void apply_to(wl_resource*) override {}
void apply_to(mf::WlSurface*) override {}
};
}

Expand All @@ -65,6 +65,8 @@ mf::WlPointer::WlPointer(

mf::WlPointer::~WlPointer()
{
if (focused_surface)
focused_surface.value()->remove_destroy_listener(this);
on_destroy(this);
}

Expand Down Expand Up @@ -110,13 +112,20 @@ void mf::WlPointer::handle_event(MirPointerEvent const* event, WlSurface* surfac
auto point = Point{mir_pointer_event_axis_value(event, mir_pointer_axis_x),
mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
auto transformed = surface->transform_point(point);
handle_enter(transformed.first, transformed.second);
handle_frame();
if (transformed)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a style nit: I prefer to restrict the scope of everything (in this case transformed). Vis:

            if (auto const transformed = surface->transform_point(point))

I know it makes little difference here (and won't block on it).

{
handle_enter(transformed.value().first, transformed.value().second);
handle_frame();
}
else
{
log_warning("surface->transform_point() returned nullopt for enter action");
}
break;
}
case mir_pointer_action_leave:
{
handle_leave(surface->raw_resource());
handle_leave();
handle_frame();
break;
}
Expand All @@ -132,14 +141,27 @@ void mf::WlPointer::handle_event(MirPointerEvent const* event, WlSurface* surfac
mir_pointer_event_axis_value(event, mir_pointer_axis_y)};
auto transformed = surface->transform_point(point);

if (!last_position || transformed.first != last_position.value())
if (transformed && focused_surface && transformed.value().second == focused_surface.value())
{
wl_pointer_send_motion(
resource,
timestamp,
wl_fixed_from_double(transformed.first.x.as_int()),
wl_fixed_from_double(transformed.first.y.as_int()));
last_position = transformed.first;
if (!last_position || transformed.value().first != last_position.value())
{
wl_pointer_send_motion(
resource,
timestamp,
wl_fixed_from_double(transformed.value().first.x.as_int()),
wl_fixed_from_double(transformed.value().first.y.as_int()));
last_position = transformed.value().first;
needs_frame = true;
}
}
else
{
if (focused_surface)
handle_leave();
if (transformed)
handle_enter(transformed.value().first, transformed.value().second);
else
log_warning("surface->transform_point() returned nullopt for motion action");
needs_frame = true;
}

Expand Down Expand Up @@ -176,25 +198,34 @@ void mf::WlPointer::handle_event(MirPointerEvent const* event, WlSurface* surfac
}
}

void mf::WlPointer::handle_enter(Point position, wl_resource* target)
void mf::WlPointer::handle_enter(Point position, WlSurface* surface)
{
cursor->apply_to(target);
cursor->apply_to(surface);
auto const serial = wl_display_next_serial(display);
wl_pointer_send_enter(
resource,
serial,
target,
surface->raw_resource(),
wl_fixed_from_double(position.x.as_int()),
wl_fixed_from_double(position.y.as_int()));
surface->add_destroy_listener(this, [this]()
{
handle_leave();
});
focused_surface = surface;
}

void mf::WlPointer::handle_leave(wl_resource* target)
void mf::WlPointer::handle_leave()
{
if (!focused_surface)
return;
focused_surface.value()->remove_destroy_listener(this);
auto const serial = wl_display_next_serial(display);
wl_pointer_send_leave(
resource,
serial,
target);
focused_surface.value()->raw_resource());
focused_surface = std::experimental::nullopt;
last_position = std::experimental::nullopt;
}

Expand All @@ -209,7 +240,7 @@ namespace
struct WlStreamCursor : mf::WlPointer::Cursor
{
WlStreamCursor(std::shared_ptr<mf::Session> const session, std::shared_ptr<mf::BufferStream> const& stream, Displacement hotspot);
void apply_to(wl_resource* target) override;
void apply_to(mf::WlSurface* surface) override;

std::shared_ptr<mf::Session> const session;
std::shared_ptr<mf::BufferStream> const stream;
Expand All @@ -219,7 +250,7 @@ struct WlStreamCursor : mf::WlPointer::Cursor
struct WlHiddenCursor : mf::WlPointer::Cursor
{
WlHiddenCursor(std::shared_ptr<mf::Session> const session);
void apply_to(wl_resource* target) override;
void apply_to(mf::WlSurface* surface) override;

std::shared_ptr<mf::Session> const session;
};
Expand Down Expand Up @@ -258,9 +289,9 @@ WlStreamCursor::WlStreamCursor(
{
}

void WlStreamCursor::apply_to(wl_resource* target)
void WlStreamCursor::apply_to(mf::WlSurface* surface)
{
auto id = mf::WlSurface::from(target)->surface_id();
auto id = surface->surface_id();
if (id.as_value())
{
auto const mir_window = session->get_surface(id);
Expand All @@ -274,9 +305,9 @@ WlHiddenCursor::WlHiddenCursor(
{
}

void WlHiddenCursor::apply_to(wl_resource* target)
void WlHiddenCursor::apply_to(mf::WlSurface* surface)
{
auto id = mf::WlSurface::from(target)->surface_id();
auto id = surface->surface_id();
if (id.as_value())
{
auto const mir_window = session->get_surface(id);
Expand Down
5 changes: 3 additions & 2 deletions src/server/frontend_wayland/wl_pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ class WlPointer : public wayland::Pointer

MirPointerButtons last_buttons{0};
std::experimental::optional<mir::geometry::Point> last_position;
std::experimental::optional<WlSurface*> focused_surface;

void handle_enter(mir::geometry::Point position, wl_resource* target);
void handle_leave(wl_resource* target);
void handle_enter(mir::geometry::Point position, WlSurface* surface);
void handle_leave();
void handle_frame();

void set_cursor(uint32_t serial, std::experimental::optional<wl_resource*> const& surface, int32_t hotspot_x, int32_t hotspot_y) override;
Expand Down
5 changes: 5 additions & 0 deletions src/server/frontend_wayland/wl_subcompositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ void mf::WlSubsurface::parent_has_committed()
}
}

std::experimental::optional<std::pair<geom::Point, mf::WlSurface*>> mf::WlSubsurface::transform_point(geom::Point point)
{
return surface->transform_point(point);
}

void mf::WlSubsurface::set_position(int32_t x, int32_t y)
{
surface->set_pending_offset(geom::Displacement{x, y});
Expand Down
2 changes: 2 additions & 0 deletions src/server/frontend_wayland/wl_subcompositor.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class WlSubsurface: public WlSurfaceRole, wayland::Subsurface

void parent_has_committed();

std::experimental::optional<std::pair<geometry::Point, WlSurface*>> transform_point(geometry::Point point);

private:
void set_position(int32_t x, int32_t y) override;
void place_above(struct wl_resource* sibling) override;
Expand Down
35 changes: 33 additions & 2 deletions src/server/frontend_wayland/wl_surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ mf::WlSurface::WlSurface(
mf::WlSurface::~WlSurface()
{
*destroyed = true;

// so that unregister_destroy_listener calls invoked from destroy listeners don't screw up the iterator
auto listeners = move(destroy_listeners);
destroy_listeners.clear();
for (auto listener: listeners)
{
listener.second();
}

role->destroy();
session->destroy_buffer_stream(stream_id);
}
Expand All @@ -95,9 +104,21 @@ bool mf::WlSurface::synchronized() const
return role->synchronized();
}

std::pair<geom::Point, wl_resource*> mf::WlSurface::transform_point(geom::Point point) const
std::experimental::optional<std::pair<geom::Point, mf::WlSurface*>> mf::WlSurface::transform_point(geom::Point point)
{
return std::make_pair(point - offset_, resource);
point = point - offset_;
for (auto child : children)
{
auto result = child->transform_point(point);
if (result)
return result;
}
for (auto& rect : input_shape.value_or(std::vector<geom::Rectangle>{{{}, buffer_size()}}))
{
if (rect.contains(point))
return std::make_pair(point, this);
}
return std::experimental::nullopt;
}

mf::SurfaceId mf::WlSurface::surface_id() const
Expand Down Expand Up @@ -166,6 +187,16 @@ void mf::WlSurface::populate_surface_data(std::vector<shell::StreamSpecification
}
}

void mf::WlSurface::add_destroy_listener(void const* key, std::function<void()> listener)
{
destroy_listeners[key] = listener;
}

void mf::WlSurface::remove_destroy_listener(void const* key)
{
destroy_listeners.erase(key);
}

mf::WlSurface* mf::WlSurface::from(wl_resource* resource)
{
void* raw_surface = wl_resource_get_user_data(resource);
Expand Down
7 changes: 5 additions & 2 deletions src/server/frontend_wayland/wl_surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ class WlSurface : public wayland::Surface
geometry::Displacement offset() const { return offset_; }
geometry::Size buffer_size() const { return buffer_size_.value_or(geometry::Size{}); }
bool synchronized() const;
std::pair<geometry::Point, wl_resource*> transform_point(geometry::Point point) const;
wl_resource* raw_resource() { return resource; }
std::experimental::optional<std::pair<geometry::Point, WlSurface*>> transform_point(geometry::Point point);
wl_resource* raw_resource() const { return resource; }
mir::frontend::SurfaceId surface_id() const;

void set_role(WlSurfaceRole* role_);
Expand All @@ -131,6 +131,8 @@ class WlSurface : public wayland::Surface
std::vector<mir::geometry::Rectangle>& input_shape_accumulator,
geometry::Displacement const& parent_offset) const;
void commit(WlSurfaceState const& state);
void add_destroy_listener(void const* key, std::function<void()> listener);
void remove_destroy_listener(void const* key);

std::shared_ptr<mir::frontend::Session> const session;
mir::frontend::BufferStreamId const stream_id;
Expand All @@ -151,6 +153,7 @@ class WlSurface : public wayland::Surface
std::experimental::optional<geometry::Size> buffer_size_;
std::vector<WlSurfaceState::Callback> frame_callbacks;
std::experimental::optional<std::vector<mir::geometry::Rectangle>> input_shape;
std::map<void const*, std::function<void()>> destroy_listeners;
std::shared_ptr<bool> const destroyed;

void send_frame_callbacks();
Expand Down