diff --git a/meson/meson-postinstall.sh b/meson/meson-postinstall.sh old mode 100755 new mode 100644 diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c index 86c62e5b1..df7127846 100644 --- a/src/compositor/meta-window-actor-wayland.c +++ b/src/compositor/meta-window-actor-wayland.c @@ -74,7 +74,7 @@ meta_window_actor_wayland_rebuild_surface_tree (MetaWindowActor *actor) meta_window_actor_get_surface (actor); MetaWaylandSurface *surface = meta_surface_actor_wayland_get_surface ( META_SURFACE_ACTOR_WAYLAND (surface_actor)); - GNode *root_node = surface->subsurface_branch_node; + GNode *root_node = surface->output_state.subsurface_branch_node; SurfaceTreeTraverseData traverse_data; traverse_data = (SurfaceTreeTraverseData) { diff --git a/src/meson.build b/src/meson.build index 97702abfb..aa4b781dd 100644 --- a/src/meson.build +++ b/src/meson.build @@ -590,6 +590,8 @@ if have_wayland 'wayland/meta-wayland-text-input.h', 'wayland/meta-wayland-touch.c', 'wayland/meta-wayland-touch.h', + 'wayland/meta-wayland-transaction.c', + 'wayland/meta-wayland-transaction.h', 'wayland/meta-wayland-types.h', 'wayland/meta-wayland-versions.h', 'wayland/meta-wayland-viewporter.c', diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c index 4e0ff5225..533ea01d0 100644 --- a/src/wayland/meta-wayland-actor-surface.c +++ b/src/wayland/meta-wayland-actor-surface.c @@ -181,16 +181,18 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor surface_actor = priv->actor; stex = meta_surface_actor_get_texture (surface_actor); - buffer = surface->buffer_ref->buffer; + buffer = meta_wayland_surface_get_buffer (surface); if (buffer) { CoglSnippet *snippet; gboolean is_y_inverted; + CoglTexture *texture; snippet = meta_wayland_buffer_create_snippet (buffer); is_y_inverted = meta_wayland_buffer_is_y_inverted (buffer); - meta_shaped_texture_set_texture (stex, surface->texture); + texture = meta_wayland_surface_get_texture (surface); + meta_shaped_texture_set_texture (stex, texture); meta_shaped_texture_set_snippet (stex, snippet); meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted); meta_shaped_texture_set_buffer_scale (stex, surface->scale); @@ -270,7 +272,8 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor meta_shaped_texture_ensure_size_valid (stex); - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface_surface) { MetaWaylandActorSurface *actor_surface; @@ -428,7 +431,8 @@ meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surface) meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (actor_surface)); MetaWaylandSurface *subsurface_surface; - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface_surface) { MetaWaylandActorSurface *actor_surface; diff --git a/src/wayland/meta-wayland-buffer.c b/src/wayland/meta-wayland-buffer.c index 069269ef7..67e5c140c 100644 --- a/src/wayland/meta-wayland-buffer.c +++ b/src/wayland/meta-wayland-buffer.c @@ -173,7 +173,8 @@ meta_wayland_buffer_realize (MetaWaylandBuffer *buffer) EGL_TEXTURE_FORMAT, &format, NULL)) { - buffer->type = META_WAYLAND_BUFFER_TYPE_EGL_IMAGE; + buffer->dma_buf.dma_buf = + meta_wayland_dma_buf_fds_for_wayland_buffer (buffer); return TRUE; } @@ -506,7 +507,6 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer, CoglTexture **texture, GError **error) { - g_return_val_if_fail (buffer->resource, FALSE); if (!meta_wayland_buffer_is_realized (buffer)) { @@ -566,6 +566,25 @@ meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer) #endif /* HAVE_WAYLAND_EGLSTREAM */ } +void +meta_wayland_buffer_inc_use_count (MetaWaylandBuffer *buffer) +{ + g_warn_if_fail (buffer->resource); + + buffer->use_count++; +} + +void +meta_wayland_buffer_dec_use_count (MetaWaylandBuffer *buffer) +{ + g_return_if_fail (buffer->use_count > 0); + + buffer->use_count--; + + if (buffer->use_count == 0 && buffer->resource) + wl_buffer_send_release (buffer->resource); +} + gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer) { @@ -752,6 +771,8 @@ meta_wayland_buffer_finalize (GObject *object) { MetaWaylandBuffer *buffer = META_WAYLAND_BUFFER (object); + g_warn_if_fail (buffer->use_count == 0); + g_clear_pointer (&buffer->egl_image.texture, cogl_object_unref); #ifdef HAVE_WAYLAND_EGLSTREAM g_clear_pointer (&buffer->egl_stream.texture, cogl_object_unref); diff --git a/src/wayland/meta-wayland-buffer.h b/src/wayland/meta-wayland-buffer.h index d0d216ef9..5e4dbf526 100644 --- a/src/wayland/meta-wayland-buffer.h +++ b/src/wayland/meta-wayland-buffer.h @@ -53,6 +53,8 @@ struct _MetaWaylandBuffer struct wl_resource *resource; struct wl_listener destroy_listener; + unsigned int use_count; + gboolean is_y_inverted; MetaWaylandBufferType type; @@ -91,6 +93,8 @@ gboolean meta_wayland_buffer_attach (MetaWaylandBuff CoglTexture **texture, GError **error); CoglSnippet * meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer); +void meta_wayland_buffer_inc_use_count (MetaWaylandBuffer *buffer); +void meta_wayland_buffer_dec_use_count (MetaWaylandBuffer *buffer); gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer); void meta_wayland_buffer_process_damage (MetaWaylandBuffer *buffer, CoglTexture *texture, diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c index 95f8186df..8ff51c11d 100644 --- a/src/wayland/meta-wayland-cursor-surface.c +++ b/src/wayland/meta-wayland-cursor-surface.c @@ -136,12 +136,10 @@ meta_wayland_cursor_surface_pre_apply_state (MetaWaylandSurfaceRole *surface_ro META_WAYLAND_CURSOR_SURFACE (surface_role); MetaWaylandCursorSurfacePrivate *priv = meta_wayland_cursor_surface_get_instance_private (cursor_surface); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); if (pending->newly_attached && priv->buffer) { - meta_wayland_surface_unref_buffer_use_count (surface); + meta_wayland_buffer_dec_use_count (priv->buffer); g_clear_object (&priv->buffer); } } @@ -154,15 +152,11 @@ meta_wayland_cursor_surface_apply_state (MetaWaylandSurfaceRole *surface_role, META_WAYLAND_CURSOR_SURFACE (surface_role); MetaWaylandCursorSurfacePrivate *priv = meta_wayland_cursor_surface_get_instance_private (cursor_surface); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); - MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); - if (pending->newly_attached) + if (pending->buffer) { - g_set_object (&priv->buffer, buffer); - if (priv->buffer) - meta_wayland_surface_ref_buffer_use_count (surface); + priv->buffer = g_object_ref (pending->buffer); + meta_wayland_buffer_inc_use_count (priv->buffer); } wl_list_insert_list (&priv->frame_callbacks, @@ -207,8 +201,6 @@ meta_wayland_cursor_surface_dispose (GObject *object) META_WAYLAND_CURSOR_SURFACE (object); MetaWaylandCursorSurfacePrivate *priv = meta_wayland_cursor_surface_get_instance_private (cursor_surface); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object)); MetaWaylandFrameCallback *cb, *next; wl_list_for_each_safe (cb, next, &priv->frame_callbacks, link) @@ -222,7 +214,7 @@ meta_wayland_cursor_surface_dispose (GObject *object) if (priv->buffer) { - meta_wayland_surface_unref_buffer_use_count (surface); + meta_wayland_buffer_dec_use_count (priv->buffer); g_clear_object (&priv->buffer); } @@ -248,8 +240,8 @@ meta_wayland_cursor_surface_constructed (GObject *object) if (buffer && buffer->resource) { - g_set_object (&priv->buffer, buffer); - meta_wayland_surface_ref_buffer_use_count (surface); + priv->buffer = g_object_ref (surface->buffer); + meta_wayland_buffer_inc_use_count (priv->buffer); } priv->cursor_sprite = meta_cursor_sprite_wayland_new (surface); diff --git a/src/wayland/meta-wayland-dma-buf.c b/src/wayland/meta-wayland-dma-buf.c index 645eaf785..f45bf00de 100644 --- a/src/wayland/meta-wayland-dma-buf.c +++ b/src/wayland/meta-wayland-dma-buf.c @@ -461,6 +461,56 @@ static const struct wl_buffer_interface dma_buf_buffer_impl = buffer_destroy, }; +/** + * meta_wayland_dma_buf_fds_for_wayland_buffer: + * @buffer: A #MetaWaylandBuffer object + * + * Creates an associated #MetaWaylandDmaBufBuffer for the wayland buffer, which + * contains just the dma-buf file descriptors. + * + * Returns: The new #MetaWaylandDmaBufBuffer (or + * %NULL if it couldn't be created) + */ +MetaWaylandDmaBufBuffer * +meta_wayland_dma_buf_fds_for_wayland_buffer (MetaWaylandBuffer *buffer) +{ +#ifdef HAVE_NATIVE_BACKEND + MetaBackend *backend = meta_get_backend (); + MetaRenderer *renderer = meta_backend_get_renderer (backend); + MetaRendererNative *renderer_native = META_RENDERER_NATIVE (renderer); + MetaGpuKms *gpu_kms; + struct gbm_device *gbm_device; + struct gbm_bo *gbm_bo; + MetaWaylandDmaBufBuffer *dma_buf; + uint32_t i, n_planes; + + gpu_kms = meta_renderer_native_get_primary_gpu (renderer_native); + if (!gpu_kms) + return NULL; + + gbm_device = meta_gbm_device_from_gpu (gpu_kms); + + gbm_bo = gbm_bo_import (gbm_device, + GBM_BO_IMPORT_WL_BUFFER, buffer->resource, + GBM_BO_USE_RENDERING); + if (!gbm_bo) + return NULL; + + dma_buf = g_object_new (META_TYPE_WAYLAND_DMA_BUF_BUFFER, NULL); + + n_planes = gbm_bo_get_plane_count (gbm_bo); + for (i = 0; i < n_planes; i++) + dma_buf->fds[i] = gbm_bo_get_fd_for_plane (gbm_bo, i); + while (i < META_WAYLAND_DMA_BUF_MAX_FDS) + dma_buf->fds[i++] = -1; + + gbm_bo_destroy (gbm_bo); + return dma_buf; +#else + return NULL; +#endif +} + /** * meta_wayland_dma_buf_from_buffer: * @buffer: A #MetaWaylandBuffer object @@ -482,7 +532,156 @@ meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer) &dma_buf_buffer_impl)) return wl_resource_get_user_data (buffer->resource); - return NULL; + return buffer->dma_buf.dma_buf; +} + +typedef struct _MetaWaylandDmaBufSource +{ + GSource base; + + MetaWaylandDmaBufSourceDispatch dispatch; + MetaWaylandBuffer *buffer; + gpointer user_data; + + gpointer fd_tags[META_WAYLAND_DMA_BUF_MAX_FDS]; +} MetaWaylandDmaBufSource; + +static gboolean +meta_wayland_dma_buf_fd_readable (int fd) +{ + GPollFD poll_fd; + + poll_fd.fd = fd; + poll_fd.events = G_IO_IN; + poll_fd.revents = 0; + + if (!g_poll (&poll_fd, 1, 0)) + return FALSE; + + return (poll_fd.revents & (G_IO_IN | G_IO_NVAL)) != 0; +} + +static gboolean +meta_wayland_dma_buf_source_dispatch (GSource *base, + GSourceFunc callback, + gpointer user_data) + + +{ + MetaWaylandDmaBufSource *source; + MetaWaylandDmaBufBuffer *dma_buf; + gboolean ready; + uint32_t i; + + source = (MetaWaylandDmaBufSource *) base; + dma_buf = source->buffer->dma_buf.dma_buf; + ready = TRUE; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + gpointer fd_tag = source->fd_tags[i]; + + if (!fd_tag) + continue; + + if (!meta_wayland_dma_buf_fd_readable (dma_buf->fds[i])) + { + ready = FALSE; + continue; + } + + g_source_remove_unix_fd (&source->base, fd_tag); + source->fd_tags[i] = NULL; + } + + if (!ready) + return G_SOURCE_CONTINUE; + + source->dispatch (source->buffer, source->user_data); + + return G_SOURCE_REMOVE; +} + +static void +meta_wayland_dma_buf_source_finalize (GSource *base) +{ + MetaWaylandDmaBufSource *source; + uint32_t i; + + source = (MetaWaylandDmaBufSource *) base; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + gpointer fd_tag = source->fd_tags[i]; + + if (fd_tag) + { + g_source_remove_unix_fd (&source->base, fd_tag); + source->fd_tags[i] = NULL; + } + } + + g_clear_object (&source->buffer); +} + +static GSourceFuncs meta_wayland_dma_buf_source_funcs = { + .dispatch = meta_wayland_dma_buf_source_dispatch, + .finalize = meta_wayland_dma_buf_source_finalize +}; + +/** + * meta_wayland_dma_buf_create_source: + * @buffer: A #MetaWaylandBuffer object + * @dispatch: Callback + * @user_data: User data for the callback + * + * Creates a GSource which will call the specified dispatch callback when all + * dma-buf file descriptors for the buffer have become readable. + * + * Returns: The new GSource (or + * %NULL if there are no dma-buf file descriptors, or they were all readable + * already) + */ +GSource * +meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, + MetaWaylandDmaBufSourceDispatch dispatch, + gpointer user_data) +{ + MetaWaylandDmaBufBuffer *dma_buf; + MetaWaylandDmaBufSource *source = NULL; + uint32_t i; + + dma_buf = buffer->dma_buf.dma_buf; + if (!dma_buf) + return NULL; + + for (i = 0; i < META_WAYLAND_DMA_BUF_MAX_FDS; i++) + { + int fd = dma_buf->fds[i]; + + if (fd < 0) + break; + + if (meta_wayland_dma_buf_fd_readable (fd)) + continue; + + if (!source) + { + source = + (MetaWaylandDmaBufSource *) g_source_new (&meta_wayland_dma_buf_source_funcs, + sizeof (*source)); + source->buffer = g_object_ref (buffer); + source->dispatch = dispatch; + source->user_data = user_data; + } + + source->fd_tags[i] = g_source_add_unix_fd (&source->base, fd, G_IO_IN); + } + + if (!source) + return NULL; + + return &source->base; } static void diff --git a/src/wayland/meta-wayland-dma-buf.h b/src/wayland/meta-wayland-dma-buf.h index 73b60d929..e060d4e12 100644 --- a/src/wayland/meta-wayland-dma-buf.h +++ b/src/wayland/meta-wayland-dma-buf.h @@ -52,9 +52,20 @@ meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer, CoglTexture **texture, GError **error); +MetaWaylandDmaBufBuffer * +meta_wayland_dma_buf_fds_for_wayland_buffer (MetaWaylandBuffer *buffer); + MetaWaylandDmaBufBuffer * meta_wayland_dma_buf_from_buffer (MetaWaylandBuffer *buffer); +typedef void (*MetaWaylandDmaBufSourceDispatch) (MetaWaylandBuffer *buffer, + gpointer user_data); + +GSource * +meta_wayland_dma_buf_create_source (MetaWaylandBuffer *buffer, + MetaWaylandDmaBufSourceDispatch dispatch, + gpointer user_data); + CoglScanout * meta_wayland_dma_buf_try_acquire_scanout (MetaWaylandDmaBufBuffer *dma_buf, CoglOnscreen *onscreen); diff --git a/src/wayland/meta-wayland-layer-shell.c b/src/wayland/meta-wayland-layer-shell.c index fb1e5494c..0fe327baf 100644 --- a/src/wayland/meta-wayland-layer-shell.c +++ b/src/wayland/meta-wayland-layer-shell.c @@ -630,7 +630,7 @@ calculate_surface_position (MetaWaylandLayerSurface *layer_surface, * fallback matters when a popup is parented to a layer surface whose first * buffer hasn't been drawn — without it we'd treat the surface as 0x0 * and place the popup at the bounds origin. */ - if (surface->buffer_ref->buffer) + if (surface->buffer) { width = meta_wayland_surface_get_width (surface); height = meta_wayland_surface_get_height (surface); @@ -703,7 +703,7 @@ meta_wayland_layer_surface_get_geometry (MetaWaylandLayerSurface *layer_surface, if (!surface) return FALSE; - if (surface->buffer_ref->buffer) + if (surface->buffer) { *out_width = meta_wayland_surface_get_width (surface); *out_height = meta_wayland_surface_get_height (surface); @@ -763,7 +763,7 @@ meta_wayland_layer_surface_apply_state (MetaWaylandSurfaceRole *surface_role, int x, y; had_buffer = layer_surface->mapped; - has_buffer = surface->buffer_ref->buffer != NULL; + has_buffer = surface->buffer != NULL; /* Save old state for strut change detection */ old_state = layer_surface->current; @@ -1175,7 +1175,7 @@ layer_shell_get_layer_surface (struct wl_client *client, } /* Check if surface already has a buffer */ - if (surface->buffer_ref->buffer) + if (surface->buffer) { wl_resource_post_error (resource, ZWLR_LAYER_SHELL_V1_ERROR_ALREADY_CONSTRUCTED, diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 28f1dbe82..628d3be3a 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -1292,7 +1292,8 @@ pointer_can_grab_surface (MetaWaylandPointer *pointer, if (pointer->focus_surface == surface) return TRUE; - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface) { if (pointer_can_grab_surface (pointer, subsurface)) return TRUE; diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h index a38ff1f47..41bd71762 100644 --- a/src/wayland/meta-wayland-private.h +++ b/src/wayland/meta-wayland-private.h @@ -90,6 +90,12 @@ struct _MetaWaylandCompositor MetaWaylandXdgForeign *foreign; MetaWaylandDmaBufManager *dma_buf_manager; + /* + * Queue of transactions which have been committed but not applied yet, in the + * order they were committed. + */ + GQueue committed_transactions; + GHashTable *scheduled_surface_associations; }; diff --git a/src/wayland/meta-wayland-shell-surface.c b/src/wayland/meta-wayland-shell-surface.c index 6bfeee332..7c6bcdf35 100644 --- a/src/wayland/meta-wayland-shell-surface.c +++ b/src/wayland/meta-wayland-shell-surface.c @@ -61,7 +61,8 @@ meta_wayland_shell_surface_calculate_geometry (MetaWaylandShellSurface *shell_su .height = meta_wayland_surface_get_height (surface), }; - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface_surface) { MetaWaylandSubsurface *subsurface; @@ -246,7 +247,7 @@ meta_wayland_shell_surface_surface_pre_apply_state (MetaWaylandSurfaceRole *sur /* Queue calc_showing when buffer is detached (unmap) */ if (pending->newly_attached && - !surface->buffer_ref->buffer && + !surface->buffer && priv->window) meta_window_queue (priv->window, META_QUEUE_CALC_SHOWING); } @@ -272,7 +273,7 @@ meta_wayland_shell_surface_surface_apply_state (MetaWaylandSurfaceRole *surface META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_shell_surface_parent_class); surface_role_class->apply_state (surface_role, pending); - buffer = surface->buffer_ref->buffer; + buffer = surface->buffer; if (!buffer) return; diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c index b2343ffff..4733e62c7 100644 --- a/src/wayland/meta-wayland-subsurface.c +++ b/src/wayland/meta-wayland-subsurface.c @@ -28,6 +28,7 @@ #include "wayland/meta-wayland-actor-surface.h" #include "wayland/meta-wayland-buffer.h" #include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-window-wayland.h" struct _MetaWaylandSubsurface @@ -49,7 +50,7 @@ transform_subsurface_position (MetaWaylandSurface *surface, *x += surface->sub.x; *y += surface->sub.y; - surface = surface->sub.parent; + surface = surface->output_state.parent; } while (surface); } @@ -74,7 +75,7 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface) clutter_actor_set_position (actor, x, y); clutter_actor_set_reactive (actor, TRUE); - if (surface->buffer_ref->buffer) + if (surface->buffer) clutter_actor_show (actor); else clutter_actor_hide (actor); @@ -84,48 +85,15 @@ static gboolean is_child (MetaWaylandSurface *surface, MetaWaylandSurface *sibling) { - if (surface->sub.parent == sibling) - return TRUE; - else - return FALSE; + return surface->protocol_state.parent == sibling; } static gboolean is_sibling (MetaWaylandSurface *surface, MetaWaylandSurface *sibling) { - if (surface->sub.parent == sibling->sub.parent) - return TRUE; - else - return FALSE; -} - -static gboolean -is_surface_effectively_synchronized (MetaWaylandSurface *surface) -{ - return meta_wayland_surface_should_cache_state (surface); -} - -void -meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface) -{ - MetaWaylandSurfaceRole *surface_role = META_WAYLAND_SURFACE_ROLE (subsurface); - MetaWaylandActorSurface *actor_surface = - META_WAYLAND_ACTOR_SURFACE (subsurface); - MetaWaylandSurface *surface = - meta_wayland_surface_role_get_surface (surface_role); - - if (surface->sub.pending_pos) - { - surface->sub.x = surface->sub.pending_x; - surface->sub.y = surface->sub.pending_y; - surface->sub.pending_pos = FALSE; - } - - if (is_surface_effectively_synchronized (surface)) - meta_wayland_surface_apply_cached_state (surface); - - meta_wayland_actor_surface_sync_actor_state (actor_surface); + return surface != sibling && + surface->protocol_state.parent == sibling->protocol_state.parent; } void @@ -147,10 +115,11 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface, .height = meta_wayland_surface_get_height (surface), }; - if (surface->buffer_ref->buffer) + if (surface->buffer) meta_rectangle_union (out_geometry, &geometry, out_geometry); - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface_surface) { MetaWaylandSubsurface *subsurface; @@ -180,7 +149,7 @@ meta_wayland_subsurface_get_toplevel (MetaWaylandSurfaceRole *surface_role) { MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - MetaWaylandSurface *parent = surface->sub.parent; + MetaWaylandSurface *parent = surface->output_state.parent; if (parent) return meta_wayland_surface_get_toplevel (parent); @@ -189,7 +158,7 @@ meta_wayland_subsurface_get_toplevel (MetaWaylandSurfaceRole *surface_role) } static gboolean -meta_wayland_subsurface_should_cache_state (MetaWaylandSurfaceRole *surface_role) +meta_wayland_subsurface_is_synchronized (MetaWaylandSurfaceRole *surface_role) { MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); @@ -198,9 +167,9 @@ meta_wayland_subsurface_should_cache_state (MetaWaylandSurfaceRole *surface_role if (surface->sub.synchronous) return TRUE; - parent = surface->sub.parent; + parent = surface->protocol_state.parent; if (parent) - return meta_wayland_surface_should_cache_state (parent); + return meta_wayland_surface_is_synchronized (parent); return TRUE; } @@ -210,7 +179,7 @@ meta_wayland_subsurface_notify_subsurface_state_changed (MetaWaylandSurfaceRole { MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - MetaWaylandSurface *parent = surface->sub.parent; + MetaWaylandSurface *parent = surface->output_state.parent; if (parent) return meta_wayland_surface_notify_subsurface_state_changed (parent); @@ -223,13 +192,14 @@ meta_wayland_subsurface_get_geometry_scale (MetaWaylandActorSurface *actor_surfa META_WAYLAND_SURFACE_ROLE (actor_surface); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - MetaWaylandSurface *parent = surface->sub.parent; + MetaWaylandSurface *parent = surface->output_state.parent; if (parent) { MetaWaylandActorSurface *parent_actor; - parent_actor = META_WAYLAND_ACTOR_SURFACE (surface->sub.parent->role); + parent_actor = + META_WAYLAND_ACTOR_SURFACE (surface->output_state.parent->role); return meta_wayland_actor_surface_get_geometry_scale (parent_actor); } else @@ -271,7 +241,7 @@ meta_wayland_subsurface_class_init (MetaWaylandSubsurfaceClass *klass) surface_role_class->assigned = meta_wayland_subsurface_assigned; surface_role_class->get_toplevel = meta_wayland_subsurface_get_toplevel; - surface_role_class->should_cache_state = meta_wayland_subsurface_should_cache_state; + surface_role_class->is_synchronized = meta_wayland_subsurface_is_synchronized; surface_role_class->notify_subsurface_state_changed = meta_wayland_subsurface_notify_subsurface_state_changed; @@ -296,23 +266,6 @@ unparent_actor (MetaWaylandSurface *surface) clutter_actor_remove_child (parent_actor, actor); } -static void -wl_subsurface_destructor (struct wl_resource *resource) -{ - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - - g_node_unlink (surface->subsurface_branch_node); - unparent_actor (surface); - - if (surface->sub.parent) - { - wl_list_remove (&surface->sub.parent_destroy_listener.link); - surface->sub.parent = NULL; - } - - surface->wl_subsurface = NULL; -} - static void wl_subsurface_destroy (struct wl_client *client, struct wl_resource *resource) @@ -327,10 +280,10 @@ wl_subsurface_set_position (struct wl_client *client, int32_t y) { MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandTransaction *transaction; - surface->sub.pending_x = x; - surface->sub.pending_y = y; - surface->sub.pending_pos = TRUE; + transaction = meta_wayland_surface_ensure_transaction (surface); + meta_wayland_transaction_add_subsurface_position (transaction, surface, x, y); } static gboolean @@ -344,59 +297,57 @@ is_valid_sibling (MetaWaylandSurface *surface, return FALSE; } -static void -subsurface_handle_pending_subsurface_destroyed (struct wl_listener *listener, - void *data) -{ - MetaWaylandSubsurfacePlacementOp *op = - wl_container_of (listener, op, subsurface_destroy_listener); - - op->surface = NULL; -} - -static void -subsurface_handle_pending_sibling_destroyed (struct wl_listener *listener, - void *data) -{ - MetaWaylandSubsurfacePlacementOp *op = - wl_container_of (listener, op, sibling_destroy_listener); - - op->sibling = NULL; -} - -void -meta_wayland_subsurface_placement_op_free (MetaWaylandSubsurfacePlacementOp *op) -{ - if (op->surface) - wl_list_remove (&op->subsurface_destroy_listener.link); - if (op->sibling) - wl_list_remove (&op->sibling_destroy_listener.link); - g_free (op); -} - static void queue_subsurface_placement (MetaWaylandSurface *surface, MetaWaylandSurface *sibling, MetaWaylandSubsurfacePlacement placement) { - MetaWaylandSurface *parent = surface->sub.parent; + MetaWaylandSurface *parent = surface->protocol_state.parent; + gboolean have_synced_parent; + MetaWaylandTransaction *transaction; MetaWaylandSubsurfacePlacementOp *op = g_new0 (MetaWaylandSubsurfacePlacementOp, 1); + GNode *sibling_node; + + have_synced_parent = sibling && meta_wayland_surface_is_synchronized (parent); + if (have_synced_parent) + transaction = meta_wayland_surface_ensure_transaction (parent); + else + transaction = meta_wayland_transaction_new (surface->compositor); op->placement = placement; - op->surface = surface; op->sibling = sibling; - op->subsurface_destroy_listener.notify = - subsurface_handle_pending_subsurface_destroyed; - op->sibling_destroy_listener.notify = - subsurface_handle_pending_sibling_destroyed; - wl_resource_add_destroy_listener (surface->wl_subsurface, - &op->subsurface_destroy_listener); - wl_resource_add_destroy_listener (sibling->resource, - &op->sibling_destroy_listener); - - parent->pending_state->subsurface_placement_ops = - g_slist_append (parent->pending_state->subsurface_placement_ops, op); + op->surface = surface; + + g_node_unlink (surface->protocol_state.subsurface_branch_node); + + if (!sibling) + goto out; + + if (sibling == parent) + sibling_node = parent->protocol_state.subsurface_leaf_node; + else + sibling_node = sibling->protocol_state.subsurface_branch_node; + + switch (placement) + { + case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE: + g_node_insert_after (parent->protocol_state.subsurface_branch_node, + sibling_node, + surface->protocol_state.subsurface_branch_node); + break; + case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW: + g_node_insert_before (parent->protocol_state.subsurface_branch_node, + sibling_node, + surface->protocol_state.subsurface_branch_node); + break; + } + + out: + meta_wayland_transaction_add_placement_op (transaction, parent, op); + + if (!have_synced_parent) + meta_wayland_transaction_commit (transaction); } static void @@ -443,6 +394,25 @@ wl_subsurface_place_below (struct wl_client *client, META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW); } +static void +wl_subsurface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + + if (surface->protocol_state.parent) + { + queue_subsurface_placement (surface, NULL, + META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW); + surface->protocol_state.parent = NULL; + } + else + { + g_node_unlink (surface->protocol_state.subsurface_branch_node); + } + + surface->wl_subsurface = NULL; +} + static void wl_subsurface_set_sync (struct wl_client *client, struct wl_resource *resource) @@ -452,19 +422,33 @@ wl_subsurface_set_sync (struct wl_client *client, surface->sub.synchronous = TRUE; } +static void +meta_wayland_subsurface_parent_desynced (MetaWaylandSurface *surface) +{ + MetaWaylandSurface *subsurface_surface; + + if (surface->sub.synchronous) + return; + + if (surface->sub.transaction) + meta_wayland_transaction_commit (g_steal_pointer (&surface->sub.transaction)); + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->protocol_state, + subsurface_surface) + meta_wayland_subsurface_parent_desynced (subsurface_surface); +} + static void wl_subsurface_set_desync (struct wl_client *client, struct wl_resource *resource) { MetaWaylandSurface *surface = wl_resource_get_user_data (resource); - gboolean was_effectively_synchronized; - was_effectively_synchronized = is_surface_effectively_synchronized (surface); surface->sub.synchronous = FALSE; - if (was_effectively_synchronized && - !is_surface_effectively_synchronized (surface)) - meta_wayland_surface_apply_cached_state (surface); + if (!meta_wayland_surface_is_synchronized (surface)) + meta_wayland_subsurface_parent_desynced (surface); + } static const struct wl_subsurface_interface meta_wayland_wl_subsurface_interface = { @@ -483,16 +467,12 @@ wl_subcompositor_destroy (struct wl_client *client, wl_resource_destroy (resource); } -static void -surface_handle_parent_surface_destroyed (struct wl_listener *listener, - void *data) +void +meta_wayland_subsurface_parent_destroyed (MetaWaylandSurface *surface) { - MetaWaylandSurface *surface = wl_container_of (listener, - surface, - sub.parent_destroy_listener); - - g_node_unlink (surface->subsurface_branch_node); - surface->sub.parent = NULL; + queue_subsurface_placement (surface, NULL, + META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW); + surface->protocol_state.parent = NULL; } static gboolean @@ -501,8 +481,8 @@ is_same_or_ancestor (MetaWaylandSurface *surface, { if (surface == other_surface) return TRUE; - if (other_surface->sub.parent) - return is_same_or_ancestor (surface, other_surface->sub.parent); + if (other_surface->protocol_state.parent) + return is_same_or_ancestor (surface, other_surface->protocol_state.parent); return FALSE; } @@ -515,6 +495,7 @@ wl_subcompositor_get_subsurface (struct wl_client *client, { MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource); + MetaWaylandSurface *reference; MetaWindow *toplevel_window; if (surface->wl_subsurface) @@ -561,16 +542,12 @@ wl_subcompositor_get_subsurface (struct wl_client *client, wl_subsurface_destructor); surface->sub.synchronous = TRUE; - surface->sub.parent = parent; - surface->sub.parent_destroy_listener.notify = - surface_handle_parent_surface_destroyed; - wl_resource_add_destroy_listener (parent->resource, - &surface->sub.parent_destroy_listener); + surface->protocol_state.parent = parent; - g_node_append (parent->subsurface_branch_node, - surface->subsurface_branch_node); - - meta_wayland_surface_notify_subsurface_state_changed (parent); + reference = + g_node_last_child (parent->protocol_state.subsurface_branch_node)->data; + queue_subsurface_placement (surface, reference, + META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE); } static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = { diff --git a/src/wayland/meta-wayland-subsurface.h b/src/wayland/meta-wayland-subsurface.h index 45dbf8626..61338e921 100644 --- a/src/wayland/meta-wayland-subsurface.h +++ b/src/wayland/meta-wayland-subsurface.h @@ -40,18 +40,14 @@ typedef struct MetaWaylandSubsurfacePlacement placement; MetaWaylandSurface *surface; MetaWaylandSurface *sibling; - struct wl_listener subsurface_destroy_listener; - struct wl_listener sibling_destroy_listener; } MetaWaylandSubsurfacePlacementOp; -void meta_wayland_subsurface_parent_state_applied (MetaWaylandSubsurface *subsurface); - void meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface, int parent_x, int parent_y, MetaRectangle *out_geometry); -void meta_wayland_subsurface_placement_op_free (MetaWaylandSubsurfacePlacementOp *op); +void meta_wayland_subsurface_parent_destroyed (MetaWaylandSurface *surface); void meta_wayland_subsurfaces_init (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 1cb39fb00..0cb954e59 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -50,6 +50,7 @@ #include "wayland/meta-wayland-region.h" #include "wayland/meta-wayland-seat.h" #include "wayland/meta-wayland-subsurface.h" +#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-wayland-viewporter.h" #include "wayland/meta-wayland-xapp-shell.h" #include "wayland/meta-wayland-xdg-shell.h" @@ -106,6 +107,11 @@ guint surface_signals[N_SURFACE_SIGNALS] = { 0 }; static void meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role); +static void +meta_wayland_surface_role_commit_state (MetaWaylandSurfaceRole *surface_role, + MetaWaylandTransaction *transaction, + MetaWaylandSurfaceState *pending); + static void meta_wayland_surface_role_pre_apply_state (MetaWaylandSurfaceRole *surface_role, MetaWaylandSurfaceState *pending); @@ -125,58 +131,6 @@ meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface static MetaWaylandSurface * meta_wayland_surface_role_get_toplevel (MetaWaylandSurfaceRole *surface_role); -static MetaWaylandBufferRef * -meta_wayland_buffer_ref_new (void) -{ - MetaWaylandBufferRef *buffer_ref; - - buffer_ref = g_new0 (MetaWaylandBufferRef, 1); - g_ref_count_init (&buffer_ref->ref_count); - - return buffer_ref; -} - -static MetaWaylandBufferRef * -meta_wayland_buffer_ref_ref (MetaWaylandBufferRef *buffer_ref) -{ - g_ref_count_inc (&buffer_ref->ref_count); - return buffer_ref; -} - -static void -meta_wayland_buffer_ref_unref (MetaWaylandBufferRef *buffer_ref) -{ - if (g_ref_count_dec (&buffer_ref->ref_count)) - { - g_warn_if_fail (buffer_ref->use_count == 0); - g_clear_object (&buffer_ref->buffer); - g_free (buffer_ref); - } -} - -static void -meta_wayland_buffer_ref_inc_use_count (MetaWaylandBufferRef *buffer_ref) -{ - g_return_if_fail (buffer_ref->buffer); - g_warn_if_fail (buffer_ref->buffer->resource); - - buffer_ref->use_count++; -} - -static void -meta_wayland_buffer_ref_dec_use_count (MetaWaylandBufferRef *buffer_ref) -{ - MetaWaylandBuffer *buffer = buffer_ref->buffer; - - g_return_if_fail (buffer_ref->use_count > 0); - g_return_if_fail (buffer); - - buffer_ref->use_count--; - - if (buffer_ref->use_count == 0 && buffer->resource) - wl_buffer_send_release (buffer->resource); -} - static void role_assignment_valist_to_properties (GType role_type, const char *first_property_name, @@ -269,7 +223,7 @@ meta_wayland_surface_assign_role (MetaWaylandSurface *surface, /* Release the use count held on behalf of the just assigned role. */ if (surface->unassigned.buffer) { - meta_wayland_surface_unref_buffer_use_count (surface); + meta_wayland_buffer_dec_use_count (surface->unassigned.buffer); g_clear_object (&surface->unassigned.buffer); } @@ -298,7 +252,7 @@ get_buffer_width (MetaWaylandSurface *surface) MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); if (buffer) - return cogl_texture_get_width (surface->texture); + return cogl_texture_get_width (surface->output_state.texture); else return 0; } @@ -309,7 +263,7 @@ get_buffer_height (MetaWaylandSurface *surface) MetaWaylandBuffer *buffer = meta_wayland_surface_get_buffer (surface); if (buffer) - return cogl_texture_get_height (surface->texture); + return cogl_texture_get_height (surface->output_state.texture); else return 0; } @@ -401,7 +355,8 @@ surface_process_damage (MetaWaylandSurface *surface, cairo_region_intersect_rectangle (buffer_region, &buffer_rect); - meta_wayland_buffer_process_damage (buffer, surface->texture, buffer_region); + meta_wayland_buffer_process_damage (buffer, surface->output_state.texture, + buffer_region); actor = meta_wayland_surface_get_actor (surface); if (actor) @@ -428,19 +383,7 @@ surface_process_damage (MetaWaylandSurface *surface, MetaWaylandBuffer * meta_wayland_surface_get_buffer (MetaWaylandSurface *surface) { - return surface->buffer_ref->buffer; -} - -void -meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface) -{ - meta_wayland_buffer_ref_inc_use_count (surface->buffer_ref); -} - -void -meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface) -{ - meta_wayland_buffer_ref_dec_use_count (surface->buffer_ref); + return surface->buffer; } static void @@ -456,6 +399,7 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state) { state->newly_attached = FALSE; state->buffer = NULL; + state->texture = NULL; state->buffer_destroy_handler_id = 0; state->dx = 0; state->dy = 0; @@ -480,6 +424,8 @@ meta_wayland_surface_state_set_default (MetaWaylandSurfaceState *state) state->has_new_viewport_dst_size = FALSE; state->subsurface_placement_ops = NULL; + + state->xdg_popup_reposition_token = 0; } static void @@ -487,46 +433,59 @@ meta_wayland_surface_state_clear (MetaWaylandSurfaceState *state) { MetaWaylandFrameCallback *cb, *next; + cogl_clear_object (&state->texture); + g_clear_pointer (&state->surface_damage, cairo_region_destroy); g_clear_pointer (&state->buffer_damage, cairo_region_destroy); g_clear_pointer (&state->input_region, cairo_region_destroy); g_clear_pointer (&state->opaque_region, cairo_region_destroy); + g_clear_pointer (&state->xdg_positioner, g_free); - if (state->buffer) - g_clear_signal_handler (&state->buffer_destroy_handler_id, state->buffer); + if (state->buffer_destroy_handler_id) + { + g_clear_signal_handler (&state->buffer_destroy_handler_id, state->buffer); + state->buffer = NULL; + } + else + { + g_clear_object (&state->buffer); + } wl_list_for_each_safe (cb, next, &state->frame_callback_list, link) wl_resource_destroy (cb->resource); if (state->subsurface_placement_ops) - { - g_slist_free_full ( - state->subsurface_placement_ops, - (GDestroyNotify) meta_wayland_subsurface_placement_op_free); - } + g_slist_free_full (state->subsurface_placement_ops, g_free); } -static void +void meta_wayland_surface_state_reset (MetaWaylandSurfaceState *state) { meta_wayland_surface_state_clear (state); meta_wayland_surface_state_set_default (state); } -static void +void meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from, MetaWaylandSurfaceState *to) { if (from->newly_attached) { if (to->buffer) - g_clear_signal_handler (&to->buffer_destroy_handler_id, to->buffer); + { + g_warn_if_fail (to->buffer_destroy_handler_id == 0); + meta_wayland_buffer_dec_use_count (to->buffer); + g_object_unref (to->buffer); + } if (from->buffer) g_clear_signal_handler (&from->buffer_destroy_handler_id, from->buffer); to->newly_attached = TRUE; - to->buffer = from->buffer; + to->buffer = g_steal_pointer (&from->buffer); + + cogl_clear_object (&to->texture); + to->texture = g_steal_pointer (&from->texture); } to->dx = from->dx; @@ -612,14 +571,6 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from, to->has_new_viewport_dst_size = TRUE; } - if (to->buffer && to->buffer_destroy_handler_id == 0) - { - to->buffer_destroy_handler_id = - g_signal_connect (to->buffer, "resource-destroyed", - G_CALLBACK (pending_buffer_resource_destroyed), - to); - } - if (from->subsurface_placement_ops != NULL) { if (to->subsurface_placement_ops != NULL) @@ -636,7 +587,12 @@ meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from, from->subsurface_placement_ops = NULL; } - meta_wayland_surface_state_set_default (from); + if (from->xdg_positioner) + { + g_clear_pointer (&to->xdg_positioner, g_free); + to->xdg_positioner = g_steal_pointer (&from->xdg_positioner); + to->xdg_popup_reposition_token = from->xdg_popup_reposition_token; + } } static void @@ -671,11 +627,54 @@ meta_wayland_surface_state_class_init (MetaWaylandSurfaceStateClass *klass) G_TYPE_NONE, 0); } -static void + +void +meta_wayland_surface_apply_placement_ops (MetaWaylandSurface *parent, + MetaWaylandSurfaceState *state) +{ + GSList *l; + + for (l = state->subsurface_placement_ops; l; l = l->next) + { + MetaWaylandSubsurfacePlacementOp *op = l->data; + MetaWaylandSurface *surface = op->surface; + GNode *sibling_node; + + g_node_unlink (surface->output_state.subsurface_branch_node); + + if (!op->sibling) + { + surface->output_state.parent = NULL; + continue; + } + + surface->output_state.parent = parent; + + if (op->sibling == parent) + sibling_node = parent->output_state.subsurface_leaf_node; + else + sibling_node = op->sibling->output_state.subsurface_branch_node; + + switch (op->placement) + { + case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE: + g_node_insert_after (parent->output_state.subsurface_branch_node, + sibling_node, + surface->output_state.subsurface_branch_node); + break; + case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW: + g_node_insert_before (parent->output_state.subsurface_branch_node, + sibling_node, + surface->output_state.subsurface_branch_node); + break; + } + } +} + +void meta_wayland_surface_apply_state (MetaWaylandSurface *surface, MetaWaylandSurfaceState *state) { - MetaWaylandSurface *subsurface_surface; gboolean had_damage = FALSE; g_signal_emit (surface, surface_signals[SURFACE_PRE_STATE_APPLIED], 0); @@ -688,7 +687,7 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, { if (state->newly_attached && surface->unassigned.buffer) { - meta_wayland_surface_unref_buffer_use_count (surface); + meta_wayland_buffer_dec_use_count (surface->unassigned.buffer); g_clear_object (&surface->unassigned.buffer); } } @@ -701,40 +700,11 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, * is symmetric. */ if (surface->buffer_held) - meta_wayland_surface_unref_buffer_use_count (surface); - - if (surface->buffer_ref->use_count > 0) - { - meta_wayland_buffer_ref_unref (surface->buffer_ref); - surface->buffer_ref = meta_wayland_buffer_ref_new (); - } - - g_set_object (&surface->buffer_ref->buffer, state->buffer); - - if (state->buffer) - meta_wayland_surface_ref_buffer_use_count (surface); + meta_wayland_buffer_dec_use_count (surface->buffer); - if (state->buffer) - { - GError *error = NULL; - - if (!meta_wayland_buffer_attach (state->buffer, - &surface->texture, - &error)) - { - g_warning ("Could not import pending buffer: %s", error->message); - wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_NO_MEMORY, - "Failed to attach buffer to surface %i: %s", - wl_resource_get_id (surface->resource), - error->message); - g_error_free (error); - goto cleanup; - } - } - else - { - cogl_clear_object (&surface->texture); - } + g_set_object (&surface->buffer, state->buffer); + cogl_clear_object (&surface->output_state.texture); + surface->output_state.texture = g_steal_pointer (&state->texture); /* If the newly attached buffer is going to be accessed directly without * making a copy, such as an EGL buffer, mark it as in-use don't release @@ -812,76 +782,32 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, &state->frame_callback_list); wl_list_init (&state->frame_callback_list); - if (state->newly_attached) + if (state->buffer) { /* The need to keep the wl_buffer from being released depends on what * role the surface is given. That means we need to also keep a use * count for wl_buffer's that are used by unassigned wl_surface's. */ - g_set_object (&surface->unassigned.buffer, - surface->buffer_ref->buffer); - if (surface->unassigned.buffer) - meta_wayland_surface_ref_buffer_use_count (surface); + surface->unassigned.buffer = g_object_ref (state->buffer); + meta_wayland_buffer_inc_use_count (surface->unassigned.buffer); } } if (state->subsurface_placement_ops) - { - GSList *l; - - for (l = state->subsurface_placement_ops; l; l = l->next) - { - MetaWaylandSubsurfacePlacementOp *op = l->data; - GNode *sibling_node; - - if (!op->surface || !op->sibling) - continue; + meta_wayland_surface_notify_subsurface_state_changed (surface); - if (op->sibling == surface) - sibling_node = surface->subsurface_leaf_node; - else - sibling_node = op->sibling->subsurface_branch_node; - - g_node_unlink (op->surface->subsurface_branch_node); - - switch (op->placement) - { - case META_WAYLAND_SUBSURFACE_PLACEMENT_ABOVE: - g_node_insert_after (surface->subsurface_branch_node, - sibling_node, - op->surface->subsurface_branch_node); - break; - case META_WAYLAND_SUBSURFACE_PLACEMENT_BELOW: - g_node_insert_before (surface->subsurface_branch_node, - sibling_node, - op->surface->subsurface_branch_node); - break; - } - } - - meta_wayland_surface_notify_subsurface_state_changed (surface); - } - -cleanup: - /* If we have a buffer that we are not using, decrease the use count so it may - * be released if no-one else has a use-reference to it. + /* If we need to hold the newly attached buffer, drop its reference from the + * state, to prevent meta_wayland_transaction_entry_destroy from decreasing + * the use count. + * */ - if (state->newly_attached && - !surface->buffer_held && surface->buffer_ref->buffer) - meta_wayland_surface_unref_buffer_use_count (surface); + if (state->newly_attached && surface->buffer_held) + g_clear_object (&state->buffer); g_signal_emit (state, surface_state_signals[SURFACE_STATE_SIGNAL_APPLIED], 0); - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) - { - MetaWaylandSubsurface *subsurface; - - subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role); - meta_wayland_subsurface_parent_state_applied (subsurface); - } - if (had_damage) { MetaWindow *toplevel_window; @@ -900,17 +826,6 @@ meta_wayland_surface_apply_state (MetaWaylandSurface *surface, if (surface->role) meta_wayland_surface_role_post_apply_state (surface->role, state); - - meta_wayland_surface_state_reset (state); -} - -void -meta_wayland_surface_apply_cached_state (MetaWaylandSurface *surface) -{ - if (!surface->cached_state) - return; - - meta_wayland_surface_apply_state (surface, surface->cached_state); } MetaWaylandSurfaceState * @@ -919,26 +834,79 @@ meta_wayland_surface_get_pending_state (MetaWaylandSurface *surface) return surface->pending_state; } -MetaWaylandSurfaceState * -meta_wayland_surface_ensure_cached_state (MetaWaylandSurface *surface) +MetaWaylandTransaction * +meta_wayland_surface_ensure_transaction (MetaWaylandSurface *surface) { - if (!surface->cached_state) - surface->cached_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, - NULL); - return surface->cached_state; + if (!surface->sub.transaction) + surface->sub.transaction = meta_wayland_transaction_new (surface->compositor); + + return surface->sub.transaction; } static void meta_wayland_surface_commit (MetaWaylandSurface *surface) { MetaWaylandSurfaceState *pending = surface->pending_state; + MetaWaylandBuffer *buffer = pending->buffer; + MetaWaylandTransaction *transaction; + MetaWaylandSurface *subsurface_surface; COGL_TRACE_BEGIN_SCOPED (MetaWaylandSurfaceCommit, "WaylandSurface (commit)"); - if (pending->buffer && - !meta_wayland_buffer_is_realized (pending->buffer)) - meta_wayland_buffer_realize (pending->buffer); + if (buffer) + { + g_autoptr (GError) error = NULL; + + g_clear_signal_handler (&pending->buffer_destroy_handler_id, + buffer); + + if (!meta_wayland_buffer_is_realized (buffer)) + meta_wayland_buffer_realize (buffer); + + if (!meta_wayland_buffer_attach (buffer, + &surface->protocol_state.texture, + &error)) + { + g_warning ("Could not import pending buffer: %s", error->message); + + wl_resource_post_error (surface->resource, WL_DISPLAY_ERROR_NO_MEMORY, + "Failed to attach buffer to surface %i: %s", + wl_resource_get_id (surface->resource), + error->message); + return; + } + + pending->texture = cogl_object_ref (surface->protocol_state.texture); + + g_object_ref (buffer); + meta_wayland_buffer_inc_use_count (buffer); + } + else if (pending->newly_attached) + { + cogl_clear_object (&surface->protocol_state.texture); + } + + if (meta_wayland_surface_is_synchronized (surface)) + transaction = meta_wayland_surface_ensure_transaction (surface); + else + transaction = meta_wayland_transaction_new (surface->compositor); + + if (surface->role) + meta_wayland_surface_role_commit_state (surface->role, transaction, pending); + + meta_wayland_transaction_merge_pending_state (transaction, surface); + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->protocol_state, + subsurface_surface) + { + if (!subsurface_surface->sub.transaction) + continue; + + meta_wayland_transaction_merge_into (subsurface_surface->sub.transaction, + transaction); + subsurface_surface->sub.transaction = NULL; + } /* * If this is a sub-surface and it is in effective synchronous mode, only @@ -948,17 +916,8 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface) * 2) Its mode changes from synchronized to desynchronized and its parent * surface is in effective desynchronized mode. */ - if (meta_wayland_surface_should_cache_state (surface)) - { - MetaWaylandSurfaceState *cached_state; - - cached_state = meta_wayland_surface_ensure_cached_state (surface); - meta_wayland_surface_state_merge_into (pending, cached_state); - } - else - { - meta_wayland_surface_apply_state (surface, surface->pending_state); - } + if (!meta_wayland_surface_is_synchronized (surface)) + meta_wayland_transaction_commit (transaction); } static void @@ -1264,18 +1223,21 @@ static void surface_entered_output (MetaWaylandSurface *surface, MetaWaylandOutput *wayland_output) { - GList *iter; struct wl_resource *resource; - for (iter = wayland_output->resources; iter != NULL; iter = iter->next) + if (surface->resource) { - resource = iter->data; + GList *iter; + for (iter = wayland_output->resources; iter != NULL; iter = iter->next) + { + resource = iter->data; - if (wl_resource_get_client (resource) != - wl_resource_get_client (surface->resource)) - continue; + if (wl_resource_get_client (resource) != + wl_resource_get_client (surface->resource)) + continue; - wl_surface_send_enter (surface->resource, resource); + wl_surface_send_enter (surface->resource, resource); + } } } @@ -1286,6 +1248,9 @@ surface_left_output (MetaWaylandSurface *surface, GList *iter; struct wl_resource *resource; + if (!surface->resource) + return; + for (iter = wayland_output->resources; iter != NULL; iter = iter->next) { resource = iter->data; @@ -1387,7 +1352,7 @@ meta_wayland_surface_update_outputs_recursively (MetaWaylandSurface *surface) meta_wayland_surface_update_outputs (surface); - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, subsurface_surface) meta_wayland_surface_update_outputs_recursively (subsurface_surface); } @@ -1398,29 +1363,24 @@ meta_wayland_surface_notify_unmapped (MetaWaylandSurface *surface) } static void -wl_surface_destructor (struct wl_resource *resource) +meta_wayland_surface_finalize (GObject *object) { - MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *surface = META_WAYLAND_SURFACE (object); MetaWaylandCompositor *compositor = surface->compositor; MetaWaylandFrameCallback *cb, *next; - g_signal_emit (surface, surface_signals[SURFACE_DESTROY], 0); - g_clear_object (&surface->role); if (surface->unassigned.buffer) { - meta_wayland_surface_unref_buffer_use_count (surface); + meta_wayland_buffer_dec_use_count (surface->unassigned.buffer); g_clear_object (&surface->unassigned.buffer); } if (surface->buffer_held) - meta_wayland_surface_unref_buffer_use_count (surface); - g_clear_pointer (&surface->texture, cogl_object_unref); - g_clear_pointer (&surface->buffer_ref, meta_wayland_buffer_ref_unref); - - g_clear_object (&surface->cached_state); - g_clear_object (&surface->pending_state); + meta_wayland_buffer_dec_use_count (surface->buffer); + g_clear_pointer (&surface->output_state.texture, cogl_object_unref); + g_clear_object (&surface->buffer); if (surface->opaque_region) cairo_region_destroy (surface->opaque_region); @@ -1442,16 +1402,43 @@ wl_surface_destructor (struct wl_resource *resource) if (surface->resource) wl_resource_set_user_data (surface->resource, NULL); - if (surface->wl_subsurface) - wl_resource_destroy (surface->wl_subsurface); - - g_clear_pointer (&surface->subsurface_branch_node, g_node_destroy); + g_clear_pointer (&surface->output_state.subsurface_branch_node, g_node_destroy); g_hash_table_destroy (surface->shortcut_inhibited_seats); - g_object_unref (surface); + G_OBJECT_CLASS (meta_wayland_surface_parent_class)->finalize (object); + +} + +static void +wl_surface_destructor (struct wl_resource *resource) +{ + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + MetaWaylandSurface *subsurface_surface; + + g_signal_emit (surface, surface_signals[SURFACE_DESTROY], 0); + + g_clear_object (&surface->pending_state); + g_clear_pointer (&surface->sub.transaction, meta_wayland_transaction_free); + + if (surface->resource) + wl_resource_set_user_data (g_steal_pointer (&surface->resource), NULL); + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->protocol_state, + subsurface_surface) + meta_wayland_subsurface_parent_destroyed (subsurface_surface); + + g_clear_pointer (&surface->wl_subsurface, wl_resource_destroy); + g_clear_pointer (&surface->protocol_state.subsurface_branch_node, g_node_destroy); + + cogl_clear_object (&surface->protocol_state.texture); - meta_wayland_compositor_repick (compositor); + /* + * Any transactions referencing this surface will keep it alive until they get + * applied/destroyed. The last reference will be dropped in + * meta_wayland_transaction_free. + */ + g_object_unref (surface); } MetaWaylandSurface * @@ -1681,13 +1668,15 @@ meta_wayland_surface_get_absolute_coordinates (MetaWaylandSurface *surface, static void meta_wayland_surface_init (MetaWaylandSurface *surface) { - surface->pending_state = g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL); + surface->pending_state = meta_wayland_surface_state_new (); - surface->buffer_ref = meta_wayland_buffer_ref_new (); + surface->output_state.subsurface_branch_node = g_node_new (surface); + surface->output_state.subsurface_leaf_node = + g_node_prepend_data (surface->output_state.subsurface_branch_node, surface); - surface->subsurface_branch_node = g_node_new (surface); - surface->subsurface_leaf_node = - g_node_prepend_data (surface->subsurface_branch_node, surface); + surface->protocol_state.subsurface_branch_node = g_node_new (surface); + surface->protocol_state.subsurface_leaf_node = + g_node_prepend_data (surface->protocol_state.subsurface_branch_node, surface); g_signal_connect (surface, "geometry-changed", G_CALLBACK (meta_wayland_surface_update_outputs_recursively), @@ -1699,6 +1688,8 @@ meta_wayland_surface_class_init (MetaWaylandSurfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->finalize = meta_wayland_surface_finalize; + surface_signals[SURFACE_DESTROY] = g_signal_new ("destroy", G_TYPE_FROM_CLASS (object_class), @@ -1834,6 +1825,18 @@ meta_wayland_surface_role_assigned (MetaWaylandSurfaceRole *surface_role) META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role)->assigned (surface_role); } +static void +meta_wayland_surface_role_commit_state (MetaWaylandSurfaceRole *surface_role, + MetaWaylandTransaction *transaction, + MetaWaylandSurfaceState *pending) +{ + MetaWaylandSurfaceRoleClass *klass; + + klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role); + if (klass->commit_state) + klass->commit_state (surface_role, transaction, pending); +} + static void meta_wayland_surface_role_pre_apply_state (MetaWaylandSurfaceRole *surface_role, MetaWaylandSurfaceState *pending) @@ -1912,24 +1915,24 @@ meta_wayland_surface_get_window (MetaWaylandSurface *surface) } static gboolean -meta_wayland_surface_role_should_cache_state (MetaWaylandSurfaceRole *surface_role) +meta_wayland_surface_role_is_synchronized (MetaWaylandSurfaceRole *surface_role) { MetaWaylandSurfaceRoleClass *klass; klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role); - if (klass->should_cache_state) - return klass->should_cache_state (surface_role); + if (klass->is_synchronized) + return klass->is_synchronized (surface_role); else return FALSE; } gboolean -meta_wayland_surface_should_cache_state (MetaWaylandSurface *surface) +meta_wayland_surface_is_synchronized (MetaWaylandSurface *surface) { if (!surface->role) return FALSE; - return meta_wayland_surface_role_should_cache_state (surface->role); + return meta_wayland_surface_role_is_synchronized (surface->role); } static void @@ -1965,7 +1968,7 @@ meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface) cairo_region_t *region; cairo_rectangle_int_t buffer_rect; - if (!surface->buffer_ref->buffer) + if (!surface->buffer) return NULL; buffer_rect = (cairo_rectangle_int_t) { @@ -2009,7 +2012,7 @@ meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurface *surface, CoglTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface) { - return surface->texture; + return surface->output_state.texture; } MetaSurfaceActor * @@ -2079,10 +2082,10 @@ static void scanout_destroyed (gpointer data, GObject *where_the_object_was) { - MetaWaylandBufferRef *buffer_ref = data; + MetaWaylandBuffer *buffer = data; - meta_wayland_buffer_ref_dec_use_count (buffer_ref); - meta_wayland_buffer_ref_unref (buffer_ref); + meta_wayland_buffer_dec_use_count (buffer); + g_object_unref (buffer); } CoglScanout * @@ -2090,22 +2093,22 @@ meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, CoglOnscreen *onscreen) { CoglScanout *scanout; - MetaWaylandBufferRef *buffer_ref; + MetaWaylandBuffer *buffer; - if (!surface->buffer_ref->buffer) + if (!surface->buffer) return NULL; - if (surface->buffer_ref->use_count == 0) + if (surface->buffer->use_count == 0) return NULL; - scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer_ref->buffer, + scanout = meta_wayland_buffer_try_acquire_scanout (surface->buffer, onscreen); if (!scanout) return NULL; - buffer_ref = meta_wayland_buffer_ref_ref (surface->buffer_ref); - meta_wayland_buffer_ref_inc_use_count (buffer_ref); - g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer_ref); + buffer = g_object_ref (surface->buffer); + meta_wayland_buffer_inc_use_count (buffer); + g_object_weak_ref (G_OBJECT (scanout), scanout_destroyed, buffer); return scanout; diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h index 8bb7116f8..207ce97fa 100644 --- a/src/wayland/meta-wayland-surface.h +++ b/src/wayland/meta-wayland-surface.h @@ -54,6 +54,9 @@ struct _MetaWaylandSurfaceRoleClass GObjectClass parent_class; void (*assigned) (MetaWaylandSurfaceRole *surface_role); + void (*commit_state) (MetaWaylandSurfaceRole *surface_role, + MetaWaylandTransaction *transaction, + MetaWaylandSurfaceState *pending); void (*pre_apply_state) (MetaWaylandSurfaceRole *surface_role, MetaWaylandSurfaceState *pending); void (*apply_state) (MetaWaylandSurfaceRole *surface_role, @@ -63,7 +66,7 @@ struct _MetaWaylandSurfaceRoleClass gboolean (*is_on_logical_monitor) (MetaWaylandSurfaceRole *surface_role, MetaLogicalMonitor *logical_monitor); MetaWaylandSurface * (*get_toplevel) (MetaWaylandSurfaceRole *surface_role); - gboolean (*should_cache_state) (MetaWaylandSurfaceRole *surface_role); + gboolean (*is_synchronized) (MetaWaylandSurfaceRole *surface_role); void (*notify_subsurface_state_changed) (MetaWaylandSurfaceRole *surface_role); void (*get_relative_coordinates) (MetaWaylandSurfaceRole *surface_role, float abs_x, @@ -80,6 +83,7 @@ struct _MetaWaylandSurfaceState /* wl_surface.attach */ gboolean newly_attached; MetaWaylandBuffer *buffer; + CoglTexture *texture; gulong buffer_destroy_handler_id; int32_t dx; int32_t dy; @@ -122,6 +126,10 @@ struct _MetaWaylandSurfaceState int viewport_dst_height; GSList *subsurface_placement_ops; + + /* xdg_popup */ + MetaWaylandXdgPositioner *xdg_positioner; + uint32_t xdg_popup_reposition_token; }; struct _MetaWaylandDragDestFuncs @@ -140,13 +148,6 @@ struct _MetaWaylandDragDestFuncs MetaWaylandSurface *surface); }; -typedef struct _MetaWaylandBufferRef -{ - grefcount ref_count; - MetaWaylandBuffer *buffer; - unsigned int use_count; -} MetaWaylandBufferRef; - struct _MetaWaylandSurface { GObject parent; @@ -159,14 +160,10 @@ struct _MetaWaylandSurface cairo_region_t *opaque_region; int scale; int32_t offset_x, offset_y; - GNode *subsurface_branch_node; - GNode *subsurface_leaf_node; GHashTable *outputs_to_destroy_notify_id; MetaMonitorTransform buffer_transform; - CoglTexture *texture; - - MetaWaylandBufferRef *buffer_ref; + MetaWaylandBuffer *buffer; /* Buffer renderer state. */ gboolean buffer_held; @@ -183,16 +180,19 @@ struct _MetaWaylandSurface /* All the pending state that wl_surface.commit will apply. */ MetaWaylandSurfaceState *pending_state; - /* State cached due to inter-surface synchronization such. */ - MetaWaylandSurfaceState *cached_state; + + struct MetaWaylandSurfaceSubState { + MetaWaylandSurface *parent; + GNode *subsurface_branch_node; + GNode *subsurface_leaf_node; + CoglTexture *texture; + } output_state, protocol_state; /* Extension resources. */ struct wl_resource *wl_subsurface; /* wl_subsurface stuff. */ struct { - MetaWaylandSurface *parent; - struct wl_listener parent_destroy_listener; int x; int y; @@ -207,9 +207,10 @@ struct _MetaWaylandSurface */ gboolean synchronous; - int32_t pending_x; - int32_t pending_y; - gboolean pending_pos; + /* Transaction which contains all synchronized state for this sub-surface. + * This can include state for nested sub-surfaces. + */ + MetaWaylandTransaction *transaction; } sub; /* wp_viewport */ @@ -225,6 +226,13 @@ struct _MetaWaylandSurface int dst_height; } viewport; + /* Transactions */ + struct { + /* First & last committed transaction which has an entry for this surface */ + MetaWaylandTransaction *first_committed; + MetaWaylandTransaction *last_committed; + } transaction; + /* table of seats for which shortcuts are inhibited */ GHashTable *shortcut_inhibited_seats; }; @@ -236,15 +244,25 @@ MetaWaylandSurface *meta_wayland_surface_create (MetaWaylandCompositor *composit struct wl_resource *compositor_resource, guint32 id); +void meta_wayland_surface_state_reset (MetaWaylandSurfaceState *state); + +void meta_wayland_surface_state_merge_into (MetaWaylandSurfaceState *from, + MetaWaylandSurfaceState *to); + +void meta_wayland_surface_apply_placement_ops (MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state); + +void meta_wayland_surface_apply_state (MetaWaylandSurface *surface, + MetaWaylandSurfaceState *state); + MetaWaylandSurfaceState * meta_wayland_surface_get_pending_state (MetaWaylandSurface *surface); MetaWaylandSurfaceState * meta_wayland_surface_ensure_cached_state (MetaWaylandSurface *surface); -void meta_wayland_surface_apply_cached_state (MetaWaylandSurface *surface); - -gboolean meta_wayland_surface_is_effectively_synchronized (MetaWaylandSurface *surface); +MetaWaylandTransaction * + meta_wayland_surface_ensure_transaction (MetaWaylandSurface *surface); gboolean meta_wayland_surface_assign_role (MetaWaylandSurface *surface, GType role_type, @@ -253,10 +271,6 @@ gboolean meta_wayland_surface_assign_role (MetaWaylandSurface *surfac MetaWaylandBuffer *meta_wayland_surface_get_buffer (MetaWaylandSurface *surface); -void meta_wayland_surface_ref_buffer_use_count (MetaWaylandSurface *surface); - -void meta_wayland_surface_unref_buffer_use_count (MetaWaylandSurface *surface); - void meta_wayland_surface_set_window (MetaWaylandSurface *surface, MetaWindow *window); @@ -282,7 +296,7 @@ MetaWaylandSurface *meta_wayland_surface_get_toplevel (MetaWaylandSurface *surfa MetaWindow * meta_wayland_surface_get_window (MetaWaylandSurface *surface); -gboolean meta_wayland_surface_should_cache_state (MetaWaylandSurface *surface); +gboolean meta_wayland_surface_is_synchronized (MetaWaylandSurface *surface); MetaWindow * meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface); @@ -346,6 +360,12 @@ int meta_wayland_surface_get_height (MetaWaylandSurface *surface CoglScanout * meta_wayland_surface_try_acquire_scanout (MetaWaylandSurface *surface, CoglOnscreen *onscreen); +static inline MetaWaylandSurfaceState * +meta_wayland_surface_state_new (void) +{ + return g_object_new (META_TYPE_WAYLAND_SURFACE_STATE, NULL); +} + static inline GNode * meta_get_next_subsurface_sibling (GNode *n) { @@ -364,20 +384,22 @@ meta_get_next_subsurface_sibling (GNode *n) } static inline GNode * -meta_get_first_subsurface_node (MetaWaylandSurface *surface) +meta_get_first_subsurface_node (struct MetaWaylandSurfaceSubState *sub) { GNode *n; - n = g_node_first_child (surface->subsurface_branch_node); + n = g_node_first_child (sub->subsurface_branch_node); if (!G_NODE_IS_LEAF (n)) return n; else return meta_get_next_subsurface_sibling (n); } -#define META_WAYLAND_SURFACE_FOREACH_SUBSURFACE(surface, subsurface) \ - for (GNode *G_PASTE(__n, __LINE__) = meta_get_first_subsurface_node ((surface)); \ - (subsurface = (G_PASTE (__n, __LINE__) ? G_PASTE (__n, __LINE__)->data : NULL)); \ - G_PASTE (__n, __LINE__) = meta_get_next_subsurface_sibling (G_PASTE (__n, __LINE__))) +#define META_WAYLAND_SURFACE_FOREACH_SUBSURFACE(state, subsurface) \ +for (GNode *G_PASTE(__n, __LINE__) = meta_get_first_subsurface_node (state), \ + *G_PASTE(__next, __LINE__) = meta_get_next_subsurface_sibling (G_PASTE (__n, __LINE__)); \ + (subsurface = (G_PASTE (__n, __LINE__) ? G_PASTE (__n, __LINE__)->data : NULL)); \ + G_PASTE (__n, __LINE__) = G_PASTE (__next, __LINE__), \ + G_PASTE (__next, __LINE__) = meta_get_next_subsurface_sibling (G_PASTE (__n, __LINE__))) #endif diff --git a/src/wayland/meta-wayland-tablet-pad.c b/src/wayland/meta-wayland-tablet-pad.c index 167d45948..26cc8b9fc 100644 --- a/src/wayland/meta-wayland-tablet-pad.c +++ b/src/wayland/meta-wayland-tablet-pad.c @@ -514,7 +514,7 @@ meta_wayland_tablet_pad_set_focus (MetaWaylandTabletPad *pad, tablet = meta_wayland_tablet_seat_lookup_paired_tablet (pad->tablet_seat, pad); - if (tablet != NULL && surface != NULL) + if (tablet != NULL && surface != NULL && surface->resource != NULL) { struct wl_client *client; diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c index 72a8e887f..ebcbc94bc 100644 --- a/src/wayland/meta-wayland-tablet-tool.c +++ b/src/wayland/meta-wayland-tablet-tool.c @@ -1021,7 +1021,8 @@ tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool, if (tool->focus_surface == surface) return TRUE; - META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface) + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, + subsurface) { if (tablet_tool_can_grab_surface (tool, subsurface)) return TRUE; diff --git a/src/wayland/meta-wayland-text-input.c b/src/wayland/meta-wayland-text-input.c index d4c377b73..b4ecaf535 100644 --- a/src/wayland/meta-wayland-text-input.c +++ b/src/wayland/meta-wayland-text-input.c @@ -346,7 +346,7 @@ meta_wayland_text_input_set_focus (MetaWaylandTextInput *text_input, text_input->surface = NULL; } - if (surface) + if (surface && surface->resource) { struct wl_resource *focus_surface_resource; diff --git a/src/wayland/meta-wayland-touch.c b/src/wayland/meta-wayland-touch.c index 9c2cfc9df..592ce911a 100644 --- a/src/wayland/meta-wayland-touch.c +++ b/src/wayland/meta-wayland-touch.c @@ -232,7 +232,7 @@ meta_wayland_touch_update (MetaWaylandTouch *touch, if (META_IS_SURFACE_ACTOR_WAYLAND (actor)) surface = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor)); - if (!surface) + if (!surface || !surface->resource) return; touch_info = touch_get_info (touch, sequence, TRUE); diff --git a/src/wayland/meta-wayland-transaction.c b/src/wayland/meta-wayland-transaction.c new file mode 100644 index 000000000..7b9a5e9fe --- /dev/null +++ b/src/wayland/meta-wayland-transaction.c @@ -0,0 +1,611 @@ +/* + * Wayland Transaction Support + * + * Copyright (C) 2021 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "wayland/meta-wayland-transaction.h" + +#include + +#include "wayland/meta-wayland.h" +#include "wayland/meta-wayland-buffer.h" +#include "wayland/meta-wayland-dma-buf.h" + +#define META_WAYLAND_TRANSACTION_NONE ((void *)(uintptr_t) G_MAXSIZE) + +struct _MetaWaylandTransaction +{ + GList node; + MetaWaylandCompositor *compositor; + MetaWaylandTransaction *next_candidate; + uint64_t committed_sequence; + + /* + * Keys: All surfaces referenced in the transaction + * Values: Pointer to MetaWaylandTransactionEntry for the surface + */ + GHashTable *entries; + + /* Sources for buffers which are not ready yet */ + GHashTable *buf_sources; +}; + +struct _MetaWaylandTransactionEntry +{ + /* Next committed transaction with entry for the same surface */ + MetaWaylandTransaction *next_transaction; + + MetaWaylandSurfaceState *state; + + /* Sub-surface position */ + gboolean has_sub_pos; + int x; + int y; +}; + +static MetaWaylandTransactionEntry * +meta_wayland_transaction_get_entry (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + return g_hash_table_lookup (transaction->entries, surface); +} + +static void +meta_wayland_transaction_sync_child_states (MetaWaylandSurface *surface) +{ + MetaWaylandSurface *subsurface_surface; + + META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (&surface->output_state, subsurface_surface) + { + MetaWaylandSubsurface *subsurface; + MetaWaylandActorSurface *actor_surface; + + subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role); + actor_surface = META_WAYLAND_ACTOR_SURFACE (subsurface); + meta_wayland_actor_surface_sync_actor_state (actor_surface); + } +} + +static void +meta_wayland_transaction_apply_subsurface_position (MetaWaylandSurface *surface, + MetaWaylandTransactionEntry *entry) +{ + if (!entry->has_sub_pos) + return; + + surface->sub.x = entry->x; + surface->sub.y = entry->y; +} + +static gboolean +is_ancestor (MetaWaylandSurface *candidate, + MetaWaylandSurface *reference) +{ + MetaWaylandSurface *ancestor; + + for (ancestor = reference->output_state.parent; + ancestor; + ancestor = ancestor->output_state.parent) + { + if (ancestor == candidate) + return TRUE; + } + + return FALSE; +} + +static int +meta_wayland_transaction_compare (const void *key1, + const void *key2) +{ + MetaWaylandSurface *surface1 = *(MetaWaylandSurface **) key1; + MetaWaylandSurface *surface2 = *(MetaWaylandSurface **) key2; + + /* Order of siblings doesn't matter */ + if (surface1->output_state.parent == surface2->output_state.parent) + return 0; + + /* Ancestor surfaces come before descendant surfaces */ + if (is_ancestor (surface1, surface2)) + return 1; + + if (is_ancestor (surface2, surface1)) + return -1; + + /* + * Order unrelated surfaces by their toplevel surface pointer values, to + * prevent unrelated surfaces from getting mixed between siblings + */ + return (meta_wayland_surface_get_toplevel (surface1) < + meta_wayland_surface_get_toplevel (surface2)) ? -1 : 1; +} + +static void +ensure_next_candidate (MetaWaylandTransaction *transaction, + MetaWaylandTransaction **first_candidate) +{ + MetaWaylandTransaction **candidate; + + if (transaction->next_candidate) + return; + + candidate = first_candidate; + while (*candidate != META_WAYLAND_TRANSACTION_NONE && + (*candidate)->committed_sequence < + transaction->committed_sequence) + candidate = &(*candidate)->next_candidate; + + transaction->next_candidate = *candidate; + *candidate = transaction; +} + +static void +meta_wayland_transaction_apply (MetaWaylandTransaction *transaction, + MetaWaylandTransaction **first_candidate) +{ + g_autofree MetaWaylandSurface **surfaces = NULL; + g_autofree MetaWaylandSurfaceState **states = NULL; + unsigned int num_surfaces; + MetaWaylandSurface *surface; + MetaWaylandTransactionEntry *entry; + int i; + + if (g_hash_table_size (transaction->entries) == 0) + goto free; + + surfaces = (MetaWaylandSurface **) + g_hash_table_get_keys_as_array (transaction->entries, &num_surfaces); + states = g_new (MetaWaylandSurfaceState *, num_surfaces); + + /* Apply sub-surface states to ensure output surface hierarchy is up to date */ + for (i = 0; i < num_surfaces; i++) + { + surface = surfaces[i]; + entry = meta_wayland_transaction_get_entry (transaction, surface); + meta_wayland_transaction_apply_subsurface_position (surface, entry); + + if (entry->state && entry->state->subsurface_placement_ops) + meta_wayland_surface_apply_placement_ops (surface, entry->state); + } + + /* Sort surfaces from ancestors to descendants */ + qsort (surfaces, num_surfaces, sizeof (MetaWaylandSurface *), + meta_wayland_transaction_compare); + + /* Apply states from ancestors to descendants */ + for (i = 0; i < num_surfaces; i++) + { + surface = surfaces[i]; + entry = meta_wayland_transaction_get_entry (transaction, surface); + + states[i] = entry->state; + if (entry->state) + meta_wayland_surface_apply_state (surface, entry->state); + + if (surface->transaction.last_committed == transaction) + { + surface->transaction.first_committed = NULL; + surface->transaction.last_committed = NULL; + } + else + { + MetaWaylandTransaction *next_transaction = entry->next_transaction; + + if (next_transaction) + { + surface->transaction.first_committed = next_transaction; + ensure_next_candidate (next_transaction, first_candidate); + } + } + } + + /* Synchronize child states from descendants to ancestors */ + for (i = num_surfaces - 1; i >= 0; i--) + { + if (states[i]) + meta_wayland_transaction_sync_child_states (surfaces[i]); + } + +free: + meta_wayland_transaction_free (transaction); +} + +static gboolean +has_dependencies (MetaWaylandTransaction *transaction) +{ + GHashTableIter iter; + MetaWaylandSurface *surface; + + if (transaction->buf_sources && + g_hash_table_size (transaction->buf_sources) > 0) + return TRUE; + + g_hash_table_iter_init (&iter, transaction->entries); + while (g_hash_table_iter_next (&iter, (gpointer *) &surface, NULL)) + { + if (surface->transaction.first_committed != transaction) + return TRUE; + } + + return FALSE; +} + +static void +meta_wayland_transaction_maybe_apply_one (MetaWaylandTransaction *transaction, + MetaWaylandTransaction **first_candidate) +{ + if (has_dependencies (transaction)) + return; + + meta_wayland_transaction_apply (transaction, first_candidate); +} + +static void +meta_wayland_transaction_maybe_apply (MetaWaylandTransaction *transaction) +{ + MetaWaylandTransaction *first_candidate = META_WAYLAND_TRANSACTION_NONE; + + while (TRUE) + { + meta_wayland_transaction_maybe_apply_one (transaction, &first_candidate); + + if (first_candidate == META_WAYLAND_TRANSACTION_NONE) + return; + + transaction = first_candidate; + first_candidate = transaction->next_candidate; + transaction->next_candidate = NULL; + } +} + +static void +meta_wayland_transaction_dma_buf_dispatch (MetaWaylandBuffer *buffer, + gpointer user_data) +{ + MetaWaylandTransaction *transaction = user_data; + + if (!transaction->buf_sources || + !g_hash_table_remove (transaction->buf_sources, buffer)) + return; + + meta_wayland_transaction_maybe_apply (transaction); +} + +static gboolean +meta_wayland_transaction_add_dma_buf_source (MetaWaylandTransaction *transaction, + MetaWaylandBuffer *buffer) +{ + GSource *source; + + if (transaction->buf_sources && + g_hash_table_contains (transaction->buf_sources, buffer)) + return FALSE; + + source = meta_wayland_dma_buf_create_source (buffer, + meta_wayland_transaction_dma_buf_dispatch, + transaction); + if (!source) + return FALSE; + + if (!transaction->buf_sources) + { + transaction->buf_sources = + g_hash_table_new_full (NULL, NULL, NULL, + (GDestroyNotify) g_source_destroy); + } + + g_hash_table_insert (transaction->buf_sources, buffer, source); + g_source_attach (source, NULL); + g_source_unref (source); + + return TRUE; +} + +void +meta_wayland_transaction_commit (MetaWaylandTransaction *transaction) +{ + static uint64_t committed_sequence; + GQueue *committed_queue; + gboolean maybe_apply = TRUE; + GHashTableIter iter; + MetaWaylandSurface *surface; + MetaWaylandTransactionEntry *entry; + + g_hash_table_iter_init (&iter, transaction->entries); + while (g_hash_table_iter_next (&iter, + (gpointer *) &surface, (gpointer *) &entry)) + { + if (entry && entry->state) + { + MetaWaylandBuffer *buffer = entry->state->buffer; + + if (buffer && + meta_wayland_transaction_add_dma_buf_source (transaction, buffer)) + maybe_apply = FALSE; + } + } + + transaction->committed_sequence = ++committed_sequence; + transaction->node.data = transaction; + + committed_queue = + meta_wayland_compositor_get_committed_transactions (transaction->compositor); + g_queue_push_tail_link (committed_queue, &transaction->node); + + g_hash_table_iter_init (&iter, transaction->entries); + while (g_hash_table_iter_next (&iter, (gpointer *) &surface, NULL)) + { + if (surface->transaction.first_committed) + { + MetaWaylandTransactionEntry *entry; + + entry = g_hash_table_lookup (surface->transaction.last_committed->entries, + surface); + entry->next_transaction = transaction; + maybe_apply = FALSE; + } + else + { + surface->transaction.first_committed = transaction; + } + + surface->transaction.last_committed = transaction; + } + + if (maybe_apply) + meta_wayland_transaction_maybe_apply (transaction); +} + +MetaWaylandTransactionEntry * +meta_wayland_transaction_ensure_entry (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_get_entry (transaction, surface); + if (entry) + return entry; + + entry = g_new0 (MetaWaylandTransactionEntry, 1); + g_hash_table_insert (transaction->entries, g_object_ref (surface), entry); + + return entry; +} + +static void +meta_wayland_transaction_entry_free (MetaWaylandTransactionEntry *entry) +{ + if (entry->state) + { + if (entry->state->buffer) + meta_wayland_buffer_dec_use_count (entry->state->buffer); + + g_clear_object (&entry->state); + } + + g_free (entry); +} + +static void +meta_wayland_transaction_add_placement_surfaces (MetaWaylandTransaction *transaction, + MetaWaylandSurfaceState *state) +{ + GSList *l; + + for (l = state->subsurface_placement_ops; l; l = l->next) + { + MetaWaylandSubsurfacePlacementOp *op = l->data; + + meta_wayland_transaction_ensure_entry (transaction, op->surface); + + if (op->sibling) + meta_wayland_transaction_ensure_entry (transaction, op->sibling); + } +} + +static void +meta_wayland_transaction_add_entry (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + MetaWaylandTransactionEntry *entry) +{ + g_hash_table_insert (transaction->entries, g_object_ref (surface), entry); + + if (entry->state) + meta_wayland_transaction_add_placement_surfaces (transaction, entry->state); +} + +void +meta_wayland_transaction_add_placement_op (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + MetaWaylandSubsurfacePlacementOp *op) +{ + MetaWaylandTransactionEntry *entry; + MetaWaylandSurfaceState *state; + + entry = meta_wayland_transaction_ensure_entry (transaction, surface); + + if (!entry->state) + entry->state = meta_wayland_surface_state_new (); + + state = entry->state; + state->subsurface_placement_ops = + g_slist_append (state->subsurface_placement_ops, op); + + meta_wayland_transaction_add_placement_surfaces (transaction, state); +} + +void +meta_wayland_transaction_add_subsurface_position (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + int x, + int y) +{ + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_ensure_entry (transaction, surface); + entry->x = x; + entry->y = y; + entry->has_sub_pos = TRUE; +} + +void +meta_wayland_transaction_add_xdg_popup_reposition (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + void *xdg_positioner, + uint32_t token) +{ + MetaWaylandTransactionEntry *entry; + MetaWaylandSurfaceState *state; + + entry = meta_wayland_transaction_ensure_entry (transaction, surface); + + if (entry->state) + g_clear_pointer (&entry->state->xdg_positioner, g_free); + else + entry->state = meta_wayland_surface_state_new (); + + state = entry->state; + state->xdg_positioner = xdg_positioner; + state->xdg_popup_reposition_token = token; +} + +static void +meta_wayland_transaction_entry_merge_into (MetaWaylandTransactionEntry *from, + MetaWaylandTransactionEntry *to) +{ + if (from->has_sub_pos) + { + to->x = from->x; + to->y = from->y; + to->has_sub_pos = TRUE; + } + + if (to->state) + { + meta_wayland_surface_state_merge_into (from->state, to->state); + g_clear_object (&from->state); + return; + } + + to->state = g_steal_pointer (&from->state); +} + +void +meta_wayland_transaction_merge_into (MetaWaylandTransaction *from, + MetaWaylandTransaction *to) +{ + GHashTableIter iter; + MetaWaylandSurface *surface; + MetaWaylandTransactionEntry *from_entry, *to_entry; + + g_hash_table_iter_init (&iter, from->entries); + while (g_hash_table_iter_next (&iter, (gpointer *) &surface, + (gpointer *) &from_entry)) + { + to_entry = meta_wayland_transaction_get_entry (to, surface); + if (!to_entry) + { + g_hash_table_iter_steal (&iter); + meta_wayland_transaction_add_entry (to, surface, from_entry); + g_object_unref (surface); + continue; + } + + if (from_entry->state) + meta_wayland_transaction_add_placement_surfaces (to, from_entry->state); + + meta_wayland_transaction_entry_merge_into (from_entry, to_entry); + g_hash_table_iter_remove (&iter); + } + + meta_wayland_transaction_free (from); +} + +void +meta_wayland_transaction_merge_pending_state (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface) +{ + MetaWaylandSurfaceState *pending = surface->pending_state; + MetaWaylandTransactionEntry *entry; + + entry = meta_wayland_transaction_ensure_entry (transaction, surface); + + if (!entry->state) + { + entry->state = pending; + surface->pending_state = meta_wayland_surface_state_new (); + return; + } + + meta_wayland_surface_state_merge_into (pending, entry->state); + meta_wayland_surface_state_reset (pending); +} + +MetaWaylandTransaction * +meta_wayland_transaction_new (MetaWaylandCompositor *compositor) +{ + MetaWaylandTransaction *transaction; + + transaction = g_new0 (MetaWaylandTransaction, 1); + + transaction->compositor = compositor; + transaction->entries = g_hash_table_new_full (NULL, NULL, g_object_unref, + (GDestroyNotify) meta_wayland_transaction_entry_free); + + return transaction; +} + +void +meta_wayland_transaction_free (MetaWaylandTransaction *transaction) +{ + if (transaction->node.data) + { + GQueue *committed_queue = + meta_wayland_compositor_get_committed_transactions (transaction->compositor); + + g_queue_unlink (committed_queue, &transaction->node); + } + + g_clear_pointer (&transaction->buf_sources, g_hash_table_destroy); + g_hash_table_destroy (transaction->entries); + g_free (transaction); +} + +void +meta_wayland_transaction_finalize (MetaWaylandCompositor *compositor) +{ + GQueue *transactions; + MetaWaylandTransaction *transaction; + + transactions = meta_wayland_compositor_get_committed_transactions (compositor); + + while ((transaction = g_queue_pop_head (transactions))) + meta_wayland_transaction_free (transaction); +} + +void +meta_wayland_transaction_init (MetaWaylandCompositor *compositor) +{ + GQueue *transactions; + + transactions = meta_wayland_compositor_get_committed_transactions (compositor); + g_queue_init (transactions); +} diff --git a/src/wayland/meta-wayland-transaction.h b/src/wayland/meta-wayland-transaction.h new file mode 100644 index 000000000..98c662001 --- /dev/null +++ b/src/wayland/meta-wayland-transaction.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef META_WAYLAND_TRANSACTION_H +#define META_WAYLAND_TRANSACTION_H + +#include "wayland/meta-wayland-types.h" +#include "wayland/meta-wayland-subsurface.h" + +void meta_wayland_transaction_commit (MetaWaylandTransaction *transaction); + +MetaWaylandTransactionEntry *meta_wayland_transaction_ensure_entry (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface); + +void meta_wayland_transaction_add_placement_op (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + MetaWaylandSubsurfacePlacementOp *op); + +void meta_wayland_transaction_add_subsurface_position (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + int x, + int y); + +void meta_wayland_transaction_add_xdg_popup_reposition (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface, + void *xdg_positioner, + uint32_t token); + +void meta_wayland_transaction_merge_into (MetaWaylandTransaction *from, + MetaWaylandTransaction *to); + +void meta_wayland_transaction_merge_pending_state (MetaWaylandTransaction *transaction, + MetaWaylandSurface *surface); + +MetaWaylandTransaction *meta_wayland_transaction_new (MetaWaylandCompositor *compositor); + +void meta_wayland_transaction_free (MetaWaylandTransaction *transaction); + +void meta_wayland_transaction_finalize (MetaWaylandCompositor *compositor); + +void meta_wayland_transaction_init (MetaWaylandCompositor *compositor); + +#endif diff --git a/src/wayland/meta-wayland-types.h b/src/wayland/meta-wayland-types.h index 064acc51b..30fde9379 100644 --- a/src/wayland/meta-wayland-types.h +++ b/src/wayland/meta-wayland-types.h @@ -54,6 +54,9 @@ typedef struct _MetaWaylandRegion MetaWaylandRegion; typedef struct _MetaWaylandSurface MetaWaylandSurface; typedef struct _MetaWaylandSurfaceState MetaWaylandSurfaceState; +typedef struct _MetaWaylandTransaction MetaWaylandTransaction; +typedef struct _MetaWaylandTransactionEntry MetaWaylandTransactionEntry; + typedef struct _MetaWaylandOutput MetaWaylandOutput; typedef struct _MetaWaylandWindowConfiguration MetaWaylandWindowConfiguration; @@ -64,4 +67,6 @@ typedef struct _MetaWaylandActivation MetaWaylandActivation; typedef struct _MetaWaylandXdgForeign MetaWaylandXdgForeign; +typedef struct _MetaWaylandXdgPositioner MetaWaylandXdgPositioner; + #endif diff --git a/src/wayland/meta-wayland-viewporter.c b/src/wayland/meta-wayland-viewporter.c index 619f3177c..765216766 100644 --- a/src/wayland/meta-wayland-viewporter.c +++ b/src/wayland/meta-wayland-viewporter.c @@ -46,10 +46,13 @@ wp_viewport_destructor (struct wl_resource *resource) g_clear_signal_handler (&surface->viewport.destroy_handler_id, surface); pending = meta_wayland_surface_get_pending_state (surface); - pending->viewport_src_rect.size.width = -1; - pending->viewport_dst_width = -1; - pending->has_new_viewport_src_rect = TRUE; - pending->has_new_viewport_dst_size = TRUE; + if (pending) + { + pending->viewport_src_rect.size.width = -1; + pending->viewport_dst_width = -1; + pending->has_new_viewport_src_rect = TRUE; + pending->has_new_viewport_dst_size = TRUE; + } surface->viewport.resource = NULL; } @@ -103,6 +106,15 @@ wp_viewport_set_source (struct wl_client *client, MetaWaylandSurfaceState *pending; pending = meta_wayland_surface_get_pending_state (surface); + + if (!pending) + { + wl_resource_post_error (resource, + WP_VIEWPORT_ERROR_NO_SURFACE, + "wl_surface for this viewport no longer exists"); + return; + } + pending->viewport_src_rect.origin.x = new_x; pending->viewport_src_rect.origin.y = new_y; pending->viewport_src_rect.size.width = new_width; @@ -142,6 +154,15 @@ wp_viewport_set_destination (struct wl_client *client, MetaWaylandSurfaceState *pending; pending = meta_wayland_surface_get_pending_state (surface); + + if (!pending) + { + wl_resource_post_error (resource, + WP_VIEWPORT_ERROR_NO_SURFACE, + "wl_surface for this viewport no longer exists"); + return; + } + pending->viewport_dst_width = dst_width; pending->viewport_dst_height = dst_height; pending->has_new_viewport_dst_size = TRUE; diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c index acc181577..fb20bf067 100644 --- a/src/wayland/meta-wayland-xdg-shell.c +++ b/src/wayland/meta-wayland-xdg-shell.c @@ -37,6 +37,7 @@ #include "wayland/meta-wayland-seat.h" #include "wayland/meta-wayland-shell-surface.h" #include "wayland/meta-wayland-surface.h" +#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-wayland-versions.h" #include "wayland/meta-wayland-window-configuration.h" #include "wayland/meta-wayland.h" @@ -59,7 +60,7 @@ typedef struct _MetaWaylandXdgShellClient GList *surface_constructors; } MetaWaylandXdgShellClient; -typedef struct _MetaWaylandXdgPositioner +struct _MetaWaylandXdgPositioner { MetaRectangle anchor_rect; int32_t width; @@ -78,7 +79,7 @@ typedef struct _MetaWaylandXdgPositioner gboolean acked_parent_configure; uint32_t parent_configure_serial; -} MetaWaylandXdgPositioner; +}; typedef struct _MetaWaylandXdgSurfaceConstructor { @@ -133,11 +134,7 @@ struct _MetaWaylandXdgPopup struct { MetaWaylandSurface *parent_surface; - /* - * The coordinates/dimensions in the placement rule are in logical pixel - * coordinate space, i.e. not scaled given what monitor the popup is on. - */ - MetaPlacementRule placement_rule; + MetaWaylandXdgPositioner xdg_positioner; /* Stored positioner data for when parent is set later (e.g., layer-shell) */ MetaRectangle anchor_rect; @@ -402,6 +399,15 @@ xdg_toplevel_set_max_size (struct wl_client *client, pending = meta_wayland_surface_get_pending_state (surface); + + if (!pending) + { + wl_resource_post_error (resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "underlying wl_surface already destroyed"); + return; + } + pending->has_new_max_size = TRUE; pending->new_max_width = width; pending->new_max_height = height; @@ -427,6 +433,15 @@ xdg_toplevel_set_min_size (struct wl_client *client, pending = meta_wayland_surface_get_pending_state (surface); + + if (!pending) + { + wl_resource_post_error (resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "underlying wl_surface already destroyed"); + return; + } + pending->has_new_min_size = TRUE; pending->new_min_width = width; pending->new_min_height = height; @@ -632,27 +647,17 @@ xdg_popup_reposition (struct wl_client *client, META_WAYLAND_SURFACE_ROLE (xdg_popup); MetaWaylandSurface *surface = meta_wayland_surface_role_get_surface (surface_role); - MetaWindow *window; - MetaWindow *parent_window; MetaWaylandXdgPositioner *xdg_positioner; - MetaPlacementRule placement_rule; - - window = meta_wayland_surface_get_window (surface); - if (!window) - return; + MetaWaylandTransaction *transaction; - parent_window = meta_wayland_surface_get_window (xdg_popup->parent_surface); + xdg_positioner = g_memdup2 (wl_resource_get_user_data (positioner_resource), + sizeof (MetaWaylandXdgPositioner)); - xdg_positioner = wl_resource_get_user_data (positioner_resource); - placement_rule = meta_wayland_xdg_positioner_to_placement (xdg_positioner, - parent_window); - - xdg_popup->pending_reposition_token = token; - xdg_popup->pending_repositioned = TRUE; - - scale_placement_rule (&placement_rule, surface); - - meta_window_update_placement_rule (window, &placement_rule); + transaction = meta_wayland_transaction_new (surface->compositor); + meta_wayland_transaction_add_xdg_popup_reposition (transaction, surface, + xdg_positioner, token); + meta_wayland_transaction_ensure_entry (transaction, xdg_popup->parent_surface); + meta_wayland_transaction_commit (transaction); } static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { @@ -834,7 +839,7 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role, return; } - if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached) + if (!surface->buffer && xdg_surface_priv->first_buffer_attached) { meta_wayland_xdg_surface_reset (xdg_surface); meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, @@ -893,7 +898,7 @@ meta_wayland_xdg_toplevel_post_apply_state (MetaWaylandSurfaceRole *surface_rol META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class); surface_role_class->post_apply_state (surface_role, pending); - if (!surface->buffer_ref->buffer) + if (surface->buffer) return; window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface); @@ -928,9 +933,12 @@ meta_wayland_xdg_toplevel_post_apply_state (MetaWaylandSurfaceRole *surface_rol } else { - wl_resource_post_error (surface->resource, - XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, - "Invalid min/max size"); + if (surface->resource) + { + wl_resource_post_error (surface->resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "Invalid min/max size"); + } } } } @@ -1115,6 +1123,8 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) uint32_t serial; MetaDisplay *display = meta_get_display (); MetaWindow *window; + MetaWindow *parent_window; + MetaPlacementRule placement_rule; parent_surface = xdg_popup->setup.parent_surface; seat = xdg_popup->setup.grab_seat; @@ -1171,7 +1181,11 @@ finish_popup_setup (MetaWaylandXdgPopup *xdg_popup) window = meta_window_wayland_new (display, surface); meta_wayland_shell_surface_set_window (shell_surface, window); - meta_wayland_xdg_popup_place (xdg_popup, &xdg_popup->setup.placement_rule); + parent_window = meta_wayland_surface_get_window (parent_surface); + placement_rule = + meta_wayland_xdg_positioner_to_placement (&xdg_popup->setup.xdg_positioner, + parent_window); + meta_wayland_xdg_popup_place (xdg_popup, &placement_rule); if (seat) { @@ -1235,6 +1249,20 @@ dismiss_invalid_popup (MetaWaylandXdgPopup *xdg_popup) } } +static void +meta_wayland_xdg_popup_commit_state (MetaWaylandSurfaceRole *surface_role, + MetaWaylandTransaction *transaction, + MetaWaylandSurfaceState *pending) +{ + MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (surface_role); + + if (xdg_popup->setup.parent_surface) + { + meta_wayland_transaction_ensure_entry (transaction, + xdg_popup->setup.parent_surface); + } +} + static void meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, MetaWaylandSurfaceState *pending) @@ -1252,7 +1280,26 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, if (xdg_popup->setup.parent_surface) finish_popup_setup (xdg_popup); - if (!surface->buffer_ref->buffer && xdg_surface_priv->first_buffer_attached) + if (pending->xdg_positioner) + { + MetaWindow *window, *parent_window; + MetaPlacementRule placement_rule; + + parent_window = meta_wayland_surface_get_window (xdg_popup->parent_surface); + placement_rule = + meta_wayland_xdg_positioner_to_placement (pending->xdg_positioner, + parent_window); + + xdg_popup->pending_reposition_token = pending->xdg_popup_reposition_token; + xdg_popup->pending_repositioned = TRUE; + + scale_placement_rule (&placement_rule, surface); + + window = meta_wayland_surface_get_window (surface); + meta_window_update_placement_rule (window, &placement_rule); + } + + if (!surface->buffer && xdg_surface_priv->first_buffer_attached) { meta_wayland_xdg_surface_reset (xdg_surface); meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); @@ -1263,7 +1310,7 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role, META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class); surface_role_class->apply_state (surface_role, pending); - if (xdg_popup->dismissed_by_client && surface->buffer_ref->buffer) + if (xdg_popup->dismissed_by_client && surface->buffer) { wl_resource_post_error (xdg_popup->resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -1294,7 +1341,7 @@ meta_wayland_xdg_popup_post_apply_state (MetaWaylandSurfaceRole *surface_role, if (!pending->newly_attached) return; - if (!surface->buffer_ref->buffer) + if (!surface->buffer) return; surface_role_class->post_apply_state (surface_role, pending); @@ -1510,6 +1557,7 @@ meta_wayland_xdg_popup_class_init (MetaWaylandXdgPopupClass *klass) object_class->finalize = meta_wayland_xdg_popup_finalize; surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass); + surface_role_class->commit_state = meta_wayland_xdg_popup_commit_state; surface_role_class->apply_state = meta_wayland_xdg_popup_apply_state; surface_role_class->post_apply_state = meta_wayland_xdg_popup_post_apply_state; surface_role_class->get_toplevel = meta_wayland_xdg_popup_get_toplevel; @@ -1638,6 +1686,15 @@ xdg_surface_set_window_geometry (struct wl_client *client, } pending = meta_wayland_surface_get_pending_state (surface); + + if (!pending) + { + wl_resource_post_error (resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "underlying wl_surface already destroyed"); + return; + } + pending->has_new_geometry = TRUE; pending->new_geometry.x = x; pending->new_geometry.y = y; @@ -1654,6 +1711,15 @@ xdg_surface_ack_configure (struct wl_client *client, MetaWaylandSurfaceState *pending; pending = meta_wayland_surface_get_pending_state (surface); + + if (!pending) + { + wl_resource_post_error (resource, + XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, + "underlying wl_surface already destroyed"); + return; + } + pending->has_acked_configure_serial = TRUE; pending->acked_configure_serial = serial; } @@ -1714,7 +1780,7 @@ meta_wayland_xdg_surface_apply_state (MetaWaylandSurfaceRole *surface_role, if (!window) return; - if (surface->buffer_ref->buffer) + if (surface->buffer) priv->first_buffer_attached = TRUE; } @@ -1744,7 +1810,7 @@ meta_wayland_xdg_surface_post_apply_state (MetaWaylandSurfaceRole *surface_role * buffer (e.g. answering an initial maximized configure). The * geometry can't be resolved against an empty surface; defer * silently until a buffer arrives rather than warning. */ - if (!surface->buffer_ref->buffer) + if (surface->buffer) { priv->has_set_geometry = TRUE; return; @@ -1797,7 +1863,7 @@ meta_wayland_xdg_surface_assigned (MetaWaylandSurfaceRole *surface_role) priv->configure_sent = FALSE; priv->first_buffer_attached = FALSE; - if (surface->buffer_ref->buffer) + if (surface->buffer) { wl_resource_post_error (xdg_wm_base_resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -2094,8 +2160,7 @@ xdg_surface_constructor_get_popup (struct wl_client *client, xdg_positioner = wl_resource_get_user_data (positioner_resource); if (parent_window) { - xdg_popup->setup.placement_rule = - meta_wayland_xdg_positioner_to_placement (xdg_positioner, parent_window); + xdg_popup->setup.xdg_positioner = *xdg_positioner; } else { @@ -2517,7 +2582,7 @@ xdg_wm_base_get_xdg_surface (struct wl_client *client, return; } - if (surface->buffer_ref->buffer) + if (surface->buffer) { wl_resource_post_error (resource, XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE, @@ -2625,7 +2690,8 @@ meta_wayland_xdg_popup_set_parent_surface (MetaWaylandXdgPopup *xdg_popup, META_WAYLAND_LAYER_SURFACE (parent_surface->role); int parent_x = 0, parent_y = 0; int parent_width = 0, parent_height = 0; - MetaPlacementRule *rule = &xdg_popup->setup.placement_rule; + MetaPlacementRule placement_rule; + MetaWaylandXdgPositioner *positioner = &xdg_popup->setup.xdg_positioner; /* Read the layer surface's intended geometry directly rather than the * clutter actor's position. The actor is only positioned after the @@ -2640,23 +2706,20 @@ meta_wayland_xdg_popup_set_parent_surface (MetaWaylandXdgPopup *xdg_popup, /* Build placement rule from stored positioner data (window-local coordinates). * parent_rect provides the global offset - don't add it to anchor_rect too. */ - rule->anchor_rect.x = xdg_popup->setup.anchor_rect.x; - rule->anchor_rect.y = xdg_popup->setup.anchor_rect.y; - rule->anchor_rect.width = xdg_popup->setup.anchor_rect.width; - rule->anchor_rect.height = xdg_popup->setup.anchor_rect.height; - rule->width = xdg_popup->setup.width; - rule->height = xdg_popup->setup.height; - rule->anchor = positioner_anchor_to_placement_anchor (xdg_popup->setup.anchor); - rule->gravity = positioner_gravity_to_placement_gravity (xdg_popup->setup.gravity); - rule->constraint_adjustment = xdg_popup->setup.constraint_adjustment; - rule->offset_x = xdg_popup->setup.offset_x; - rule->offset_y = xdg_popup->setup.offset_y; - rule->is_reactive = FALSE; - - rule->parent_rect.x = parent_x; - rule->parent_rect.y = parent_y; - rule->parent_rect.width = parent_width; - rule->parent_rect.height = parent_height; + placement_rule.anchor_rect = positioner->anchor_rect; + placement_rule.width = positioner->width; + placement_rule.height = positioner->height; + placement_rule.anchor = positioner_anchor_to_placement_anchor (positioner->anchor); + placement_rule.gravity = positioner_gravity_to_placement_gravity (positioner->gravity); + placement_rule.constraint_adjustment = positioner->constraint_adjustment; + placement_rule.offset_x = positioner->offset_x; + placement_rule.offset_y = positioner->offset_y; + placement_rule.is_reactive = positioner->is_reactive; + + placement_rule.parent_rect.x = parent_x; + placement_rule.parent_rect.y = parent_y; + placement_rule.parent_rect.width = parent_width; + placement_rule.parent_rect.height = parent_height; } } diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c index 2c4918abb..da00f332b 100644 --- a/src/wayland/meta-wayland.c +++ b/src/wayland/meta-wayland.c @@ -49,6 +49,7 @@ #include "wayland/meta-wayland-subsurface.h" #include "wayland/meta-wayland-system-bell.h" #include "wayland/meta-wayland-tablet-manager.h" +#include "wayland/meta-wayland-transaction.h" #include "wayland/meta-wayland-xdg-dialog.h" #include "wayland/meta-wayland-xdg-foreign.h" #include "wayland/meta-wayland-xdg-toplevel-tag.h" @@ -301,6 +302,12 @@ meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *co g_list_remove (compositor->frame_callback_surfaces, surface); } +GQueue * +meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor) +{ + return &compositor->committed_transactions; +} + static void set_gnome_env (const char *name, const char *value) @@ -458,6 +465,7 @@ meta_wayland_compositor_setup (MetaWaylandCompositor *wayland_compositor) meta_wayland_surface_inhibit_shortcuts_dialog_init (); meta_wayland_text_input_init (compositor); meta_wayland_activation_init (compositor); + meta_wayland_transaction_init (compositor); meta_wayland_idle_inhibit_init (compositor); meta_wayland_init_xdg_wm_dialog (compositor); meta_wayland_xdg_toplevel_tag_init (compositor); diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h index 3549fb2d5..f6ef0a9b9 100644 --- a/src/wayland/meta-wayland.h +++ b/src/wayland/meta-wayland.h @@ -68,6 +68,8 @@ void meta_wayland_compositor_add_frame_callback_surface (Meta void meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor, MetaWaylandSurface *surface); +GQueue *meta_wayland_compositor_get_committed_transactions (MetaWaylandCompositor *compositor); + META_EXPORT_TEST const char *meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor); diff --git a/src/wayland/meta-window-wayland.c b/src/wayland/meta-window-wayland.c index 7e491d754..ea5b718c3 100644 --- a/src/wayland/meta-window-wayland.c +++ b/src/wayland/meta-window-wayland.c @@ -156,7 +156,11 @@ static void meta_window_wayland_kill (MetaWindow *window) { MetaWaylandSurface *surface = window->surface; - struct wl_resource *resource = surface->resource; + struct wl_resource *resource; + + resource = surface->resource; + if (!resource) + return; /* Send the client an unrecoverable error to kill the client. */ wl_resource_post_error (resource, @@ -630,9 +634,13 @@ static uint32_t meta_window_wayland_get_client_pid (MetaWindow *window) { MetaWaylandSurface *surface = window->surface; - struct wl_resource *resource = surface->resource; + struct wl_resource *resource; pid_t pid; + resource = surface->resource; + if (!resource) + return 0; + wl_client_get_credentials (wl_resource_get_client (resource), &pid, NULL, NULL); return (uint32_t)pid; } diff --git a/src/wayland/meta-xwayland-surface.c b/src/wayland/meta-xwayland-surface.c index c8625f414..b7aa3cb2e 100644 --- a/src/wayland/meta-xwayland-surface.c +++ b/src/wayland/meta-xwayland-surface.c @@ -182,7 +182,7 @@ meta_xwayland_surface_pre_apply_state (MetaWaylandSurfaceRole *surface_role, MetaXwaylandSurface *xwayland_surface = META_XWAYLAND_SURFACE (surface_role); if (pending->newly_attached && - surface->buffer_ref->buffer && + !surface->buffer && xwayland_surface->window) meta_window_queue (xwayland_surface->window, META_QUEUE_CALC_SHOWING); } diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c index 861f4415c..466f7ed94 100644 --- a/src/wayland/meta-xwayland.c +++ b/src/wayland/meta-xwayland.c @@ -120,7 +120,8 @@ meta_xwayland_is_xwayland_surface (MetaWaylandSurface *surface) MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); MetaXWaylandManager *manager = &compositor->xwayland_manager; - return wl_resource_get_client (surface->resource) == manager->client; + return surface->resource != NULL && + wl_resource_get_client (surface->resource) == manager->client; } static gboolean