wayland: Don't unset surface->buffer when wl_buffer destroyed

Don't unset the surface->buffer if the associated wl_buffer object is
destroyed. The MetaWaylandBuffer doesn't really only represent a
wl_buffer object, but also the data (texture) created from the given
wl_buffer. Thus, for example destroying a released SHM wl_buffer should
not destroy the MetaWaylandBuffer instance, because the texture may
still be used.

This commit also fixes a race where calc_showing would hide a window
because, at the time of calculation whether it should be showing, the
surface's buffer had been destroyed as described above.

https://bugzilla.gnome.org/show_bug.cgi?id=762716
This commit is contained in:
Jonas Ådahl
2016-02-26 17:47:21 +08:00
parent 43bd057754
commit d340c3a6dd
4 changed files with 40 additions and 48 deletions

View File

@ -30,6 +30,8 @@
#include <cogl/cogl-wayland-server.h>
#include <meta/util.h>
G_DEFINE_TYPE (MetaWaylandBuffer, meta_wayland_buffer, G_TYPE_OBJECT);
static void
meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
void *data)
@ -37,32 +39,16 @@ meta_wayland_buffer_destroy_handler (struct wl_listener *listener,
MetaWaylandBuffer *buffer =
wl_container_of (listener, buffer, destroy_listener);
buffer->resource = NULL;
wl_signal_emit (&buffer->destroy_signal, buffer);
g_slice_free (MetaWaylandBuffer, buffer);
}
void
meta_wayland_buffer_ref (MetaWaylandBuffer *buffer)
{
buffer->ref_count++;
}
void
meta_wayland_buffer_unref (MetaWaylandBuffer *buffer)
{
buffer->ref_count--;
if (buffer->ref_count == 0)
{
g_warn_if_fail (buffer->use_count == 0);
g_clear_pointer (&buffer->texture, cogl_object_unref);
}
g_object_unref (buffer);
}
void
meta_wayland_buffer_ref_use_count (MetaWaylandBuffer *buffer)
{
g_warn_if_fail (buffer->resource);
buffer->use_count++;
}
@ -73,7 +59,7 @@ meta_wayland_buffer_unref_use_count (MetaWaylandBuffer *buffer)
buffer->use_count--;
if (buffer->use_count == 0)
if (buffer->use_count == 0 && buffer->resource)
wl_resource_queue_event (buffer->resource, WL_BUFFER_RELEASE);
}
@ -93,7 +79,7 @@ meta_wayland_buffer_from_resource (struct wl_resource *resource)
}
else
{
buffer = g_slice_new0 (MetaWaylandBuffer);
buffer = g_object_new (META_TYPE_WAYLAND_BUFFER, NULL);
buffer->resource = resource;
wl_signal_init (&buffer->destroy_signal);
@ -113,6 +99,7 @@ meta_wayland_buffer_ensure_texture (MetaWaylandBuffer *buffer)
struct wl_shm_buffer *shm_buffer;
g_return_val_if_fail (buffer->use_count != 0, NULL);
g_return_val_if_fail (buffer->resource, NULL);
if (buffer->texture)
goto out;
@ -172,3 +159,26 @@ meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer,
wl_shm_buffer_end_access (shm_buffer);
}
}
static void
meta_wayland_buffer_finalize (GObject *object)
{
MetaWaylandBuffer *buffer = META_WAYLAND_BUFFER (object);
g_clear_pointer (&buffer->texture, cogl_object_unref);
G_OBJECT_CLASS (meta_wayland_buffer_parent_class)->finalize (object);
}
static void
meta_wayland_buffer_init (MetaWaylandBuffer *buffer)
{
}
static void
meta_wayland_buffer_class_init (MetaWaylandBufferClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_wayland_buffer_finalize;
}