summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2018-04-06 17:50:31 +0200
committerCarlos Garnacho <carlosg@gnome.org>2018-04-10 15:22:06 +0200
commitebe128ba8d79130d7107c79e9af2edc0195fc82c (patch)
tree5d497ce40260023042eee70c2de229c4c1a03e9d
parent98dfd5b8871596612db2a1dc8b5e886d01c86c50 (diff)
downloadmutter-wip/carlosg/pending-state-leak-fix.tar.gz
wayland: Plug surface pending state contents leakwip/carlosg/pending-state-leak-fix
When moving the pending state of an effectively synchronized subsurface so it is applied together with the parent, perform a merge of the source MetaWaylandPendingState into the destination one, instead of simply overwriting the struct. The other approach had 2 kind of leaks, one that would happen everytime a wl_surface.commit happens on a sync subsurface (both surface/buffer damage regions are leaked). The other more unlikely one would apply on the rest of pending state data, happening whenever the compositor gets >1 wl_surface.commit calls on the subsurface before the parent surface gets its own. The function has also been renamed to use the more descriptive "merge" term. Related: gnome-shell#64
-rw-r--r--src/wayland/meta-wayland-surface.c95
1 files changed, 68 insertions, 27 deletions
diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c
index 05b99f8bb..87384cac0 100644
--- a/src/wayland/meta-wayland-surface.c
+++ b/src/wayland/meta-wayland-surface.c
@@ -439,36 +439,77 @@ pending_state_reset (MetaWaylandPendingState *state)
}
static void
-move_pending_state (MetaWaylandPendingState *from,
- MetaWaylandPendingState *to)
-{
- if (from->buffer)
- g_signal_handler_disconnect (from->buffer, from->buffer_destroy_handler_id);
-
- to->newly_attached = from->newly_attached;
- to->buffer = from->buffer;
- to->dx = from->dx;
- to->dy = from->dy;
- to->scale = from->scale;
- to->surface_damage = from->surface_damage;
- to->buffer_damage = from->buffer_damage;
- to->input_region = from->input_region;
- to->input_region_set = from->input_region_set;
- to->opaque_region = from->opaque_region;
- to->opaque_region_set = from->opaque_region_set;
- to->new_geometry = from->new_geometry;
- to->has_new_geometry = from->has_new_geometry;
- to->has_new_min_size = from->has_new_min_size;
- to->new_min_width = from->new_min_width;
- to->new_min_height = from->new_min_height;
- to->has_new_max_size = from->has_new_max_size;
- to->new_max_width = from->new_max_width;
- to->new_max_height = from->new_max_height;
+merge_pending_state (MetaWaylandPendingState *from,
+ MetaWaylandPendingState *to)
+{
+ if (from->newly_attached)
+ {
+ if (to->buffer)
+ {
+ g_signal_handler_disconnect (to->buffer, to->buffer_destroy_handler_id);
+ to->buffer_destroy_handler_id = 0;
+ }
+
+ if (from->buffer)
+ {
+ g_signal_handler_disconnect (from->buffer, from->buffer_destroy_handler_id);
+ from->buffer_destroy_handler_id = 0;
+ }
+
+ to->newly_attached = TRUE;
+ to->buffer = from->buffer;
+ to->dx = from->dx;
+ to->dy = from->dy;
+ }
wl_list_init (&to->frame_callback_list);
wl_list_insert_list (&to->frame_callback_list, &from->frame_callback_list);
- if (to->buffer)
+ cairo_region_union (to->surface_damage, from->surface_damage);
+ cairo_region_union (to->buffer_damage, from->buffer_damage);
+
+ if (from->input_region_set)
+ {
+ if (to->input_region)
+ cairo_region_union (to->input_region, from->input_region);
+ else
+ to->input_region = cairo_region_reference (from->input_region);
+ to->input_region_set = TRUE;
+ }
+
+ if (from->opaque_region_set)
+ {
+ if (to->opaque_region)
+ cairo_region_union (to->opaque_region, from->opaque_region);
+ else
+ to->opaque_region = cairo_region_reference (from->opaque_region);
+ to->opaque_region_set = TRUE;
+ }
+
+ if (from->has_new_geometry)
+ {
+ to->new_geometry = from->new_geometry;
+ to->has_new_geometry = TRUE;
+ }
+
+ if (from->has_new_min_size)
+ {
+ to->new_min_width = from->new_min_width;
+ to->new_min_height = from->new_min_height;
+ to->has_new_min_size = TRUE;
+ }
+
+ if (from->has_new_max_size)
+ {
+ to->new_max_width = from->new_max_width;
+ to->new_max_height = from->new_max_height;
+ to->has_new_max_size = TRUE;
+ }
+
+ if (from->scale > 0)
+ to->scale = from->scale;
+
+ if (to->buffer && to->buffer_destroy_handler_id == 0)
{
to->buffer_destroy_handler_id =
g_signal_connect (to->buffer, "resource-destroyed",
@@ -716,7 +757,7 @@ meta_wayland_surface_commit (MetaWaylandSurface *surface)
* surface is in effective desynchronized mode.
*/
if (meta_wayland_surface_is_effectively_synchronized (surface))
- move_pending_state (surface->pending, surface->sub.pending);
+ merge_pending_state (surface->pending, surface->sub.pending);
else
meta_wayland_surface_apply_pending_state (surface, surface->pending);
}