wayland-surface: Attach the buffer to a surface, even if it doesn't have a role

Currently, set_cursor isn't properly working. Often, the requests look
like this:

  cursor_surface = wl_compositor.create_surface()
  cursor_buffer = create_cursor_buffer()
  cursor_surface.attach(cursor_buffer, 0, 0)
  cursor_surface.commit()
  wl_pointer.set_cursor(cursor_surface, 7, 14)

But since the surface doesn't "have a role" when the commit comes in,
we ignore it, and don't do anything with the pending buffer. When
set_cursor is called, however, we don't immediately update anything
since it doesn't have a buffer.

This effectively means that set_cursor has unpredictable side effects.
Weston's toy toolkit reuses the same surface for every buffer, so it
only fails the first time. In clients that use a new surface for every
cursor sprite, the cursor is effectively invisible.

To solve this, change the code to always set the buffer for a surface,
even if it doesn't have any real role.
This commit is contained in:
Jasper St. Pierre 2014-02-01 17:05:14 -05:00
parent d74796ee80
commit 92e36e7076

View File

@ -250,34 +250,25 @@ ensure_buffer_texture (MetaWaylandBuffer *buffer)
static void static void
cursor_surface_commit (MetaWaylandSurface *surface, cursor_surface_commit (MetaWaylandSurface *surface,
MetaWaylandDoubleBufferedState *pending) MetaWaylandDoubleBufferedState *pending,
gboolean buffer_changed)
{ {
MetaWaylandBuffer *buffer = pending->buffer; if (buffer_changed)
if (pending->newly_attached && buffer != surface->buffer_ref.buffer)
{
ensure_buffer_texture (buffer);
meta_wayland_buffer_reference (&surface->buffer_ref, buffer);
}
meta_wayland_seat_update_sprite (surface->compositor->seat); meta_wayland_seat_update_sprite (surface->compositor->seat);
} }
static gboolean static void
actor_surface_commit (MetaWaylandSurface *surface, actor_surface_commit (MetaWaylandSurface *surface,
MetaWaylandDoubleBufferedState *pending) MetaWaylandDoubleBufferedState *pending,
gboolean buffer_changed)
{ {
MetaSurfaceActor *surface_actor = surface->surface_actor; MetaSurfaceActor *surface_actor = surface->surface_actor;
MetaWaylandBuffer *buffer = pending->buffer; MetaWaylandBuffer *buffer = pending->buffer;
gboolean changed = FALSE;
/* wl_surface.attach */ if (buffer_changed)
if (pending->newly_attached && buffer != surface->buffer_ref.buffer)
{ {
ensure_buffer_texture (buffer); ensure_buffer_texture (buffer);
meta_wayland_buffer_reference (&surface->buffer_ref, buffer);
meta_surface_actor_attach_wayland_buffer (surface_actor, buffer); meta_surface_actor_attach_wayland_buffer (surface_actor, buffer);
changed = TRUE;
} }
surface_process_damage (surface, pending->damage); surface_process_damage (surface, pending->damage);
@ -286,15 +277,16 @@ actor_surface_commit (MetaWaylandSurface *surface,
meta_surface_actor_set_opaque_region (surface_actor, pending->opaque_region); meta_surface_actor_set_opaque_region (surface_actor, pending->opaque_region);
if (pending->input_region) if (pending->input_region)
meta_surface_actor_set_input_region (surface_actor, pending->input_region); meta_surface_actor_set_input_region (surface_actor, pending->input_region);
return changed;
} }
static void static void
toplevel_surface_commit (MetaWaylandSurface *surface, toplevel_surface_commit (MetaWaylandSurface *surface,
MetaWaylandDoubleBufferedState *pending) MetaWaylandDoubleBufferedState *pending,
gboolean buffer_changed)
{ {
if (actor_surface_commit (surface, pending)) actor_surface_commit (surface, pending, buffer_changed);
if (buffer_changed)
{ {
MetaWindow *window = surface->window; MetaWindow *window = surface->window;
MetaWaylandBuffer *buffer = pending->buffer; MetaWaylandBuffer *buffer = pending->buffer;
@ -398,7 +390,8 @@ move_double_buffered_state (MetaWaylandDoubleBufferedState *from,
static void static void
subsurface_surface_commit (MetaWaylandSurface *surface, subsurface_surface_commit (MetaWaylandSurface *surface,
MetaWaylandDoubleBufferedState *pending) MetaWaylandDoubleBufferedState *pending,
gboolean buffer_changed)
{ {
/* /*
* If the sub-surface is in synchronous mode, post-pone the commit of its * If the sub-surface is in synchronous mode, post-pone the commit of its
@ -416,7 +409,11 @@ subsurface_surface_commit (MetaWaylandSurface *surface,
{ {
move_double_buffered_state (pending, &surface->sub.pending_surface_state); move_double_buffered_state (pending, &surface->sub.pending_surface_state);
} }
else if (actor_surface_commit (surface, pending)) else
{
actor_surface_commit (surface, pending, buffer_changed);
if (buffer_changed)
{ {
MetaSurfaceActor *surface_actor = surface->surface_actor; MetaSurfaceActor *surface_actor = surface->surface_actor;
MetaWaylandBuffer *buffer = pending->buffer; MetaWaylandBuffer *buffer = pending->buffer;
@ -433,6 +430,7 @@ subsurface_surface_commit (MetaWaylandSurface *surface,
clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y); clutter_actor_set_position (CLUTTER_ACTOR (surface_actor), x, y);
} }
} }
}
static void static void
subsurface_parent_surface_committed (MetaWaylandSurface *surface); subsurface_parent_surface_committed (MetaWaylandSurface *surface);
@ -448,13 +446,21 @@ commit_double_buffered_state (MetaWaylandSurface *surface,
MetaWaylandDoubleBufferedState *pending) MetaWaylandDoubleBufferedState *pending)
{ {
MetaWaylandCompositor *compositor = surface->compositor; MetaWaylandCompositor *compositor = surface->compositor;
gboolean buffer_changed = FALSE;
/* wl_surface.attach */
if (pending->newly_attached && pending->buffer != surface->buffer_ref.buffer)
{
meta_wayland_buffer_reference (&surface->buffer_ref, pending->buffer);
buffer_changed = TRUE;
}
if (surface == compositor->seat->sprite) if (surface == compositor->seat->sprite)
cursor_surface_commit (surface, pending); cursor_surface_commit (surface, pending, buffer_changed);
else if (surface->window) else if (surface->window)
toplevel_surface_commit (surface, pending); toplevel_surface_commit (surface, pending, buffer_changed);
else if (surface->subsurface.resource) else if (surface->subsurface.resource)
subsurface_surface_commit (surface, pending); subsurface_surface_commit (surface, pending, buffer_changed);
g_list_foreach (surface->subsurfaces, g_list_foreach (surface->subsurfaces,
parent_surface_committed, parent_surface_committed,