From 79df40dfaa1e86d8b2ef750e7ae2862238405ea7 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 10 2020 09:52:04 +0000 Subject: import mutter-3.28.3-28.el7 --- diff --git a/SOURCES/0001-cally-Fix-state-set-leak.patch b/SOURCES/0001-cally-Fix-state-set-leak.patch new file mode 100644 index 0000000..44673bf --- /dev/null +++ b/SOURCES/0001-cally-Fix-state-set-leak.patch @@ -0,0 +1,125 @@ +From f5c5f62d9f820b56e81f8b3829aae8195841c755 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 30 Apr 2020 10:23:09 -0400 +Subject: [PATCH 1/4] cally: Fix state set leak + +cally_actor_action_do_action leaks a state set object in the +case where the actor is defunct, insensitive, or hidden. + +This commit plugs the leak. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1225 +--- + clutter/clutter/cally/cally-actor.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/clutter/clutter/cally/cally-actor.c b/clutter/clutter/cally/cally-actor.c +index 77195c0b0..ff6dba14e 100644 +--- a/clutter/clutter/cally/cally-actor.c ++++ b/clutter/clutter/cally/cally-actor.c +@@ -797,92 +797,95 @@ _cally_actor_get_top_level_origin (ClutterActor *actor, + + if (xp) + *xp = x; + + if (yp) + *yp = y; + } + + /* AtkAction implementation */ + static void + cally_actor_action_interface_init (AtkActionIface *iface) + { + g_return_if_fail (iface != NULL); + + iface->do_action = cally_actor_action_do_action; + iface->get_n_actions = cally_actor_action_get_n_actions; + iface->get_description = cally_actor_action_get_description; + iface->get_keybinding = cally_actor_action_get_keybinding; + iface->get_name = cally_actor_action_get_name; + iface->set_description = cally_actor_action_set_description; + } + + static gboolean + cally_actor_action_do_action (AtkAction *action, + gint index) + { + CallyActor *cally_actor = NULL; + AtkStateSet *set = NULL; + CallyActorPrivate *priv = NULL; + CallyActorActionInfo *info = NULL; ++ gboolean did_action = FALSE; + + cally_actor = CALLY_ACTOR (action); + priv = cally_actor->priv; + + set = atk_object_ref_state_set (ATK_OBJECT (cally_actor)); + + if (atk_state_set_contains_state (set, ATK_STATE_DEFUNCT)) +- return FALSE; ++ goto out; + + if (!atk_state_set_contains_state (set, ATK_STATE_SENSITIVE) || + !atk_state_set_contains_state (set, ATK_STATE_SHOWING)) +- return FALSE; +- +- g_object_unref (set); ++ goto out; + + info = _cally_actor_get_action_info (cally_actor, index); + + if (info == NULL) +- return FALSE; ++ goto out; + + if (info->do_action_func == NULL) +- return FALSE; ++ goto out; + + if (!priv->action_queue) + priv->action_queue = g_queue_new (); + + g_queue_push_head (priv->action_queue, info); + + if (!priv->action_idle_handler) + priv->action_idle_handler = g_idle_add (idle_do_action, cally_actor); + +- return TRUE; ++ did_action = TRUE; ++ ++out: ++ g_clear_object (&set); ++ return did_action; + } + + static gboolean + idle_do_action (gpointer data) + { + CallyActor *cally_actor = NULL; + CallyActorPrivate *priv = NULL; + ClutterActor *actor = NULL; + + cally_actor = CALLY_ACTOR (data); + priv = cally_actor->priv; + actor = CALLY_GET_CLUTTER_ACTOR (cally_actor); + priv->action_idle_handler = 0; + + if (actor == NULL) /* state is defunct*/ + return FALSE; + + while (!g_queue_is_empty (priv->action_queue)) + { + CallyActorActionInfo *info = NULL; + + info = (CallyActorActionInfo *) g_queue_pop_head (priv->action_queue); + + info->do_action_func (cally_actor, info->user_data); + } + + return FALSE; + } + + static gint +-- +2.26.2 + diff --git a/SOURCES/0001-cogl-Use-autopointers-to-free-structs-on-return.patch b/SOURCES/0001-cogl-Use-autopointers-to-free-structs-on-return.patch new file mode 100644 index 0000000..2a4aa6d --- /dev/null +++ b/SOURCES/0001-cogl-Use-autopointers-to-free-structs-on-return.patch @@ -0,0 +1,267 @@ +From a5fa286732b08b832ea642347963cb0456c1e19f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 9 Jul 2019 11:13:09 +0200 +Subject: [PATCH 01/28] cogl: Use autopointers to free structs on return + +This is a potential leak discovered by static analysis, in fact if +_COGL_GET_CONTEXT returns, the newly allocated struct isn't released. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + cogl/cogl-pango/cogl-pango-fontmap.c | 4 ++-- + cogl/cogl/cogl-onscreen.c | 4 +++- + cogl/cogl/cogl-pipeline-cache.c | 4 ++-- + 3 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/cogl/cogl-pango/cogl-pango-fontmap.c b/cogl/cogl-pango/cogl-pango-fontmap.c +index 145f3b9e8..3ec64eee6 100644 +--- a/cogl/cogl-pango/cogl-pango-fontmap.c ++++ b/cogl/cogl-pango/cogl-pango-fontmap.c +@@ -49,72 +49,72 @@ + #include + + #include "cogl-pango.h" + #include "cogl-pango-private.h" + #include "cogl-util.h" + #include "cogl/cogl-context-private.h" + + static GQuark cogl_pango_font_map_get_priv_key (void) G_GNUC_CONST; + + typedef struct _CoglPangoFontMapPriv + { + CoglContext *ctx; + PangoRenderer *renderer; + } CoglPangoFontMapPriv; + + static void + free_priv (gpointer data) + { + CoglPangoFontMapPriv *priv = data; + + cogl_object_unref (priv->ctx); + cogl_object_unref (priv->renderer); + + g_free (priv); + } + + PangoFontMap * + cogl_pango_font_map_new (void) + { + PangoFontMap *fm = pango_cairo_font_map_new (); +- CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1); ++ g_autofree CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1); + + _COGL_GET_CONTEXT (context, NULL); + + priv->ctx = cogl_object_ref (context); + + /* XXX: The public pango api doesn't let us sub-class + * PangoCairoFontMap so we attach our own private data using qdata + * for now. */ + g_object_set_qdata_full (G_OBJECT (fm), + cogl_pango_font_map_get_priv_key (), +- priv, ++ g_steal_pointer (&priv), + free_priv); + + return fm; + } + + PangoContext * + cogl_pango_font_map_create_context (CoglPangoFontMap *fm) + { + _COGL_RETURN_VAL_IF_FAIL (COGL_PANGO_IS_FONT_MAP (fm), NULL); + + #if PANGO_VERSION_CHECK (1, 22, 0) + /* We can just directly use the pango context from the Cairo font + map */ + return pango_font_map_create_context (PANGO_FONT_MAP (fm)); + #else + return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fm)); + #endif + } + + static CoglPangoFontMapPriv * + _cogl_pango_font_map_get_priv (CoglPangoFontMap *fm) + { + return g_object_get_qdata (G_OBJECT (fm), + cogl_pango_font_map_get_priv_key ()); + } + + PangoRenderer * + _cogl_pango_font_map_get_renderer (CoglPangoFontMap *fm) + { + CoglPangoFontMapPriv *priv = _cogl_pango_font_map_get_priv (fm); +diff --git a/cogl/cogl/cogl-onscreen.c b/cogl/cogl/cogl-onscreen.c +index e766e59d0..fcf7f4168 100644 +--- a/cogl/cogl/cogl-onscreen.c ++++ b/cogl/cogl/cogl-onscreen.c +@@ -72,64 +72,66 @@ COGL_GTYPE_DEFINE_BOXED (FrameClosure, frame_closure, + cogl_dummy_free); + COGL_GTYPE_DEFINE_BOXED (OnscreenResizeClosure, + onscreen_resize_closure, + cogl_dummy_copy, + cogl_dummy_free); + COGL_GTYPE_DEFINE_BOXED (OnscreenDirtyClosure, + onscreen_dirty_closure, + cogl_dummy_copy, + cogl_dummy_free); + + static void + _cogl_onscreen_init_from_template (CoglOnscreen *onscreen, + CoglOnscreenTemplate *onscreen_template) + { + CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen); + + _cogl_list_init (&onscreen->frame_closures); + _cogl_list_init (&onscreen->resize_closures); + _cogl_list_init (&onscreen->dirty_closures); + + framebuffer->config = onscreen_template->config; + cogl_object_ref (framebuffer->config.swap_chain); + } + + /* XXX: While we still have backend in Clutter we need a dummy object + * to represent the CoglOnscreen framebuffer that the backend + * creates... */ + CoglOnscreen * + _cogl_onscreen_new (void) + { +- CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1); ++ g_autofree CoglOnscreen *onscreen_ptr = g_new0 (CoglOnscreen, 1); ++ CoglOnscreen *onscreen; + + _COGL_GET_CONTEXT (ctx, NULL); + ++ onscreen = g_steal_pointer (&onscreen_ptr); + _cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen), + ctx, + COGL_FRAMEBUFFER_TYPE_ONSCREEN, + 0x1eadbeef, /* width */ + 0x1eadbeef); /* height */ + /* NB: make sure to pass positive width/height numbers here + * because otherwise we'll hit input validation assertions!*/ + + _cogl_onscreen_init_from_template (onscreen, ctx->display->onscreen_template); + + COGL_FRAMEBUFFER (onscreen)->allocated = TRUE; + + /* XXX: Note we don't initialize onscreen->winsys in this case. */ + + return _cogl_onscreen_object_new (onscreen); + } + + CoglOnscreen * + cogl_onscreen_new (CoglContext *ctx, int width, int height) + { + CoglOnscreen *onscreen; + + /* FIXME: We are assuming onscreen buffers will always be + premultiplied so we'll set the premult flag on the bitmap + format. This will usually be correct because the result of the + default blending operations for Cogl ends up with premultiplied + data in the framebuffer. However it is possible for the + framebuffer to be in whatever format depending on what + CoglPipeline is used to render to it. Eventually we may want to + add a way for an application to inform Cogl that the framebuffer +diff --git a/cogl/cogl/cogl-pipeline-cache.c b/cogl/cogl/cogl-pipeline-cache.c +index 62b372406..4267d2ccb 100644 +--- a/cogl/cogl/cogl-pipeline-cache.c ++++ b/cogl/cogl/cogl-pipeline-cache.c +@@ -25,91 +25,91 @@ + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + * Authors: + * Neil Roberts + * Robert Bragg + */ + + #ifdef HAVE_CONFIG_H + #include "cogl-config.h" + #endif + + #include + + #include "cogl-context-private.h" + #include "cogl-pipeline-private.h" + #include "cogl-pipeline-cache.h" + #include "cogl-pipeline-hash-table.h" + + struct _CoglPipelineCache + { + CoglPipelineHashTable fragment_hash; + CoglPipelineHashTable vertex_hash; + CoglPipelineHashTable combined_hash; + }; + + CoglPipelineCache * + _cogl_pipeline_cache_new (void) + { +- CoglPipelineCache *cache = g_new (CoglPipelineCache, 1); ++ g_autofree CoglPipelineCache *cache = g_new (CoglPipelineCache, 1); + unsigned long vertex_state; + unsigned long layer_vertex_state; + unsigned int fragment_state; + unsigned int layer_fragment_state; + + _COGL_GET_CONTEXT (ctx, 0); + + vertex_state = + _cogl_pipeline_get_state_for_vertex_codegen (ctx); + layer_vertex_state = + COGL_PIPELINE_LAYER_STATE_AFFECTS_VERTEX_CODEGEN; + fragment_state = + _cogl_pipeline_get_state_for_fragment_codegen (ctx); + layer_fragment_state = + _cogl_pipeline_get_layer_state_for_fragment_codegen (ctx); + + _cogl_pipeline_hash_table_init (&cache->vertex_hash, + vertex_state, + layer_vertex_state, + "vertex shaders"); + _cogl_pipeline_hash_table_init (&cache->fragment_hash, + fragment_state, + layer_fragment_state, + "fragment shaders"); + _cogl_pipeline_hash_table_init (&cache->combined_hash, + vertex_state | fragment_state, + layer_vertex_state | layer_fragment_state, + "programs"); + +- return cache; ++ return g_steal_pointer (&cache); + } + + void + _cogl_pipeline_cache_free (CoglPipelineCache *cache) + { + _cogl_pipeline_hash_table_destroy (&cache->fragment_hash); + _cogl_pipeline_hash_table_destroy (&cache->vertex_hash); + _cogl_pipeline_hash_table_destroy (&cache->combined_hash); + g_free (cache); + } + + CoglPipelineCacheEntry * + _cogl_pipeline_cache_get_fragment_template (CoglPipelineCache *cache, + CoglPipeline *key_pipeline) + { + return _cogl_pipeline_hash_table_get (&cache->fragment_hash, + key_pipeline); + } + + CoglPipelineCacheEntry * + _cogl_pipeline_cache_get_vertex_template (CoglPipelineCache *cache, + CoglPipeline *key_pipeline) + { + return _cogl_pipeline_hash_table_get (&cache->vertex_hash, + key_pipeline); + } + + CoglPipelineCacheEntry * + _cogl_pipeline_cache_get_combined_template (CoglPipelineCache *cache, + CoglPipeline *key_pipeline) +-- +2.26.2 + diff --git a/SOURCES/0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch b/SOURCES/0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch new file mode 100644 index 0000000..d2f2c55 --- /dev/null +++ b/SOURCES/0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch @@ -0,0 +1,199 @@ +From 599d5241c927ecc716dd5c45f3bf447701161980 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 9 Jun 2020 19:07:47 +0200 +Subject: [PATCH 1/2] stack-tracker: Fix coding style of meta_stack_op_apply() + +Change tabs to spaces, clean up variable declarations. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1300 +--- + src/core/stack-tracker.c | 142 +++++++++++++++++++++------------------ + 1 file changed, 76 insertions(+), 66 deletions(-) + +diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c +index 82afd644a5..8f0164692f 100644 +--- a/src/core/stack-tracker.c ++++ b/src/core/stack-tracker.c +@@ -356,103 +356,113 @@ move_window_above (GArray *stack, + static gboolean + meta_stack_op_apply (MetaStackTracker *tracker, + MetaStackOp *op, +- GArray *stack, ++ GArray *stack, + ApplyFlags apply_flags) + { + switch (op->any.type) + { + case STACK_OP_ADD: + { ++ int old_pos; ++ + if (META_STACK_ID_IS_X11 (op->add.window) && + (apply_flags & NO_RESTACK_X_WINDOWS) != 0) + return FALSE; + +- int old_pos = find_window (stack, op->add.window); +- if (old_pos >= 0) +- { +- g_warning ("STACK_OP_ADD: window %s already in stack", +- get_window_desc (tracker, op->add.window)); +- return FALSE; +- } ++ old_pos = find_window (stack, op->add.window); ++ if (old_pos >= 0) ++ { ++ g_warning ("STACK_OP_ADD: window %s already in stack", ++ get_window_desc (tracker, op->add.window)); ++ return FALSE; ++ } + +- g_array_append_val (stack, op->add.window); +- return TRUE; ++ g_array_append_val (stack, op->add.window); ++ return TRUE; + } + case STACK_OP_REMOVE: + { ++ int old_pos; ++ + if (META_STACK_ID_IS_X11 (op->remove.window) && + (apply_flags & NO_RESTACK_X_WINDOWS) != 0) + return FALSE; + +- int old_pos = find_window (stack, op->remove.window); +- if (old_pos < 0) +- { +- g_warning ("STACK_OP_REMOVE: window %s not in stack", +- get_window_desc (tracker, op->remove.window)); +- return FALSE; +- } ++ old_pos = find_window (stack, op->remove.window); ++ if (old_pos < 0) ++ { ++ g_warning ("STACK_OP_REMOVE: window %s not in stack", ++ get_window_desc (tracker, op->remove.window)); ++ return FALSE; ++ } + +- g_array_remove_index (stack, old_pos); +- return TRUE; ++ g_array_remove_index (stack, old_pos); ++ return TRUE; + } + case STACK_OP_RAISE_ABOVE: + { +- int old_pos = find_window (stack, op->raise_above.window); +- int above_pos; +- if (old_pos < 0) +- { +- g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack", +- get_window_desc (tracker, op->raise_above.window)); +- return FALSE; +- } ++ int old_pos; ++ int above_pos; ++ ++ old_pos = find_window (stack, op->raise_above.window); ++ if (old_pos < 0) ++ { ++ g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack", ++ get_window_desc (tracker, op->raise_above.window)); ++ return FALSE; ++ } + + if (op->raise_above.sibling) +- { +- above_pos = find_window (stack, op->raise_above.sibling); +- if (above_pos < 0) +- { +- g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack", ++ { ++ above_pos = find_window (stack, op->raise_above.sibling); ++ if (above_pos < 0) ++ { ++ g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack", + get_window_desc (tracker, op->raise_above.sibling)); +- return FALSE; +- } +- } +- else +- { +- above_pos = -1; +- } +- +- return move_window_above (stack, op->raise_above.window, old_pos, above_pos, ++ return FALSE; ++ } ++ } ++ else ++ { ++ above_pos = -1; ++ } ++ ++ return move_window_above (stack, op->raise_above.window, old_pos, above_pos, + apply_flags); + } + case STACK_OP_LOWER_BELOW: + { +- int old_pos = find_window (stack, op->lower_below.window); +- int above_pos; +- if (old_pos < 0) +- { +- g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack", +- get_window_desc (tracker, op->lower_below.window)); +- return FALSE; +- } ++ int old_pos; ++ int above_pos; ++ ++ old_pos = find_window (stack, op->raise_above.window); ++ if (old_pos < 0) ++ { ++ g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack", ++ get_window_desc (tracker, op->lower_below.window)); ++ return FALSE; ++ } + + if (op->lower_below.sibling) +- { +- int below_pos = find_window (stack, op->lower_below.sibling); +- if (below_pos < 0) +- { +- g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack", +- get_window_desc (tracker, op->lower_below.sibling)); +- return FALSE; +- } +- +- above_pos = below_pos - 1; +- } +- else +- { +- above_pos = stack->len - 1; +- } +- +- return move_window_above (stack, op->lower_below.window, old_pos, above_pos, ++ { ++ int below_pos; ++ ++ below_pos = find_window (stack, op->lower_below.sibling); ++ if (below_pos < 0) ++ { ++ g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack", ++ get_window_desc (tracker, op->lower_below.sibling)); ++ return FALSE; ++ } ++ ++ above_pos = below_pos - 1; ++ } ++ else ++ { ++ above_pos = stack->len - 1; ++ } ++ ++ return move_window_above (stack, op->lower_below.window, old_pos, above_pos, + apply_flags); + } + } +-- +2.26.2 + diff --git a/SOURCES/0002-barriers-Fix-leak-in-meta_barrier_destroy.patch b/SOURCES/0002-barriers-Fix-leak-in-meta_barrier_destroy.patch new file mode 100644 index 0000000..af09d5c --- /dev/null +++ b/SOURCES/0002-barriers-Fix-leak-in-meta_barrier_destroy.patch @@ -0,0 +1,86 @@ +From 574e832f20c8c3f278709531083a03b190f1adfa Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 25 Sep 2020 14:04:31 -0400 +Subject: [PATCH 2/4] barriers: Fix leak in meta_barrier_destroy + +meta_barrier_destroy is responsible for removing the extra +reference added in meta_barrier_constructed. + +Unfortunately, it fails to do this because of a misplaced early +return statement. + +This commit removes the spurious return. +--- + src/backends/meta-barrier.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/backends/meta-barrier.c b/src/backends/meta-barrier.c +index a1e1180fe..2353ef150 100644 +--- a/src/backends/meta-barrier.c ++++ b/src/backends/meta-barrier.c +@@ -264,61 +264,61 @@ meta_barrier_class_init (MetaBarrierClass *klass) + G_TYPE_NONE, 1, + META_TYPE_BARRIER_EVENT); + + /** + * MetaBarrier::left: + * @barrier: The #MetaBarrier that was left + * @event: A #MetaBarrierEvent that has the details of how + * the barrier was left. + * + * When a pointer barrier hitbox was left, this will trigger. + * This requires an XI2-enabled server. + */ + obj_signals[LEFT] = + g_signal_new ("left", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 1, + META_TYPE_BARRIER_EVENT); + + g_type_class_add_private (object_class, sizeof(MetaBarrierPrivate)); + } + + void + meta_barrier_destroy (MetaBarrier *barrier) + { + MetaBarrierImpl *impl = barrier->priv->impl; + + if (impl) +- return META_BARRIER_IMPL_GET_CLASS (impl)->destroy (impl); ++ META_BARRIER_IMPL_GET_CLASS (impl)->destroy (impl); + + g_object_unref (barrier); + } + + static void + meta_barrier_init (MetaBarrier *barrier) + { + barrier->priv = G_TYPE_INSTANCE_GET_PRIVATE (barrier, META_TYPE_BARRIER, MetaBarrierPrivate); + } + + void + _meta_barrier_emit_hit_signal (MetaBarrier *barrier, + MetaBarrierEvent *event) + { + g_signal_emit (barrier, obj_signals[HIT], 0, event); + } + + void + _meta_barrier_emit_left_signal (MetaBarrier *barrier, + MetaBarrierEvent *event) + { + g_signal_emit (barrier, obj_signals[LEFT], 0, event); + } + + static void + meta_barrier_impl_class_init (MetaBarrierImplClass *klass) + { + klass->is_active = NULL; + klass->release = NULL; + klass->destroy = NULL; +-- +2.26.2 + diff --git a/SOURCES/0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch b/SOURCES/0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch new file mode 100644 index 0000000..7fa1cf4 --- /dev/null +++ b/SOURCES/0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch @@ -0,0 +1,215 @@ +From 758ede11d0967b38eba75241fb5dadb395f29617 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 9 Jul 2019 14:45:48 +0200 +Subject: [PATCH 02/28] cogl: Define autoptr cleanup functions for Cogl types + +Make possible to use g_autoptr () with Cogl types + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + cogl/cogl/Makefile.am | 1 + + cogl/cogl/cogl-autocleanups.h | 67 +++++++++++++++++++++++++++++++++++ + cogl/cogl/cogl.h | 2 ++ + 3 files changed, 70 insertions(+) + create mode 100644 cogl/cogl/cogl-autocleanups.h + +diff --git a/cogl/cogl/Makefile.am b/cogl/cogl/Makefile.am +index 66accf709..ecb5e8b59 100644 +--- a/cogl/cogl/Makefile.am ++++ b/cogl/cogl/Makefile.am +@@ -38,60 +38,61 @@ endif + AM_CFLAGS = $(COGL_DEP_CFLAGS) $(COGL_EXTRA_CFLAGS) $(MAINTAINER_CFLAGS) + + BUILT_SOURCES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h + DISTCLEANFILES += cogl-defines.h cogl-egl-defines.h cogl-gl-header.h + EXTRA_DIST += cogl-defines.h.in cogl-egl-defines.h.in cogl-gl-header.h.in + + pc_files = mutter-cogl-$(LIBMUTTER_API_VERSION).pc + + pkgconfigdir = $(libdir)/pkgconfig + pkgconfig_DATA = $(pc_files) + + DISTCLEANFILES += $(pc_files) + + cogl_deprecated_h = \ + deprecated/cogl-material-compat.h \ + deprecated/cogl-vertex-buffer.h \ + deprecated/cogl-shader.h \ + deprecated/cogl-clutter.h \ + deprecated/cogl-type-casts.h \ + deprecated/cogl-auto-texture.h \ + $(NULL) + + cogl_deprecated_nonintrospected_h = \ + deprecated/cogl-framebuffer-deprecated.h \ + $(NULL) + + # public 1.x api headers + cogl_1_public_h = \ + $(cogl_deprecated_h) \ + cogl1-context.h \ ++ cogl-autocleanups.h \ + cogl-bitmap.h \ + cogl-color.h \ + cogl-matrix.h \ + cogl-offscreen.h \ + cogl-primitives.h \ + cogl-texture.h \ + cogl-types.h \ + cogl.h \ + $(NULL) + + cogl_nonintrospected_h = \ + cogl-object.h \ + cogl-renderer.h \ + cogl-swap-chain.h \ + cogl-onscreen-template.h \ + cogl-display.h \ + cogl-context.h \ + cogl-pipeline.h \ + cogl-pipeline-state.h \ + cogl-pipeline-layer-state.h \ + cogl-snippet.h \ + cogl-gles2.h \ + cogl-gles2-types.h \ + cogl-index-buffer.h \ + cogl-attribute-buffer.h \ + cogl-indices.h \ + cogl-attribute.h \ + cogl-primitive.h \ + cogl-framebuffer.h \ + cogl-onscreen.h \ +diff --git a/cogl/cogl/cogl-autocleanups.h b/cogl/cogl/cogl-autocleanups.h +new file mode 100644 +index 000000000..f18002418 +--- /dev/null ++++ b/cogl/cogl/cogl-autocleanups.h +@@ -0,0 +1,67 @@ ++/* ++ * Cogl ++ * ++ * A Low Level GPU Graphics and Utilities API ++ * ++ * Copyright (C) 2009 Intel Corporation. ++ * Copyright (C) 2019 Canonical Ltd. ++ * ++ * Permission is hereby granted, free of charge, to any person ++ * obtaining a copy of this software and associated documentation ++ * files (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, ++ * modify, merge, publish, distribute, sublicense, and/or sell copies ++ * of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be ++ * included in all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ++ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS ++ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ++ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++ * SOFTWARE. ++ * ++ */ ++ ++#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION) ++#error "Only can be included directly." ++#endif ++ ++#ifndef __COGL_AUTOCLEANUPS_H__ ++#define __COGL_AUTOCLEANUPS_H__ ++ ++#ifndef __GI_SCANNER__ ++ ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglAtlasTexture, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglAttribute, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglAttributeBuffer, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglBitmap, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglColor, cogl_color_free) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglDisplay, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglEuler, cogl_euler_free) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglFramebuffer, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglIndices, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglHandle, cogl_handle_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglMatrix, cogl_matrix_free) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglMatrixEntry, cogl_matrix_entry_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglMatrixStack, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglObject, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglOffscreen, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglOnscreenTemplate, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglPath, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglPipeline, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglQuaternion, cogl_quaternion_free) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglRenderer, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglSnippet, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglTexture, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglTexture2D, cogl_object_unref) ++G_DEFINE_AUTOPTR_CLEANUP_FUNC (CoglTexture2DSliced, cogl_object_unref) ++ ++#endif /* __GI_SCANNER__ */ ++ ++#endif /* __COGL_AUTOCLEANUPS_H__ */ +diff --git a/cogl/cogl/cogl.h b/cogl/cogl/cogl.h +index 5210e3c59..c7cf7e6a8 100644 +--- a/cogl/cogl/cogl.h ++++ b/cogl/cogl/cogl.h +@@ -127,51 +127,53 @@ + #include + #include + #include + #include + /* XXX: This will definitly go away once all the Clutter winsys + * code has been migrated down into Cogl! */ + #include + + /* + * API deprecations + */ + #include + + /* + * Cogl Path api compatability + * + * The cogl_path_ api used to be part of the core Cogl api so for + * compatability we include cogl-path.h via cogl.h + * + * Note: we have to make sure not to include cogl-path.h while + * building core cogl or generating the Cogl .gir data because + * cogl-path now gets built after cogl and some cogl-path headers are + * only generated at build time... + */ + #if defined (COGL_HAS_COGL_PATH_SUPPORT) && \ + !defined (COGL_COMPILATION) && \ + !defined (COGL_GIR_SCANNING) + #include + #endif + ++#include ++ + /** + * SECTION:cogl + * @short_description: General purpose API + * + * General utility functions for COGL. + */ + + /* The gobject introspection scanner seems to parse public headers in + * isolation which means we need to be extra careful about how we + * define and undefine __COGL_H_INSIDE__ used to detect when internal + * headers are incorrectly included by developers. In the gobject + * introspection case we have to manually define __COGL_H_INSIDE__ as + * a commandline argument for the scanner which means we must be + * careful not to undefine it in a header... + */ + #ifdef __COGL_MUST_UNDEF_COGL_H_INSIDE__ + #undef __COGL_H_INSIDE__ + #undef __COGL_MUST_UNDEF_COGL_H_INSIDE__ + #endif + + #endif /* __COGL_H__ */ +-- +2.26.2 + diff --git a/SOURCES/0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch b/SOURCES/0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch new file mode 100644 index 0000000..a550cce --- /dev/null +++ b/SOURCES/0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch @@ -0,0 +1,98 @@ +From 58ff94c8d008ff2df35f014df24a1937cdc962ae Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 9 Jun 2020 19:09:00 +0200 +Subject: [PATCH 2/2] stack-tracker: Don't log warnings on race conditions + +X11 window stacking operations are by nature prone to race conditions. +For example, we might queue a "raise above" operation, but before it +actually takes place, the sibling the window was to be rased above, is +withdrawn. + +In these cases we'd log warnings even though they are expected to +happen. Downgrade these warnings to debug messages, only printed when +MUTTER_VERBOSE is set. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1300 +--- + src/core/stack-tracker.c | 30 ++++++++++++++++++------------ + 1 file changed, 18 insertions(+), 12 deletions(-) + +diff --git a/src/core/stack-tracker.c b/src/core/stack-tracker.c +index 8f0164692f..37fd20fc59 100644 +--- a/src/core/stack-tracker.c ++++ b/src/core/stack-tracker.c +@@ -372,8 +372,9 @@ meta_stack_op_apply (MetaStackTracker *tracker, + old_pos = find_window (stack, op->add.window); + if (old_pos >= 0) + { +- g_warning ("STACK_OP_ADD: window %s already in stack", +- get_window_desc (tracker, op->add.window)); ++ meta_topic (META_DEBUG_STACK, ++ "STACK_OP_ADD: window %s already in stack", ++ get_window_desc (tracker, op->add.window)); + return FALSE; + } + +@@ -391,8 +392,9 @@ meta_stack_op_apply (MetaStackTracker *tracker, + old_pos = find_window (stack, op->remove.window); + if (old_pos < 0) + { +- g_warning ("STACK_OP_REMOVE: window %s not in stack", +- get_window_desc (tracker, op->remove.window)); ++ meta_topic (META_DEBUG_STACK, ++ "STACK_OP_REMOVE: window %s not in stack", ++ get_window_desc (tracker, op->remove.window)); + return FALSE; + } + +@@ -407,8 +409,9 @@ meta_stack_op_apply (MetaStackTracker *tracker, + old_pos = find_window (stack, op->raise_above.window); + if (old_pos < 0) + { +- g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack", +- get_window_desc (tracker, op->raise_above.window)); ++ meta_topic (META_DEBUG_STACK, ++ "STACK_OP_RAISE_ABOVE: window %s not in stack", ++ get_window_desc (tracker, op->raise_above.window)); + return FALSE; + } + +@@ -417,8 +420,9 @@ meta_stack_op_apply (MetaStackTracker *tracker, + above_pos = find_window (stack, op->raise_above.sibling); + if (above_pos < 0) + { +- g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack", +- get_window_desc (tracker, op->raise_above.sibling)); ++ meta_topic (META_DEBUG_STACK, ++ "STACK_OP_RAISE_ABOVE: sibling window %s not in stack", ++ get_window_desc (tracker, op->raise_above.sibling)); + return FALSE; + } + } +@@ -438,8 +442,9 @@ meta_stack_op_apply (MetaStackTracker *tracker, + old_pos = find_window (stack, op->raise_above.window); + if (old_pos < 0) + { +- g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack", +- get_window_desc (tracker, op->lower_below.window)); ++ meta_topic (META_DEBUG_STACK, ++ "STACK_OP_LOWER_BELOW: window %s not in stack", ++ get_window_desc (tracker, op->lower_below.window)); + return FALSE; + } + +@@ -450,8 +455,9 @@ meta_stack_op_apply (MetaStackTracker *tracker, + below_pos = find_window (stack, op->lower_below.sibling); + if (below_pos < 0) + { +- g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack", +- get_window_desc (tracker, op->lower_below.sibling)); ++ meta_topic (META_DEBUG_STACK, ++ "STACK_OP_LOWER_BELOW: sibling window %s not in stack", ++ get_window_desc (tracker, op->lower_below.sibling)); + return FALSE; + } + +-- +2.26.2 + diff --git a/SOURCES/0003-barriers-Free-backend-implementation-at-dispose-time.patch b/SOURCES/0003-barriers-Free-backend-implementation-at-dispose-time.patch new file mode 100644 index 0000000..cdf21de --- /dev/null +++ b/SOURCES/0003-barriers-Free-backend-implementation-at-dispose-time.patch @@ -0,0 +1,96 @@ +From ba76ed7d519a45b7f9b331a28e0617b919c9805e Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 25 Sep 2020 14:04:31 -0400 +Subject: [PATCH 3/4] barriers: Free backend implementation at dispose time + +When a MetaBarrier is first created it allocates a backend +impl object which does the actual heavy lifting. + +Unfortunately, that backend object is never freed. + +This commit ensures the implementation gets freed when +the barrier object is freed. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1451 +--- + src/backends/meta-barrier.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/backends/meta-barrier.c b/src/backends/meta-barrier.c +index 2353ef150..65abf7cab 100644 +--- a/src/backends/meta-barrier.c ++++ b/src/backends/meta-barrier.c +@@ -94,67 +94,70 @@ meta_barrier_set_property (GObject *object, + { + case PROP_DISPLAY: + priv->display = g_value_get_object (value); + break; + case PROP_X1: + priv->border.line.a.x = g_value_get_int (value); + break; + case PROP_Y1: + priv->border.line.a.y = g_value_get_int (value); + break; + case PROP_X2: + priv->border.line.b.x = g_value_get_int (value); + break; + case PROP_Y2: + priv->border.line.b.y = g_value_get_int (value); + break; + case PROP_DIRECTIONS: + meta_border_set_allows_directions (&priv->border, + g_value_get_flags (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + } + + static void + meta_barrier_dispose (GObject *object) + { + MetaBarrier *barrier = META_BARRIER (object); ++ MetaBarrierPrivate *priv = barrier->priv; + + if (meta_barrier_is_active (barrier)) + { + meta_bug ("MetaBarrier %p was destroyed while it was still active.", + barrier); + } + ++ g_clear_object (&priv->impl); ++ + G_OBJECT_CLASS (meta_barrier_parent_class)->dispose (object); + } + + gboolean + meta_barrier_is_active (MetaBarrier *barrier) + { + MetaBarrierImpl *impl = barrier->priv->impl; + + if (impl) + return META_BARRIER_IMPL_GET_CLASS (impl)->is_active (impl); + else + return FALSE; + } + + /** + * meta_barrier_release: + * @barrier: The barrier to release + * @event: The event to release the pointer for + * + * In XI2.3, pointer barriers provide a feature where they can + * be temporarily released so that the pointer goes through + * them. Pass a #MetaBarrierEvent to release the barrier for + * this event sequence. + */ + void + meta_barrier_release (MetaBarrier *barrier, + MetaBarrierEvent *event) + { + MetaBarrierImpl *impl = barrier->priv->impl; + +-- +2.26.2 + diff --git a/SOURCES/0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch b/SOURCES/0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch new file mode 100644 index 0000000..f71de9a --- /dev/null +++ b/SOURCES/0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch @@ -0,0 +1,91 @@ +From 7e516f6348505c28c48aed8d21e6194cd1d5cee1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 9 Jul 2019 16:12:33 +0200 +Subject: [PATCH 03/28] cogl/vertex-buffer: Don't try to use free'd data + +set_attribute_enable might try to warn using cogl_attribute_name after that has +been free'd. + +Avoid this using an auto-pointer. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + cogl/cogl/deprecated/cogl-vertex-buffer.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/cogl/cogl/deprecated/cogl-vertex-buffer.c b/cogl/cogl/deprecated/cogl-vertex-buffer.c +index cf6e51ea2..59381dc56 100644 +--- a/cogl/cogl/deprecated/cogl-vertex-buffer.c ++++ b/cogl/cogl/deprecated/cogl-vertex-buffer.c +@@ -590,66 +590,65 @@ cogl_vertex_buffer_delete (CoglHandle handle, + + /* The submit function works by diffing between submitted_attributes + * and new_attributes to minimize the upload bandwidth + cost of + * allocating new VBOs, so if there isn't already a list of new_attributes + * we create one: */ + if (!buffer->new_attributes) + buffer->new_attributes = copy_submitted_attributes_list (buffer); + + for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) + { + CoglVertexBufferAttrib *submitted_attribute = tmp->data; + if (submitted_attribute->name == name) + { + buffer->new_attributes = + g_list_delete_link (buffer->new_attributes, tmp); + _cogl_vertex_buffer_attrib_free (submitted_attribute); + return; + } + } + + g_warning ("Failed to find an attribute named %s to delete\n", + attribute_name); + } + + static void + set_attribute_enable (CoglHandle handle, + const char *attribute_name, + CoglBool state) + { + CoglVertexBuffer *buffer; +- char *cogl_attribute_name = canonize_attribute_name (attribute_name); ++ g_autofree char *cogl_attribute_name = ++ canonize_attribute_name (attribute_name); + GQuark name_quark = g_quark_from_string (cogl_attribute_name); + GList *tmp; + +- g_free (cogl_attribute_name); +- + if (!cogl_is_vertex_buffer (handle)) + return; + + buffer = handle; + buffer->dirty_attributes = TRUE; + + /* NB: If a buffer is currently being edited, then there can be two seperate + * lists of attributes; those that are currently submitted and a new list yet + * to be submitted, we need to modify both. */ + + for (tmp = buffer->new_attributes; tmp != NULL; tmp = tmp->next) + { + CoglVertexBufferAttrib *attribute = tmp->data; + if (attribute->name == name_quark) + { + if (state) + attribute->flags |= COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; + else + attribute->flags &= ~COGL_VERTEX_BUFFER_ATTRIB_FLAG_ENABLED; + break; + } + } + + for (tmp = buffer->submitted_vbos; tmp != NULL; tmp = tmp->next) + { + CoglVertexBufferVBO *cogl_vbo = tmp->data; + GList *tmp2; + + for (tmp2 = cogl_vbo->attributes; tmp2 != NULL; tmp2 = tmp2->next) + { +-- +2.26.2 + diff --git a/SOURCES/0004-cogl-onscreen-template-Unref-the-swap-chain.patch b/SOURCES/0004-cogl-onscreen-template-Unref-the-swap-chain.patch new file mode 100644 index 0000000..0e2b381 --- /dev/null +++ b/SOURCES/0004-cogl-onscreen-template-Unref-the-swap-chain.patch @@ -0,0 +1,83 @@ +From bc80ae3c807287597da8c673447311807ae4ce15 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 10 Jul 2019 15:38:56 +0200 +Subject: [PATCH 04/28] cogl/onscreen-template: Unref the swap chain + +Each onscreen template owns a swap chain, but this is not released once on free + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + cogl/cogl/cogl-onscreen-template.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/cogl/cogl/cogl-onscreen-template.c b/cogl/cogl/cogl-onscreen-template.c +index 1adbf4128..6ca176755 100644 +--- a/cogl/cogl/cogl-onscreen-template.c ++++ b/cogl/cogl/cogl-onscreen-template.c +@@ -22,60 +22,63 @@ + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Robert Bragg + */ + + #ifdef HAVE_CONFIG_H + #include "cogl-config.h" + #endif + + #include "cogl-object.h" + + #include "cogl-framebuffer-private.h" + #include "cogl-onscreen-template-private.h" + #include "cogl-gtype-private.h" + + #include + + static void _cogl_onscreen_template_free (CoglOnscreenTemplate *onscreen_template); + + COGL_OBJECT_DEFINE (OnscreenTemplate, onscreen_template); + COGL_GTYPE_DEFINE_CLASS (OnscreenTemplate, onscreen_template); + + static void + _cogl_onscreen_template_free (CoglOnscreenTemplate *onscreen_template) + { ++ if (onscreen_template->config.swap_chain) ++ cogl_object_unref (onscreen_template->config.swap_chain); ++ + g_slice_free (CoglOnscreenTemplate, onscreen_template); + } + + CoglOnscreenTemplate * + cogl_onscreen_template_new (CoglSwapChain *swap_chain) + { + CoglOnscreenTemplate *onscreen_template = g_slice_new0 (CoglOnscreenTemplate); + char *user_config; + + onscreen_template->config.swap_chain = swap_chain; + if (swap_chain) + cogl_object_ref (swap_chain); + else + onscreen_template->config.swap_chain = cogl_swap_chain_new (); + + onscreen_template->config.swap_throttled = TRUE; + onscreen_template->config.need_stencil = TRUE; + onscreen_template->config.samples_per_pixel = 0; + + user_config = getenv ("COGL_POINT_SAMPLES_PER_PIXEL"); + if (user_config) + { + unsigned long samples_per_pixel = strtoul (user_config, NULL, 10); + if (samples_per_pixel != ULONG_MAX) + onscreen_template->config.samples_per_pixel = + samples_per_pixel; + } + + return _cogl_onscreen_template_object_new (onscreen_template); + } +-- +2.26.2 + diff --git a/SOURCES/0004-src-Export-MetaWaylandX11-to-introspection.patch b/SOURCES/0004-src-Export-MetaWaylandX11-to-introspection.patch new file mode 100644 index 0000000..773b02c --- /dev/null +++ b/SOURCES/0004-src-Export-MetaWaylandX11-to-introspection.patch @@ -0,0 +1,79 @@ +From a2e8cf329ba80ea43864829f8d95f3e2b751e579 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 14 Oct 2020 14:20:33 -0400 +Subject: [PATCH 4/4] src: Export MetaWaylandX11 to introspection + +This avoids a harmless warning at startup for gnome-shell +--- + src/Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/Makefile.am b/src/Makefile.am +index 8b21d2f6c..56761727e 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -535,60 +535,61 @@ libmutterinclude_headers = \ + meta/errors.h \ + meta/group.h \ + meta/keybindings.h \ + meta/main.h \ + meta/meta-backend.h \ + meta/meta-background.h \ + meta/meta-background-actor.h \ + meta/meta-background-image.h \ + meta/meta-background-group.h \ + meta/meta-close-dialog.h \ + meta/meta-inhibit-shortcuts-dialog.h \ + meta/meta-cursor-tracker.h \ + meta/meta-dnd.h \ + meta/meta-idle-monitor.h \ + meta/meta-plugin.h \ + meta/meta-monitor-manager.h \ + meta/meta-settings.h \ + meta/meta-shaped-texture.h \ + meta/meta-shadow-factory.h \ + meta/meta-stage.h \ + meta/meta-window-actor.h \ + meta/meta-window-group.h \ + meta/meta-window-shape.h \ + meta/prefs.h \ + meta/screen.h \ + meta/theme.h \ + meta/types.h \ + meta/util.h \ + meta/window.h \ + meta/workspace.h \ ++ x11/window-x11.h \ + $(NULL) + + libmutterinclude_built_headers = \ + meta/meta-version.h \ + meta/meta-enum-types.h \ + $(NULL) + + libmutterinclude_base_headers = \ + $(libmutterinclude_headers) \ + $(libmutterinclude_built_headers) + + libmutterincludedir = $(includedir)/mutter/meta + + libmutterinclude_HEADERS = \ + $(libmutterinclude_headers) + + nodist_libmutterinclude_HEADERS = \ + $(libmutterinclude_built_headers) + + bin_PROGRAMS=mutter + noinst_PROGRAMS= + + mutter_SOURCES = core/mutter.c + mutter_LDADD = $(MUTTER_LIBS) libmutter-@LIBMUTTER_API_VERSION@.la + + libexec_PROGRAMS = mutter-restart-helper + mutter_restart_helper_SOURCES = core/restart-helper.c + mutter_restart_helper_LDADD = $(MUTTER_LIBS) + + include Makefile-tests.am +-- +2.26.2 + diff --git a/SOURCES/0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch b/SOURCES/0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch new file mode 100644 index 0000000..7891953 --- /dev/null +++ b/SOURCES/0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch @@ -0,0 +1,87 @@ +From cec68590283dd7f9905695c8f52dc7d93d8f2350 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 24 Jul 2019 16:45:15 +0200 +Subject: [PATCH 05/28] cogl/framebuffer: Unref the config swap chain if set + +When initializing an onscreen through _cogl_onscreen_init_from_template, we set +the framebuffer config swap_chain and ref it. +However we don't unref it on destruction. + +So, unref it if set when freeing the framebuffer + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + cogl/cogl/cogl-framebuffer.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c +index 6b105087d..3a107a2e2 100644 +--- a/cogl/cogl/cogl-framebuffer.c ++++ b/cogl/cogl/cogl-framebuffer.c +@@ -168,60 +168,63 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer, + ctx->framebuffers = g_list_prepend (ctx->framebuffers, framebuffer); + } + + void + _cogl_framebuffer_set_internal_format (CoglFramebuffer *framebuffer, + CoglPixelFormat internal_format) + { + framebuffer->internal_format = internal_format; + } + + void + _cogl_framebuffer_free (CoglFramebuffer *framebuffer) + { + CoglContext *ctx = framebuffer->context; + + _cogl_fence_cancel_fences_for_framebuffer (framebuffer); + + _cogl_clip_stack_unref (framebuffer->clip_stack); + + cogl_object_unref (framebuffer->modelview_stack); + framebuffer->modelview_stack = NULL; + + cogl_object_unref (framebuffer->projection_stack); + framebuffer->projection_stack = NULL; + + cogl_object_unref (framebuffer->journal); + + if (ctx->viewport_scissor_workaround_framebuffer == framebuffer) + ctx->viewport_scissor_workaround_framebuffer = NULL; + ++ if (framebuffer->config.swap_chain) ++ cogl_object_unref (framebuffer->config.swap_chain); ++ + ctx->framebuffers = g_list_remove (ctx->framebuffers, framebuffer); + + if (ctx->current_draw_buffer == framebuffer) + ctx->current_draw_buffer = NULL; + if (ctx->current_read_buffer == framebuffer) + ctx->current_read_buffer = NULL; + } + + const CoglWinsysVtable * + _cogl_framebuffer_get_winsys (CoglFramebuffer *framebuffer) + { + return framebuffer->context->display->renderer->winsys_vtable; + } + + /* This version of cogl_clear can be used internally as an alternative + * to avoid flushing the journal or the framebuffer state. This is + * needed when doing operations that may be called whiling flushing + * the journal */ + void + _cogl_framebuffer_clear_without_flush4f (CoglFramebuffer *framebuffer, + unsigned long buffers, + float red, + float green, + float blue, + float alpha) + { + CoglContext *ctx = framebuffer->context; + + if (!buffers) + { +-- +2.26.2 + diff --git a/SOURCES/0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch b/SOURCES/0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch new file mode 100644 index 0000000..e3e0a64 --- /dev/null +++ b/SOURCES/0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch @@ -0,0 +1,105 @@ +From bfd1c16e87cf9f90e8fe039b4bab400c68fb68a2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 24 Jul 2019 16:49:38 +0200 +Subject: [PATCH 06/28] clutter/backend: Use an auto-pointer to handle the + template on creation + +We allocate a CoglOnscreenTemplate but this is not unreffed if we have an error, +so let's just use an auto-pointer to manage its lifecycle. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-backend.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c +index 30ebe5ef1..69aeec5eb 100644 +--- a/clutter/clutter/clutter-backend.c ++++ b/clutter/clutter/clutter-backend.c +@@ -234,81 +234,79 @@ clutter_backend_do_real_create_context (ClutterBackend *backend, + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + + swap_chain = NULL; + internal_error = NULL; + + CLUTTER_NOTE (BACKEND, "Creating Cogl renderer"); + backend->cogl_renderer = klass->get_renderer (backend, &internal_error); + + if (backend->cogl_renderer == NULL) + goto error; + + CLUTTER_NOTE (BACKEND, "Connecting the renderer"); + cogl_renderer_set_driver (backend->cogl_renderer, driver_id); + if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error)) + goto error; + + CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain"); + swap_chain = cogl_swap_chain_new (); + + CLUTTER_NOTE (BACKEND, "Creating Cogl display"); + if (klass->get_display != NULL) + { + backend->cogl_display = klass->get_display (backend, + backend->cogl_renderer, + swap_chain, + &internal_error); + } + else + { +- CoglOnscreenTemplate *tmpl; ++ g_autoptr (CoglOnscreenTemplate) tmpl = NULL; + gboolean res; + + tmpl = cogl_onscreen_template_new (swap_chain); + + /* XXX: I have some doubts that this is a good design. + * + * Conceptually should we be able to check an onscreen_template + * without more details about the CoglDisplay configuration? + */ + res = cogl_renderer_check_onscreen_template (backend->cogl_renderer, + tmpl, + &internal_error); + + if (!res) + goto error; + +- backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl); +- + /* the display owns the template */ +- cogl_object_unref (tmpl); ++ backend->cogl_display = cogl_display_new (backend->cogl_renderer, tmpl); + } + + if (backend->cogl_display == NULL) + goto error; + + #ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT + cogl_wayland_display_set_compositor_display (backend->cogl_display, + _wayland_compositor_display); + #endif + + CLUTTER_NOTE (BACKEND, "Setting up the display"); + if (!cogl_display_setup (backend->cogl_display, &internal_error)) + goto error; + + CLUTTER_NOTE (BACKEND, "Creating the Cogl context"); + backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error); + if (backend->cogl_context == NULL) + goto error; + + /* the display owns the renderer and the swap chain */ + cogl_object_unref (backend->cogl_renderer); + cogl_object_unref (swap_chain); + + return TRUE; + + error: + if (backend->cogl_display != NULL) + { + cogl_object_unref (backend->cogl_display); + backend->cogl_display = NULL; +-- +2.26.2 + diff --git a/SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch b/SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch new file mode 100644 index 0000000..3905c2a --- /dev/null +++ b/SOURCES/0007-clutter-Keep-a-device-reference-with-events.patch @@ -0,0 +1,284 @@ +From dfd79cf19dcebf283bd884dded8efc83e449016d Mon Sep 17 00:00:00 2001 +From: Olivier Fourdan +Date: Mon, 19 Nov 2018 11:25:57 +0100 +Subject: [PATCH 07/28] clutter: Keep a device reference with events + +If a device (virtual or real) is removed while there are remaining +events queued for that device, the event loop may try to access the +event freed memory. + +To avoid the issue, add a reference to the device when the event is +created or copied, and remove the reference once the device is freed. + +Closes: https://gitlab.gnome.org/GNOME/mutter/issues/393 +--- + clutter/clutter/clutter-event.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c +index 10b6c0082..1b21b6a97 100644 +--- a/clutter/clutter/clutter-event.c ++++ b/clutter/clutter/clutter-event.c +@@ -1068,61 +1068,61 @@ clutter_event_get_device_type (const ClutterEvent *event) + + g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE); + + device = clutter_event_get_device (event); + if (device != NULL) + return clutter_input_device_get_device_type (device); + + return CLUTTER_POINTER_DEVICE; + } + + /** + * clutter_event_set_device: + * @event: a #ClutterEvent + * @device: (allow-none): a #ClutterInputDevice, or %NULL + * + * Sets the device for @event. + * + * Since: 1.6 + */ + void + clutter_event_set_device (ClutterEvent *event, + ClutterInputDevice *device) + { + g_return_if_fail (event != NULL); + g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device)); + + if (is_event_allocated (event)) + { + ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; + +- real_event->device = device; ++ g_set_object (&real_event->device, device); + } + + switch (event->type) + { + case CLUTTER_NOTHING: + case CLUTTER_STAGE_STATE: + case CLUTTER_DESTROY_NOTIFY: + case CLUTTER_CLIENT_MESSAGE: + case CLUTTER_DELETE: + case CLUTTER_EVENT_LAST: + break; + + case CLUTTER_ENTER: + case CLUTTER_LEAVE: + event->crossing.device = device; + break; + + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + event->button.device = device; + break; + + case CLUTTER_MOTION: + event->motion.device = device; + break; + + case CLUTTER_SCROLL: + event->scroll.device = device; + break; + +@@ -1337,62 +1337,62 @@ clutter_event_new (ClutterEventType type) + return new_event; + } + + /** + * clutter_event_copy: + * @event: A #ClutterEvent. + * + * Copies @event. + * + * Return value: (transfer full): A newly allocated #ClutterEvent + */ + ClutterEvent * + clutter_event_copy (const ClutterEvent *event) + { + ClutterEvent *new_event; + ClutterEventPrivate *new_real_event; + ClutterInputDevice *device; + gint n_axes = 0; + + g_return_val_if_fail (event != NULL, NULL); + + new_event = clutter_event_new (CLUTTER_NOTHING); + new_real_event = (ClutterEventPrivate *) new_event; + + *new_event = *event; + + if (is_event_allocated (event)) + { + ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; + +- new_real_event->device = real_event->device; +- new_real_event->source_device = real_event->source_device; ++ g_set_object (&new_real_event->device, real_event->device); ++ g_set_object (&new_real_event->source_device, real_event->source_device); + new_real_event->delta_x = real_event->delta_x; + new_real_event->delta_y = real_event->delta_y; + new_real_event->is_pointer_emulated = real_event->is_pointer_emulated; + new_real_event->base_state = real_event->base_state; + new_real_event->button_state = real_event->button_state; + new_real_event->latched_state = real_event->latched_state; + new_real_event->locked_state = real_event->locked_state; + new_real_event->tool = real_event->tool; + } + + device = clutter_event_get_device (event); + if (device != NULL) + n_axes = clutter_input_device_get_n_axes (device); + + switch (event->type) + { + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + if (event->button.axes != NULL) + new_event->button.axes = g_memdup (event->button.axes, + sizeof (gdouble) * n_axes); + break; + + case CLUTTER_SCROLL: + if (event->scroll.axes != NULL) + new_event->scroll.axes = g_memdup (event->scroll.axes, + sizeof (gdouble) * n_axes); + break; + + case CLUTTER_MOTION: +@@ -1408,60 +1408,68 @@ clutter_event_copy (const ClutterEvent *event) + if (event->touch.axes != NULL) + new_event->touch.axes = g_memdup (event->touch.axes, + sizeof (gdouble) * n_axes); + break; + + default: + break; + } + + if (is_event_allocated (event)) + _clutter_backend_copy_event_data (clutter_get_default_backend (), + event, + new_event); + + return new_event; + } + + /** + * clutter_event_free: + * @event: A #ClutterEvent. + * + * Frees all resources used by @event. + */ + void + clutter_event_free (ClutterEvent *event) + { + if (G_LIKELY (event != NULL)) + { + _clutter_backend_free_event_data (clutter_get_default_backend (), event); + ++ if (is_event_allocated (event)) ++ { ++ ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; ++ ++ g_clear_object (&real_event->device); ++ g_clear_object (&real_event->source_device); ++ } ++ + switch (event->type) + { + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + g_free (event->button.axes); + break; + + case CLUTTER_MOTION: + g_free (event->motion.axes); + break; + + case CLUTTER_SCROLL: + g_free (event->scroll.axes); + break; + + case CLUTTER_TOUCH_BEGIN: + case CLUTTER_TOUCH_UPDATE: + case CLUTTER_TOUCH_END: + case CLUTTER_TOUCH_CANCEL: + g_free (event->touch.axes); + break; + + default: + break; + } + + g_hash_table_remove (all_events, event); + g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event); + } + } +@@ -1662,61 +1670,61 @@ clutter_event_get_source_device (const ClutterEvent *event) + if (real_event->source_device != NULL) + return real_event->source_device; + + return clutter_event_get_device (event); + } + + /** + * clutter_event_set_source_device: + * @event: a #ClutterEvent + * @device: (allow-none): a #ClutterInputDevice + * + * Sets the source #ClutterInputDevice for @event. + * + * The #ClutterEvent must have been created using clutter_event_new(). + * + * Since: 1.8 + */ + void + clutter_event_set_source_device (ClutterEvent *event, + ClutterInputDevice *device) + { + ClutterEventPrivate *real_event; + + g_return_if_fail (event != NULL); + g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device)); + + if (!is_event_allocated (event)) + return; + + real_event = (ClutterEventPrivate *) event; +- real_event->source_device = device; ++ g_set_object (&real_event->source_device, device); + } + + /** + * clutter_event_get_axes: + * @event: a #ClutterEvent + * @n_axes: (out): return location for the number of axes returned + * + * Retrieves the array of axes values attached to the event. + * + * Return value: (transfer none): an array of axis values + * + * Since: 1.6 + */ + gdouble * + clutter_event_get_axes (const ClutterEvent *event, + guint *n_axes) + { + gdouble *retval = NULL; + guint len = 0; + + switch (event->type) + { + case CLUTTER_NOTHING: + case CLUTTER_STAGE_STATE: + case CLUTTER_DESTROY_NOTIFY: + case CLUTTER_CLIENT_MESSAGE: + case CLUTTER_DELETE: + case CLUTTER_ENTER: + case CLUTTER_LEAVE: + case CLUTTER_KEY_PRESS: +-- +2.26.2 + diff --git a/SOURCES/0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch b/SOURCES/0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch new file mode 100644 index 0000000..aef85ec --- /dev/null +++ b/SOURCES/0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch @@ -0,0 +1,801 @@ +From 1a5275cdb099e3b15f82cabdd55d2eb6c5196c39 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 11 Jul 2019 13:32:01 +0200 +Subject: [PATCH 08/28] clutter/event: Use all-events Hash table as a Set with + auto deletion + +Avoid allocating memory for the value, since we don't use it, just add the key +to the table, and check for its presence. + +Use a custom free function to free the event data and unref the GOBjects, so +that in clutter_event_free we don't have to both check for the event presence +in the set, clear the data and eventually remove it from the table, but we +can just rely on a single g_hash_table_remove() call. + +This required to change the event data free/copy functions signatures so that +we can pass to them the platform data directly, otherwise we might try to call +get_platform_data on an even that has already been removed from the table, and +thus that is not considered allocated anymore, causing a leak. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-backend-private.h | 16 +++---- + clutter/clutter/clutter-backend.c | 21 ++++----- + .../clutter/clutter-device-manager-private.h | 7 ++- + clutter/clutter/clutter-event.c | 45 +++++++++++-------- + .../evdev/clutter-device-manager-evdev.c | 15 +++---- + .../clutter/x11/clutter-device-manager-xi2.c | 17 +++---- + 6 files changed, 60 insertions(+), 61 deletions(-) + +diff --git a/clutter/clutter/clutter-backend-private.h b/clutter/clutter/clutter-backend-private.h +index 864d896a3..2438f83e1 100644 +--- a/clutter/clutter/clutter-backend-private.h ++++ b/clutter/clutter/clutter-backend-private.h +@@ -63,100 +63,98 @@ struct _ClutterBackend + }; + + struct _ClutterBackendClass + { + /*< private >*/ + GObjectClass parent_class; + + /* vfuncs */ + gboolean (* pre_parse) (ClutterBackend *backend, + GError **error); + gboolean (* post_parse) (ClutterBackend *backend, + GError **error); + ClutterStageWindow * (* create_stage) (ClutterBackend *backend, + ClutterStage *wrapper, + GError **error); + void (* init_events) (ClutterBackend *backend); + void (* init_features) (ClutterBackend *backend); + void (* add_options) (ClutterBackend *backend, + GOptionGroup *group); + ClutterFeatureFlags (* get_features) (ClutterBackend *backend); + CoglRenderer * (* get_renderer) (ClutterBackend *backend, + GError **error); + CoglDisplay * (* get_display) (ClutterBackend *backend, + CoglRenderer *renderer, + CoglSwapChain *swap_chain, + GError **error); + gboolean (* create_context) (ClutterBackend *backend, + GError **error); + ClutterDeviceManager *(* get_device_manager) (ClutterBackend *backend); + +- void (* copy_event_data) (ClutterBackend *backend, +- const ClutterEvent *src, +- ClutterEvent *dest); +- void (* free_event_data) (ClutterBackend *backend, +- ClutterEvent *event); ++ gpointer (* copy_event_data) (ClutterBackend *backend, ++ gpointer data); ++ void (* free_event_data) (ClutterBackend *backend, ++ gpointer data); + + gboolean (* translate_event) (ClutterBackend *backend, + gpointer native, + ClutterEvent *event); + + PangoDirection (* get_keymap_direction) (ClutterBackend *backend); + + void (* bell_notify) (ClutterBackend *backend); + + /* signals */ + void (* resolution_changed) (ClutterBackend *backend); + void (* font_changed) (ClutterBackend *backend); + void (* settings_changed) (ClutterBackend *backend); + }; + + ClutterBackend * _clutter_create_backend (void); + + ClutterStageWindow * _clutter_backend_create_stage (ClutterBackend *backend, + ClutterStage *wrapper, + GError **error); + gboolean _clutter_backend_create_context (ClutterBackend *backend, + GError **error); + + void _clutter_backend_add_options (ClutterBackend *backend, + GOptionGroup *group); + gboolean _clutter_backend_pre_parse (ClutterBackend *backend, + GError **error); + gboolean _clutter_backend_post_parse (ClutterBackend *backend, + GError **error); + + void _clutter_backend_init_events (ClutterBackend *backend); +-void _clutter_backend_copy_event_data (ClutterBackend *backend, +- const ClutterEvent *src, +- ClutterEvent *dest); ++gpointer _clutter_backend_copy_event_data (ClutterBackend *backend, ++ const gpointer data); + void _clutter_backend_free_event_data (ClutterBackend *backend, +- ClutterEvent *event); ++ gpointer data); + gboolean _clutter_backend_translate_event (ClutterBackend *backend, + gpointer native, + ClutterEvent *event); + + CLUTTER_AVAILABLE_IN_MUTTER + void _clutter_backend_add_event_translator (ClutterBackend *backend, + ClutterEventTranslator *translator); + + void _clutter_backend_remove_event_translator (ClutterBackend *backend, + ClutterEventTranslator *translator); + + ClutterFeatureFlags _clutter_backend_get_features (ClutterBackend *backend); + + gfloat _clutter_backend_get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc); + gint32 _clutter_backend_get_units_serial (ClutterBackend *backend); + + PangoDirection _clutter_backend_get_keymap_direction (ClutterBackend *backend); + + CLUTTER_AVAILABLE_IN_MUTTER + void _clutter_backend_reset_cogl_framebuffer (ClutterBackend *backend); + + void clutter_set_allowed_drivers (const char *drivers); + + void clutter_try_set_windowing_backend (const char *drivers); + + G_END_DECLS + + #endif /* __CLUTTER_BACKEND_PRIVATE_H__ */ +diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c +index 69aeec5eb..41ea3daed 100644 +--- a/clutter/clutter/clutter-backend.c ++++ b/clutter/clutter/clutter-backend.c +@@ -804,96 +804,97 @@ _clutter_backend_get_features (ClutterBackend *backend) + return klass->get_features (backend); + + return 0; + } + + void + _clutter_backend_init_events (ClutterBackend *backend) + { + ClutterBackendClass *klass; + + g_assert (CLUTTER_IS_BACKEND (backend)); + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + klass->init_events (backend); + } + + gfloat + _clutter_backend_get_units_per_em (ClutterBackend *backend, + PangoFontDescription *font_desc) + { + /* recompute for the font description, but do not cache the result */ + if (font_desc != NULL) + return get_units_per_em (backend, font_desc); + + if (backend->units_per_em < 0) + backend->units_per_em = get_units_per_em (backend, NULL); + + return backend->units_per_em; + } + +-void +-_clutter_backend_copy_event_data (ClutterBackend *backend, +- const ClutterEvent *src, +- ClutterEvent *dest) ++gpointer ++_clutter_backend_copy_event_data (ClutterBackend *backend, ++ gpointer data) + { + ClutterEventExtenderInterface *iface; + ClutterBackendClass *klass; + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager)) + { + iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager); +- iface->copy_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager), +- src, dest); ++ return iface->copy_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager), ++ data); + } + else if (klass->copy_event_data != NULL) +- klass->copy_event_data (backend, src, dest); ++ return klass->copy_event_data (backend, data); ++ ++ return NULL; + } + + void + _clutter_backend_free_event_data (ClutterBackend *backend, +- ClutterEvent *event) ++ gpointer data) + { + ClutterEventExtenderInterface *iface; + ClutterBackendClass *klass; + + klass = CLUTTER_BACKEND_GET_CLASS (backend); + + if (CLUTTER_IS_EVENT_EXTENDER (backend->device_manager)) + { + iface = CLUTTER_EVENT_EXTENDER_GET_IFACE (backend->device_manager); + iface->free_event_data (CLUTTER_EVENT_EXTENDER (backend->device_manager), +- event); ++ data); + } + else if (klass->free_event_data != NULL) +- klass->free_event_data (backend, event); ++ klass->free_event_data (backend, data); + } + + /** + * clutter_get_default_backend: + * + * Retrieves the default #ClutterBackend used by Clutter. The + * #ClutterBackend holds backend-specific configuration options. + * + * Return value: (transfer none): the default backend. You should + * not ref or unref the returned object. Applications should rarely + * need to use this. + * + * Since: 0.4 + */ + ClutterBackend * + clutter_get_default_backend (void) + { + ClutterMainContext *clutter_context; + + clutter_context = _clutter_context_get_default (); + + return clutter_context->backend; + } + + /** + * clutter_backend_set_double_click_time: + * @backend: a #ClutterBackend + * @msec: milliseconds between two button press events + * + * Sets the maximum time between two button press events, used to +diff --git a/clutter/clutter/clutter-device-manager-private.h b/clutter/clutter/clutter-device-manager-private.h +index 2364fd27c..6b2c20c72 100644 +--- a/clutter/clutter/clutter-device-manager-private.h ++++ b/clutter/clutter/clutter-device-manager-private.h +@@ -159,65 +159,64 @@ struct _ClutterInputDeviceClass + ClutterInputDeviceTool *tool); + + gboolean (* is_mode_switch_button) (ClutterInputDevice *device, + guint group, + guint button); + gint (* get_group_n_modes) (ClutterInputDevice *device, + gint group); + + gboolean (* is_grouped) (ClutterInputDevice *device, + ClutterInputDevice *other_device); + + /* Keyboard accessbility */ + void (* process_kbd_a11y_event) (ClutterEvent *event, + ClutterInputDevice *device, + ClutterEmitInputDeviceEvent emit_event_func); + }; + + /* Platform-dependent interface */ + typedef struct _ClutterEventExtender ClutterEventExtender; + typedef struct _ClutterEventExtenderInterface ClutterEventExtenderInterface; + + #define CLUTTER_TYPE_EVENT_EXTENDER (clutter_event_extender_get_type ()) + #define CLUTTER_EVENT_EXTENDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), CLUTTER_TYPE_EVENT_EXTENDER, ClutterEventExtender)) + #define CLUTTER_IS_EVENT_EXTENDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), CLUTTER_TYPE_EVENT_EXTENDER)) + #define CLUTTER_EVENT_EXTENDER_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), CLUTTER_TYPE_EVENT_EXTENDER, ClutterEventExtenderInterface)) + + struct _ClutterEventExtenderInterface + { + GTypeInterface g_iface; + +- void (* copy_event_data) (ClutterEventExtender *event_extender, +- const ClutterEvent *src, +- ClutterEvent *dest); ++ gpointer (* copy_event_data) (ClutterEventExtender *event_extender, ++ gpointer data); + void (* free_event_data) (ClutterEventExtender *event_extender, +- ClutterEvent *event); ++ gpointer data); + }; + + GType clutter_event_extender_get_type (void) G_GNUC_CONST; + + /* device manager */ + void _clutter_device_manager_add_device (ClutterDeviceManager *device_manager, + ClutterInputDevice *device); + void _clutter_device_manager_remove_device (ClutterDeviceManager *device_manager, + ClutterInputDevice *device); + void _clutter_device_manager_update_devices (ClutterDeviceManager *device_manager); + void _clutter_device_manager_select_stage_events (ClutterDeviceManager *device_manager, + ClutterStage *stage); + ClutterBackend *_clutter_device_manager_get_backend (ClutterDeviceManager *device_manager); + + void _clutter_device_manager_compress_motion (ClutterDeviceManager *device_manger, + ClutterEvent *event, + const ClutterEvent *to_discard); + + /* input device */ + gboolean _clutter_input_device_has_sequence (ClutterInputDevice *device, + ClutterEventSequence *sequence); + void _clutter_input_device_add_event_sequence (ClutterInputDevice *device, + ClutterEvent *event); + void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device, + ClutterEvent *event); + void _clutter_input_device_set_coords (ClutterInputDevice *device, + ClutterEventSequence *sequence, + gfloat x, + gfloat y, + ClutterStage *stage); +diff --git a/clutter/clutter/clutter-event.c b/clutter/clutter/clutter-event.c +index 1b21b6a97..60bdd325c 100644 +--- a/clutter/clutter/clutter-event.c ++++ b/clutter/clutter/clutter-event.c +@@ -77,61 +77,73 @@ typedef struct _ClutterEventFilter { + + static GHashTable *all_events = NULL; + + G_DEFINE_BOXED_TYPE (ClutterEvent, clutter_event, + clutter_event_copy, + clutter_event_free); + + static ClutterEventSequence * + clutter_event_sequence_copy (ClutterEventSequence *sequence) + { + /* Nothing to copy here */ + return sequence; + } + + static void + clutter_event_sequence_free (ClutterEventSequence *sequence) + { + /* Nothing to free here */ + } + + G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence, + clutter_event_sequence_copy, + clutter_event_sequence_free); + + static gboolean + is_event_allocated (const ClutterEvent *event) + { + if (all_events == NULL) + return FALSE; + +- return g_hash_table_lookup (all_events, event) != NULL; ++ return g_hash_table_contains (all_events, event); ++} ++ ++static void ++clutter_event_private_data_free (ClutterEvent *event) ++{ ++ ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; ++ ++ _clutter_backend_free_event_data (clutter_get_default_backend (), ++ real_event->platform_data); ++ ++ g_clear_object (&real_event->device); ++ g_clear_object (&real_event->source_device); + } + + /* + * _clutter_event_get_platform_data: + * @event: a #ClutterEvent + * + * Retrieves the pointer to platform-specific data inside an event + * + * Return value: a pointer to platform-specific data + * + * Since: 1.4 + */ + gpointer + _clutter_event_get_platform_data (const ClutterEvent *event) + { + if (!is_event_allocated (event)) + return NULL; + + return ((ClutterEventPrivate *) event)->platform_data; + } + + /*< private > + * _clutter_event_set_platform_data: + * @event: a #ClutterEvent + * @data: a pointer to platform-specific data + * + * Sets the pointer to platform-specific data inside an event + * + * Since: 1.4 + */ +@@ -1303,200 +1315,195 @@ clutter_event_get_device_tool (const ClutterEvent *event) + if (is_event_allocated (event)) + { + ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; + + return real_event->tool; + } + + return NULL; + } + + /** + * clutter_event_new: + * @type: The type of event. + * + * Creates a new #ClutterEvent of the specified type. + * + * Return value: (transfer full): A newly allocated #ClutterEvent. + */ + ClutterEvent * + clutter_event_new (ClutterEventType type) + { + ClutterEvent *new_event; + ClutterEventPrivate *priv; + + priv = g_slice_new0 (ClutterEventPrivate); + + new_event = (ClutterEvent *) priv; + new_event->type = new_event->any.type = type; + + if (G_UNLIKELY (all_events == NULL)) +- all_events = g_hash_table_new (NULL, NULL); ++ { ++ all_events = ++ g_hash_table_new_full (NULL, NULL, ++ (GDestroyNotify) clutter_event_private_data_free, ++ NULL); ++ } + +- g_hash_table_replace (all_events, priv, GUINT_TO_POINTER (1)); ++ g_hash_table_add (all_events, priv); + + return new_event; + } + + /** + * clutter_event_copy: + * @event: A #ClutterEvent. + * + * Copies @event. + * + * Return value: (transfer full): A newly allocated #ClutterEvent + */ + ClutterEvent * + clutter_event_copy (const ClutterEvent *event) + { + ClutterEvent *new_event; + ClutterEventPrivate *new_real_event; + ClutterInputDevice *device; + gint n_axes = 0; + + g_return_val_if_fail (event != NULL, NULL); + + new_event = clutter_event_new (CLUTTER_NOTHING); + new_real_event = (ClutterEventPrivate *) new_event; + + *new_event = *event; + + if (is_event_allocated (event)) + { + ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; + + g_set_object (&new_real_event->device, real_event->device); + g_set_object (&new_real_event->source_device, real_event->source_device); + new_real_event->delta_x = real_event->delta_x; + new_real_event->delta_y = real_event->delta_y; + new_real_event->is_pointer_emulated = real_event->is_pointer_emulated; + new_real_event->base_state = real_event->base_state; + new_real_event->button_state = real_event->button_state; + new_real_event->latched_state = real_event->latched_state; + new_real_event->locked_state = real_event->locked_state; + new_real_event->tool = real_event->tool; ++ new_real_event->platform_data = ++ _clutter_backend_copy_event_data (clutter_get_default_backend (), ++ real_event->platform_data); + } + + device = clutter_event_get_device (event); + if (device != NULL) + n_axes = clutter_input_device_get_n_axes (device); + + switch (event->type) + { + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + if (event->button.axes != NULL) + new_event->button.axes = g_memdup (event->button.axes, + sizeof (gdouble) * n_axes); + break; + + case CLUTTER_SCROLL: + if (event->scroll.axes != NULL) + new_event->scroll.axes = g_memdup (event->scroll.axes, + sizeof (gdouble) * n_axes); + break; + + case CLUTTER_MOTION: + if (event->motion.axes != NULL) + new_event->motion.axes = g_memdup (event->motion.axes, + sizeof (gdouble) * n_axes); + break; + + case CLUTTER_TOUCH_BEGIN: + case CLUTTER_TOUCH_UPDATE: + case CLUTTER_TOUCH_END: + case CLUTTER_TOUCH_CANCEL: + if (event->touch.axes != NULL) + new_event->touch.axes = g_memdup (event->touch.axes, + sizeof (gdouble) * n_axes); + break; + + default: + break; + } + +- if (is_event_allocated (event)) +- _clutter_backend_copy_event_data (clutter_get_default_backend (), +- event, +- new_event); +- + return new_event; + } + + /** + * clutter_event_free: + * @event: A #ClutterEvent. + * + * Frees all resources used by @event. + */ + void + clutter_event_free (ClutterEvent *event) + { + if (G_LIKELY (event != NULL)) + { +- _clutter_backend_free_event_data (clutter_get_default_backend (), event); +- +- if (is_event_allocated (event)) +- { +- ClutterEventPrivate *real_event = (ClutterEventPrivate *) event; +- +- g_clear_object (&real_event->device); +- g_clear_object (&real_event->source_device); +- } +- + switch (event->type) + { + case CLUTTER_BUTTON_PRESS: + case CLUTTER_BUTTON_RELEASE: + g_free (event->button.axes); + break; + + case CLUTTER_MOTION: + g_free (event->motion.axes); + break; + + case CLUTTER_SCROLL: + g_free (event->scroll.axes); + break; + + case CLUTTER_TOUCH_BEGIN: + case CLUTTER_TOUCH_UPDATE: + case CLUTTER_TOUCH_END: + case CLUTTER_TOUCH_CANCEL: + g_free (event->touch.axes); + break; + + default: + break; + } + +- g_hash_table_remove (all_events, event); ++ if (G_LIKELY (all_events)) ++ g_hash_table_remove (all_events, event); ++ + g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event); + } + } + + /** + * clutter_event_get: + * + * Pops an event off the event queue. Applications should not need to call + * this. + * + * Return value: A #ClutterEvent or NULL if queue empty + * + * Since: 0.4 + */ + ClutterEvent * + clutter_event_get (void) + { + ClutterMainContext *context = _clutter_context_get_default (); + + if (context->events_queue == NULL) + return NULL; + + if (g_queue_is_empty (context->events_queue)) + return NULL; + + return g_queue_pop_tail (context->events_queue); + } + + /** + * clutter_event_peek: +diff --git a/clutter/clutter/evdev/clutter-device-manager-evdev.c b/clutter/clutter/evdev/clutter-device-manager-evdev.c +index f2aeda696..11cb4781a 100644 +--- a/clutter/clutter/evdev/clutter-device-manager-evdev.c ++++ b/clutter/clutter/evdev/clutter-device-manager-evdev.c +@@ -128,77 +128,76 @@ static gchar * evdev_seat_id; + + #ifdef CLUTTER_ENABLE_DEBUG + static const char *device_type_str[] = { + "pointer", /* CLUTTER_POINTER_DEVICE */ + "keyboard", /* CLUTTER_KEYBOARD_DEVICE */ + "extension", /* CLUTTER_EXTENSION_DEVICE */ + "joystick", /* CLUTTER_JOYSTICK_DEVICE */ + "tablet", /* CLUTTER_TABLET_DEVICE */ + "touchpad", /* CLUTTER_TOUCHPAD_DEVICE */ + "touchscreen", /* CLUTTER_TOUCHSCREEN_DEVICE */ + "pen", /* CLUTTER_PEN_DEVICE */ + "eraser", /* CLUTTER_ERASER_DEVICE */ + "cursor", /* CLUTTER_CURSOR_DEVICE */ + "pad", /* CLUTTER_PAD_DEVICE */ + }; + #endif /* CLUTTER_ENABLE_DEBUG */ + + /* + * ClutterEventSource management + * + * The device manager is responsible for managing the GSource when devices + * appear and disappear from the system. + */ + + static const char *option_xkb_layout = "us"; + static const char *option_xkb_variant = ""; + static const char *option_xkb_options = ""; + + static void + clutter_device_manager_evdev_copy_event_data (ClutterEventExtender *event_extender, +- const ClutterEvent *src, +- ClutterEvent *dest) ++ gpointer data) + { +- ClutterEventEvdev *event_evdev; ++ ClutterEventEvdev *event_evdev = data; + +- event_evdev = _clutter_event_get_platform_data (src); + if (event_evdev != NULL) +- _clutter_event_set_platform_data (dest, _clutter_event_evdev_copy (event_evdev)); ++ return _clutter_event_evdev_copy (event_evdev); ++ ++ return NULL; + } + + static void + clutter_device_manager_evdev_free_event_data (ClutterEventExtender *event_extender, +- ClutterEvent *event) ++ gpointer data) + { +- ClutterEventEvdev *event_evdev; ++ ClutterEventEvdev *event_evdev = data; + +- event_evdev = _clutter_event_get_platform_data (event); + if (event_evdev != NULL) + _clutter_event_evdev_free (event_evdev); + } + + static void + clutter_device_manager_evdev_event_extender_init (ClutterEventExtenderInterface *iface) + { + iface->copy_event_data = clutter_device_manager_evdev_copy_event_data; + iface->free_event_data = clutter_device_manager_evdev_free_event_data; + } + + /* + * ClutterEventSource for reading input devices + */ + + struct _ClutterEventSource + { + GSource source; + + ClutterDeviceManagerEvdev *manager_evdev; + GPollFD event_poll_fd; + }; + + static void + process_events (ClutterDeviceManagerEvdev *manager_evdev); + + static gboolean + clutter_event_prepare (GSource *source, + gint *timeout) + { +diff --git a/clutter/clutter/x11/clutter-device-manager-xi2.c b/clutter/clutter/x11/clutter-device-manager-xi2.c +index 0718cd975..35e3808e7 100644 +--- a/clutter/clutter/x11/clutter-device-manager-xi2.c ++++ b/clutter/clutter/x11/clutter-device-manager-xi2.c +@@ -63,79 +63,74 @@ static const char *clutter_input_axis_atom_names[] = { + "Abs Tilt Y", /* CLUTTER_INPUT_AXIS_YTILT */ + "Abs Wheel", /* CLUTTER_INPUT_AXIS_WHEEL */ + "Abs Distance", /* CLUTTER_INPUT_AXIS_DISTANCE */ + }; + + #define N_AXIS_ATOMS G_N_ELEMENTS (clutter_input_axis_atom_names) + + enum { + PAD_AXIS_FIRST = 3, /* First axes are always x/y/pressure, ignored in pads */ + PAD_AXIS_STRIP1 = PAD_AXIS_FIRST, + PAD_AXIS_STRIP2, + PAD_AXIS_RING1, + PAD_AXIS_RING2, + }; + + static Atom clutter_input_axis_atoms[N_AXIS_ATOMS] = { 0, }; + + static void clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface); + static void clutter_event_extender_iface_init (ClutterEventExtenderInterface *iface); + + #define clutter_device_manager_xi2_get_type _clutter_device_manager_xi2_get_type + + G_DEFINE_TYPE_WITH_CODE (ClutterDeviceManagerXI2, + clutter_device_manager_xi2, + CLUTTER_TYPE_DEVICE_MANAGER, + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_TRANSLATOR, + clutter_event_translator_iface_init) + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_EVENT_EXTENDER, + clutter_event_extender_iface_init)) + +-static void ++static gpointer + clutter_device_manager_x11_copy_event_data (ClutterEventExtender *event_extender, +- const ClutterEvent *src, +- ClutterEvent *dest) ++ gpointer event_x11) + { +- gpointer event_x11; +- +- event_x11 = _clutter_event_get_platform_data (src); + if (event_x11 != NULL) +- _clutter_event_set_platform_data (dest, _clutter_event_x11_copy (event_x11)); ++ return _clutter_event_x11_copy (event_x11); ++ ++ return NULL; + } + + static void + clutter_device_manager_x11_free_event_data (ClutterEventExtender *event_extender, +- ClutterEvent *event) ++ gpointer event_x11) + { +- gpointer event_x11; +- +- event_x11 = _clutter_event_get_platform_data (event); + if (event_x11 != NULL) + _clutter_event_x11_free (event_x11); + } + + static void + clutter_event_extender_iface_init (ClutterEventExtenderInterface *iface) + { + iface->copy_event_data = clutter_device_manager_x11_copy_event_data; + iface->free_event_data = clutter_device_manager_x11_free_event_data; + } + + static void + translate_valuator_class (Display *xdisplay, + ClutterInputDevice *device, + XIValuatorClassInfo *class) + { + static gboolean atoms_initialized = FALSE; + ClutterInputAxis i, axis = CLUTTER_INPUT_AXIS_IGNORE; + + if (G_UNLIKELY (!atoms_initialized)) + { + XInternAtoms (xdisplay, + (char **) clutter_input_axis_atom_names, N_AXIS_ATOMS, + False, + clutter_input_axis_atoms); + + atoms_initialized = TRUE; + } + + for (i = 0; +-- +2.26.2 + diff --git a/SOURCES/0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch b/SOURCES/0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch new file mode 100644 index 0000000..101d0b5 --- /dev/null +++ b/SOURCES/0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch @@ -0,0 +1,83 @@ +From 80949841b030d5272ae625bc3cca82d2affd09e7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 10 Jul 2019 12:29:26 +0200 +Subject: [PATCH 09/28] clutter/actor: Take the marging boxed type if valid + +We were using a clutter margin boxed type, copying it instead of passing the +ownership, causing a memory leak. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-actor.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c +index 7111d824d..f7b7be0ab 100644 +--- a/clutter/clutter/clutter-actor.c ++++ b/clutter/clutter/clutter-actor.c +@@ -14695,61 +14695,61 @@ clutter_actor_parse_custom_node (ClutterScriptable *scriptable, + "written ClutterScript definitions."); + #endif + + l = parse_behaviours (script, actor, node); + + g_value_init (value, G_TYPE_POINTER); + g_value_set_pointer (value, l); + + retval = TRUE; + } + else if (strcmp (name, "actions") == 0 || + strcmp (name, "constraints") == 0 || + strcmp (name, "effects") == 0) + { + GSList *l; + + l = parse_actor_metas (script, actor, node); + + g_value_init (value, G_TYPE_POINTER); + g_value_set_pointer (value, l); + + retval = TRUE; + } + else if (strcmp (name, "margin") == 0) + { + ClutterMargin *margin = parse_margin (actor, node); + + if (margin) + { + g_value_init (value, CLUTTER_TYPE_MARGIN); +- g_value_set_boxed (value, margin); ++ g_value_take_boxed (value, margin); + retval = TRUE; + } + } + + return retval; + } + + static void + clutter_actor_set_custom_property (ClutterScriptable *scriptable, + ClutterScript *script, + const gchar *name, + const GValue *value) + { + ClutterActor *actor = CLUTTER_ACTOR (scriptable); + + #ifdef CLUTTER_ENABLE_DEBUG + if (G_UNLIKELY (CLUTTER_HAS_DEBUG (SCRIPT))) + { + gchar *tmp = g_strdup_value_contents (value); + + CLUTTER_NOTE (SCRIPT, + "in ClutterActor::set_custom_property('%s') = %s", + name, + tmp); + + g_free (tmp); + } + #endif /* CLUTTER_ENABLE_DEBUG */ + + if (strcmp (name, "rotation") == 0) +-- +2.26.2 + diff --git a/SOURCES/0010-clutter-actor-meta-Notify-when-actor-property-change.patch b/SOURCES/0010-clutter-actor-meta-Notify-when-actor-property-change.patch new file mode 100644 index 0000000..72f0f6a --- /dev/null +++ b/SOURCES/0010-clutter-actor-meta-Notify-when-actor-property-change.patch @@ -0,0 +1,86 @@ +From d4b6d9e3190e2cae30fb5bbc41a76286bbed0214 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Sat, 27 Jul 2019 00:20:55 +0200 +Subject: [PATCH 10/28] clutter/actor-meta: Notify when actor property changed + +The ActorMeta contains an actor property holding the parent actor, however when +it changes no notification is emitted. + +Other tham this, since the set_actor vfunc is called on meta destruction, it +could be a problem if the virtual function is implemented by a Javascript object +since the JS context will try to use it during its disposition. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-actor-meta.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/clutter/clutter/clutter-actor-meta.c b/clutter/clutter/clutter-actor-meta.c +index 085f2f65d..2843ea222 100644 +--- a/clutter/clutter/clutter-actor-meta.c ++++ b/clutter/clutter/clutter-actor-meta.c +@@ -73,60 +73,61 @@ enum + PROP_LAST + }; + + static GParamSpec *obj_props[PROP_LAST]; + + G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterActorMeta, + clutter_actor_meta, + G_TYPE_INITIALLY_UNOWNED) + + static void + on_actor_destroy (ClutterActor *actor, + ClutterActorMeta *meta) + { + meta->priv->actor = NULL; + } + + static void + clutter_actor_meta_real_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) + { + if (meta->priv->actor == actor) + return; + + if (meta->priv->destroy_id != 0) + { + g_signal_handler_disconnect (meta->priv->actor, meta->priv->destroy_id); + meta->priv->destroy_id = 0; + } + + meta->priv->actor = actor; ++ g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ACTOR]); + + if (meta->priv->actor != NULL) + meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy", + G_CALLBACK (on_actor_destroy), + meta); + } + + static void + clutter_actor_meta_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) + { + ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject); + + switch (prop_id) + { + case PROP_NAME: + clutter_actor_meta_set_name (meta, g_value_get_string (value)); + break; + + case PROP_ENABLED: + clutter_actor_meta_set_enabled (meta, g_value_get_boolean (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } + } +-- +2.26.2 + diff --git a/SOURCES/0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch b/SOURCES/0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch new file mode 100644 index 0000000..b8ac9b7 --- /dev/null +++ b/SOURCES/0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch @@ -0,0 +1,90 @@ +From 7a5c4a68c4c80b61566e6c9eeb0e854d5c344dd1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Sat, 27 Jul 2019 00:28:46 +0200 +Subject: [PATCH 11/28] clutter/actor-meta: Unset the actor if disposed, + calling the vfunc + +If the actor owned by an ActorMeta is destroyed we unset its pointer, however +many implementations of this class keep a reference on the pointer, so we should +notify them about the invalid pointer or they might try to reference an invalid +memory location. + +Fix this by changing the destroy callback, unsetting the destroy connection id +and calling _clutter_actor_meta_set_actor() + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-actor-meta.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/clutter/clutter/clutter-actor-meta.c b/clutter/clutter/clutter-actor-meta.c +index 2843ea222..157c1d67e 100644 +--- a/clutter/clutter/clutter-actor-meta.c ++++ b/clutter/clutter/clutter-actor-meta.c +@@ -56,61 +56,62 @@ struct _ClutterActorMetaPrivate + guint destroy_id; + + gchar *name; + + guint is_enabled : 1; + + gint priority; + }; + + enum + { + PROP_0, + + PROP_ACTOR, + PROP_NAME, + PROP_ENABLED, + + PROP_LAST + }; + + static GParamSpec *obj_props[PROP_LAST]; + + G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterActorMeta, + clutter_actor_meta, + G_TYPE_INITIALLY_UNOWNED) + + static void + on_actor_destroy (ClutterActor *actor, + ClutterActorMeta *meta) + { +- meta->priv->actor = NULL; ++ meta->priv->destroy_id = 0; ++ _clutter_actor_meta_set_actor (meta, NULL); + } + + static void + clutter_actor_meta_real_set_actor (ClutterActorMeta *meta, + ClutterActor *actor) + { + if (meta->priv->actor == actor) + return; + + if (meta->priv->destroy_id != 0) + { + g_signal_handler_disconnect (meta->priv->actor, meta->priv->destroy_id); + meta->priv->destroy_id = 0; + } + + meta->priv->actor = actor; + g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ACTOR]); + + if (meta->priv->actor != NULL) + meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy", + G_CALLBACK (on_actor_destroy), + meta); + } + + static void + clutter_actor_meta_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) + { +-- +2.26.2 + diff --git a/SOURCES/0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch b/SOURCES/0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch new file mode 100644 index 0000000..580d4a7 --- /dev/null +++ b/SOURCES/0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch @@ -0,0 +1,91 @@ +From 8f2044e41222e2f5360f7ee7386d4ce0903ed786 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 01:14:37 +0200 +Subject: [PATCH 12/28] clutter/stage-manager: Pause the master clock when all + stages have been removed + +The clutter master clock is used by the stage during redraws, but never +stopped when the last stage is destroyed, potentially causing calls to dead +objects. + +So, set it paused (destroying the underlying GSource) when the last stage is +disposed. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-stage-manager.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/clutter/clutter/clutter-stage-manager.c b/clutter/clutter/clutter-stage-manager.c +index 3a44c8209..185e3e2ce 100644 +--- a/clutter/clutter/clutter-stage-manager.c ++++ b/clutter/clutter/clutter-stage-manager.c +@@ -267,57 +267,65 @@ clutter_stage_manager_list_stages (ClutterStageManager *stage_manager) + /** + * clutter_stage_manager_peek_stages: + * @stage_manager: a #ClutterStageManager + * + * Lists all currently used stages. + * + * Return value: (transfer none) (element-type Clutter.Stage): a pointer + * to the internal list of #ClutterStage objects. The returned list + * is owned by the #ClutterStageManager and should never be modified + * or freed + * + * Since: 1.0 + */ + const GSList * + clutter_stage_manager_peek_stages (ClutterStageManager *stage_manager) + { + return stage_manager->stages; + } + + void + _clutter_stage_manager_add_stage (ClutterStageManager *stage_manager, + ClutterStage *stage) + { + if (g_slist_find (stage_manager->stages, stage)) + { + g_warning ("Trying to add a stage to the list of managed stages, " + "but it is already in it, aborting."); + return; + } + ++ _clutter_master_clock_set_paused (_clutter_master_clock_get_default (), FALSE); ++ + g_object_ref_sink (stage); + + stage_manager->stages = g_slist_append (stage_manager->stages, stage); + + g_signal_emit (stage_manager, manager_signals[STAGE_ADDED], 0, stage); + } + + void + _clutter_stage_manager_remove_stage (ClutterStageManager *stage_manager, + ClutterStage *stage) + { + /* this might be called multiple times from a ::dispose, so it + * needs to just return without warning + */ + if (!g_slist_find (stage_manager->stages, stage)) + return; + + stage_manager->stages = g_slist_remove (stage_manager->stages, stage); + + /* if the default stage is being destroyed then we unset the pointer */ + if (default_stage == stage) + default_stage = NULL; + + g_signal_emit (stage_manager, manager_signals[STAGE_REMOVED], 0, stage); + + g_object_unref (stage); ++ ++ if (!stage_manager->stages) ++ { ++ ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); ++ _clutter_master_clock_set_paused (master_clock, TRUE); ++ } + } +-- +2.26.2 + diff --git a/SOURCES/0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch b/SOURCES/0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch new file mode 100644 index 0000000..72bb350 --- /dev/null +++ b/SOURCES/0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch @@ -0,0 +1,87 @@ +From 19a03c1c2df7e510d3fa1b25eec7840cc5816dfe Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 01:02:34 +0200 +Subject: [PATCH 13/28] cally/stage: Set the keyfocus to NULL if the stage is + focused + +By definition when the key focus is set to NULL we assume that the stage has it, +so in such case avoid keeping track of the stage pointer and setting a weak ref +on it, as it might only cause double-free errors during the stage disposition, +that would lead (via atk) to a cally stage disposition as well. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/cally/cally-stage.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/clutter/clutter/cally/cally-stage.c b/clutter/clutter/cally/cally-stage.c +index 7c100aabf..5638c1bb1 100644 +--- a/clutter/clutter/cally/cally-stage.c ++++ b/clutter/clutter/cally/cally-stage.c +@@ -101,60 +101,63 @@ cally_stage_init (CallyStage *cally_stage) + */ + AtkObject* + cally_stage_new (ClutterActor *actor) + { + GObject *object = NULL; + AtkObject *accessible = NULL; + + g_return_val_if_fail (CLUTTER_IS_STAGE (actor), NULL); + + object = g_object_new (CALLY_TYPE_STAGE, NULL); + + accessible = ATK_OBJECT (object); + atk_object_initialize (accessible, actor); + + return accessible; + } + + static void + cally_stage_notify_key_focus_cb (ClutterStage *stage, + GParamSpec *pspec, + CallyStage *self) + { + ClutterActor *key_focus = NULL; + AtkObject *new = NULL; + + if (self->priv->active == FALSE) + return; + + key_focus = clutter_stage_get_key_focus (stage); + ++ if (key_focus == CLUTTER_ACTOR (stage)) ++ key_focus = NULL; ++ + if (key_focus != self->priv->key_focus) + { + AtkObject *old = NULL; + + if (self->priv->key_focus != NULL) + { + g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus), + (gpointer *) &self->priv->key_focus); + old = clutter_actor_get_accessible (self->priv->key_focus); + } + else + old = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); + + atk_object_notify_state_change (old, + ATK_STATE_FOCUSED, + FALSE); + } + + /* we keep notifying the focus gain without checking previous + * key-focus to avoid some missing events due timing + */ + self->priv->key_focus = key_focus; + + if (key_focus != NULL) + { + /* ensure that if the key focus goes away, the field inside + * CallyStage is reset. see bug: + * + * https://bugzilla.gnome.org/show_bug.cgi?id=692706 + * +-- +2.26.2 + diff --git a/SOURCES/0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch b/SOURCES/0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch new file mode 100644 index 0000000..620ec8b --- /dev/null +++ b/SOURCES/0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch @@ -0,0 +1,243 @@ +From 14c2a8eba29647336ca80ce4ed0afe8352fa8818 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 01:10:02 +0200 +Subject: [PATCH 14/28] cally/stage: Monitor key-focus actor via "destroyed" + signal + +We use a weak pointer for monitoring the state of the key-focused actor, however +actors are considered dead once we get a "destroyed" signal instead (that +happens) before actual GObject disposition. +Also the weak pointer was set twice if the same actor was signaled as +key-focused twice in a row. + +So instead of using weak pointers, connect to the "destroy" signal to nullify +the key_focus actor pointer, and don't connect to the signal multiple times. +Also use a signal handler to manage the connection, that implies less operations +on disconnection. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/cally/cally-stage.c | 53 ++++++++++++++++++++++------- + 1 file changed, 40 insertions(+), 13 deletions(-) + +diff --git a/clutter/clutter/cally/cally-stage.c b/clutter/clutter/cally/cally-stage.c +index 5638c1bb1..147ec72e6 100644 +--- a/clutter/clutter/cally/cally-stage.c ++++ b/clutter/clutter/cally/cally-stage.c +@@ -30,173 +30,200 @@ + * + * Some implementation details: at this moment #CallyStage is used as + * the most similar Window object in this toolkit (ie: emitting window + * related signals), although the real purpose of #ClutterStage is + * being a canvas. Anyway, this is required for applications using + * just clutter, or directly #ClutterStage + */ + #include "clutter-build-config.h" + + #include "cally-stage.h" + #include "cally-actor-private.h" + + /* AtkObject.h */ + static void cally_stage_real_initialize (AtkObject *obj, + gpointer data); + static AtkStateSet* cally_stage_ref_state_set (AtkObject *obj); + + /* AtkWindow */ + static void cally_stage_window_interface_init (AtkWindowIface *iface); + + /* Auxiliar */ + static void cally_stage_activate_cb (ClutterStage *stage, + gpointer data); + static void cally_stage_deactivate_cb (ClutterStage *stage, + gpointer data); + + struct _CallyStagePrivate + { + /* NULL means that the stage will receive the focus */ + ClutterActor *key_focus; ++ gulong key_focus_destroyed_id; + + gboolean active; + }; + + G_DEFINE_TYPE_WITH_CODE (CallyStage, + cally_stage, + CALLY_TYPE_GROUP, + G_ADD_PRIVATE (CallyStage) + G_IMPLEMENT_INTERFACE (ATK_TYPE_WINDOW, + cally_stage_window_interface_init)); + ++static void ++cally_stage_dispose (GObject *object) ++{ ++ CallyStage *self = CALLY_STAGE (object); ++ ++ if (self->priv->key_focus) ++ { ++ if (self->priv->key_focus_destroyed_id) ++ { ++ g_signal_handler_disconnect (self->priv->key_focus, ++ self->priv->key_focus_destroyed_id); ++ self->priv->key_focus_destroyed_id = 0; ++ } ++ ++ self->priv->key_focus = NULL; ++ } ++ ++ G_OBJECT_CLASS (cally_stage_parent_class)->dispose (object); ++} ++ + static void + cally_stage_class_init (CallyStageClass *klass) + { ++ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + + /* AtkObject */ + class->initialize = cally_stage_real_initialize; + class->ref_state_set = cally_stage_ref_state_set; ++ ++ gobject_class->dispose = cally_stage_dispose; + } + + static void + cally_stage_init (CallyStage *cally_stage) + { + CallyStagePrivate *priv = cally_stage_get_instance_private (cally_stage); + + cally_stage->priv = priv; + + priv->active = FALSE; + } + + /** + * cally_stage_new: + * @actor: a #ClutterActor + * + * Creates a new #CallyStage for the given @actor. @actor should be a + * #ClutterStage. + * + * Return value: the newly created #AtkObject + * + * Since: 1.4 + */ + AtkObject* + cally_stage_new (ClutterActor *actor) + { + GObject *object = NULL; + AtkObject *accessible = NULL; + + g_return_val_if_fail (CLUTTER_IS_STAGE (actor), NULL); + + object = g_object_new (CALLY_TYPE_STAGE, NULL); + + accessible = ATK_OBJECT (object); + atk_object_initialize (accessible, actor); + + return accessible; + } + + static void + cally_stage_notify_key_focus_cb (ClutterStage *stage, + GParamSpec *pspec, + CallyStage *self) + { + ClutterActor *key_focus = NULL; + AtkObject *new = NULL; + + if (self->priv->active == FALSE) + return; + + key_focus = clutter_stage_get_key_focus (stage); + + if (key_focus == CLUTTER_ACTOR (stage)) + key_focus = NULL; + + if (key_focus != self->priv->key_focus) + { + AtkObject *old = NULL; + +- if (self->priv->key_focus != NULL) ++ if (self->priv->key_focus != NULL && self->priv->key_focus_destroyed_id) + { +- g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus), +- (gpointer *) &self->priv->key_focus); +- old = clutter_actor_get_accessible (self->priv->key_focus); ++ g_signal_handler_disconnect (self->priv->key_focus, ++ self->priv->key_focus_destroyed_id); ++ self->priv->key_focus_destroyed_id = 0; + } +- else +- old = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); ++ ++ old = clutter_actor_get_accessible (self->priv->key_focus ? ++ self->priv->key_focus : ++ CLUTTER_ACTOR (stage)); + + atk_object_notify_state_change (old, + ATK_STATE_FOCUSED, + FALSE); + } + + /* we keep notifying the focus gain without checking previous + * key-focus to avoid some missing events due timing + */ + self->priv->key_focus = key_focus; + +- if (key_focus != NULL) ++ if (key_focus != NULL && !self->priv->key_focus_destroyed_id) + { + /* ensure that if the key focus goes away, the field inside + * CallyStage is reset. see bug: + * + * https://bugzilla.gnome.org/show_bug.cgi?id=692706 + * + * we remove the weak pointer above. + */ +- g_object_add_weak_pointer (G_OBJECT (self->priv->key_focus), +- (gpointer *) &self->priv->key_focus); +- +- new = clutter_actor_get_accessible (key_focus); ++ self->priv->key_focus_destroyed_id = ++ g_signal_connect_swapped (self->priv->key_focus, "destroy", ++ G_CALLBACK (g_nullify_pointer), ++ &self->priv->key_focus); + } +- else +- new = clutter_actor_get_accessible (CLUTTER_ACTOR (stage)); ++ ++ new = clutter_actor_get_accessible (key_focus ? ++ key_focus : CLUTTER_ACTOR (stage)); + + atk_object_notify_state_change (new, + ATK_STATE_FOCUSED, + TRUE); + } + + static void + cally_stage_real_initialize (AtkObject *obj, + gpointer data) + { + ClutterStage *stage = NULL; + + g_return_if_fail (CALLY_IS_STAGE (obj)); + + ATK_OBJECT_CLASS (cally_stage_parent_class)->initialize (obj, data); + + stage = CLUTTER_STAGE (CALLY_GET_CLUTTER_ACTOR (obj)); + + g_signal_connect (stage, "activate", G_CALLBACK (cally_stage_activate_cb), obj); + g_signal_connect (stage, "deactivate", G_CALLBACK (cally_stage_deactivate_cb), obj); + g_signal_connect (stage, "notify::key-focus", + G_CALLBACK (cally_stage_notify_key_focus_cb), obj); + + atk_object_set_role (obj, ATK_ROLE_WINDOW); + } + + static AtkStateSet* + cally_stage_ref_state_set (AtkObject *obj) + { + CallyStage *cally_stage = NULL; +-- +2.26.2 + diff --git a/SOURCES/0015-group-Free-group-if-returning-early.patch b/SOURCES/0015-group-Free-group-if-returning-early.patch new file mode 100644 index 0000000..d7a0c9e --- /dev/null +++ b/SOURCES/0015-group-Free-group-if-returning-early.patch @@ -0,0 +1,134 @@ +From 12eefc7a5346ef9132afe1a3e929308f70cd5121 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Tue, 9 Jul 2019 11:17:18 +0200 +Subject: [PATCH 15/28] group: Free group if returning early + +If we get an error when fetching the window attributes, the group isn't ever +free'd, so use an autopointer instead, releasing the stolen one. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/x11/group.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/x11/group.c b/src/x11/group.c +index 123b9e153..4fafa28eb 100644 +--- a/src/x11/group.c ++++ b/src/x11/group.c +@@ -10,111 +10,111 @@ + * 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, see . + */ + + /** + * SECTION:group + * @title: MetaGroup + * @short_description: Mutter window groups + * + */ + + #include + #include + #include "group-private.h" + #include "group-props.h" + #include "window-private.h" + #include + #include + + static MetaGroup* + meta_group_new (MetaDisplay *display, + Window group_leader) + { +- MetaGroup *group; ++ g_autofree MetaGroup *group = NULL; + #define N_INITIAL_PROPS 3 + Atom initial_props[N_INITIAL_PROPS]; + int i; + + g_assert (N_INITIAL_PROPS == (int) G_N_ELEMENTS (initial_props)); + + group = g_new0 (MetaGroup, 1); + + group->display = display; + group->windows = NULL; + group->group_leader = group_leader; + group->refcount = 1; /* owned by caller, hash table has only weak ref */ + + xcb_connection_t *xcb_conn = XGetXCBConnection (display->xdisplay); + xcb_generic_error_t *e; + g_autofree xcb_get_window_attributes_reply_t *attrs = + xcb_get_window_attributes_reply (xcb_conn, + xcb_get_window_attributes (xcb_conn, group_leader), + &e); + if (e) + return NULL; + + const uint32_t events[] = { attrs->your_event_mask | XCB_EVENT_MASK_PROPERTY_CHANGE }; + xcb_change_window_attributes (xcb_conn, group_leader, + XCB_CW_EVENT_MASK, events); + + if (display->groups_by_leader == NULL) + display->groups_by_leader = g_hash_table_new (meta_unsigned_long_hash, + meta_unsigned_long_equal); + + g_assert (g_hash_table_lookup (display->groups_by_leader, &group_leader) == NULL); + + g_hash_table_insert (display->groups_by_leader, + &group->group_leader, + group); + + /* Fill these in the order we want them to be gotten */ + i = 0; + initial_props[i++] = display->atom_WM_CLIENT_MACHINE; + initial_props[i++] = display->atom__NET_WM_PID; + initial_props[i++] = display->atom__NET_STARTUP_ID; + g_assert (N_INITIAL_PROPS == i); + + meta_group_reload_properties (group, initial_props, N_INITIAL_PROPS); + + meta_topic (META_DEBUG_GROUPS, + "Created new group with leader 0x%lx\n", + group->group_leader); + +- return group; ++ return g_steal_pointer (&group); + } + + static void + meta_group_unref (MetaGroup *group) + { + g_return_if_fail (group->refcount > 0); + + group->refcount -= 1; + if (group->refcount == 0) + { + meta_topic (META_DEBUG_GROUPS, + "Destroying group with leader 0x%lx\n", + group->group_leader); + + g_assert (group->display->groups_by_leader != NULL); + + g_hash_table_remove (group->display->groups_by_leader, + &group->group_leader); + + /* mop up hash table, this is how it gets freed on display close */ + if (g_hash_table_size (group->display->groups_by_leader) == 0) + { + g_hash_table_destroy (group->display->groups_by_leader); + group->display->groups_by_leader = NULL; + } + + g_free (group->wm_client_machine); + g_free (group->startup_id); + + g_free (group); +-- +2.26.2 + diff --git a/SOURCES/0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch b/SOURCES/0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch new file mode 100644 index 0000000..646ac2b --- /dev/null +++ b/SOURCES/0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch @@ -0,0 +1,82 @@ +From e4221a10d0c7e84d141765948489f264a2ff3105 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 10 Jul 2019 16:06:57 +0200 +Subject: [PATCH 16/28] surface-actor: Destroy the pending damage region on + dispose + +As the region isn't going to be used anymore, we can safely remove it on dispose + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/compositor/meta-surface-actor.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c +index bf8c76f39..6996658ed 100644 +--- a/src/compositor/meta-surface-actor.c ++++ b/src/compositor/meta-surface-actor.c +@@ -80,60 +80,61 @@ meta_surface_actor_pick (ClutterActor *actor, + + rectangles[pos + 0] = rect.x; + rectangles[pos + 1] = rect.y; + rectangles[pos + 2] = rect.x + rect.width; + rectangles[pos + 3] = rect.y + rect.height; + } + + ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ()); + fb = cogl_get_draw_framebuffer (); + + cogl_color_init_from_4ub (&cogl_color, color->red, color->green, color->blue, color->alpha); + + pipeline = cogl_pipeline_new (ctx); + cogl_pipeline_set_color (pipeline, &cogl_color); + cogl_framebuffer_draw_rectangles (fb, pipeline, rectangles, n_rects); + cogl_object_unref (pipeline); + } + + clutter_actor_iter_init (&iter, actor); + + while (clutter_actor_iter_next (&iter, &child)) + clutter_actor_paint (child); + } + + static void + meta_surface_actor_dispose (GObject *object) + { + MetaSurfaceActor *self = META_SURFACE_ACTOR (object); + MetaSurfaceActorPrivate *priv = self->priv; + ++ g_clear_pointer (&priv->pending_damage, cairo_region_destroy); + g_clear_pointer (&priv->input_region, cairo_region_destroy); + + G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object); + } + + static void + meta_surface_actor_class_init (MetaSurfaceActorClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + object_class->dispose = meta_surface_actor_dispose; + actor_class->pick = meta_surface_actor_pick; + + signals[REPAINT_SCHEDULED] = g_signal_new ("repaint-scheduled", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + signals[SIZE_CHANGED] = g_signal_new ("size-changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + g_type_class_add_private (klass, sizeof (MetaSurfaceActorPrivate)); + } +-- +2.26.2 + diff --git a/SOURCES/0017-CrtcMode-Free-the-mode-name-on-finalize.patch b/SOURCES/0017-CrtcMode-Free-the-mode-name-on-finalize.patch new file mode 100644 index 0000000..3d4a28e --- /dev/null +++ b/SOURCES/0017-CrtcMode-Free-the-mode-name-on-finalize.patch @@ -0,0 +1,65 @@ +From 172906f150a15658e2b375340307e3d48b640d42 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 22 Jul 2019 00:04:33 +0200 +Subject: [PATCH 17/28] CrtcMode: Free the mode name on finalize + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-crtc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/backends/meta-crtc.c b/src/backends/meta-crtc.c +index 7ca31ba39..e4da25c5a 100644 +--- a/src/backends/meta-crtc.c ++++ b/src/backends/meta-crtc.c +@@ -36,45 +36,47 @@ meta_crtc_finalize (GObject *object) + { + MetaCrtc *crtc = META_CRTC (object); + + if (crtc->driver_notify) + crtc->driver_notify (crtc); + + G_OBJECT_CLASS (meta_crtc_parent_class)->finalize (object); + } + + static void + meta_crtc_init (MetaCrtc *crtc) + { + } + + static void + meta_crtc_class_init (MetaCrtcClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_crtc_finalize; + } + + static void + meta_crtc_mode_finalize (GObject *object) + { + MetaCrtcMode *crtc_mode = META_CRTC_MODE (object); + + if (crtc_mode->driver_notify) + crtc_mode->driver_notify (crtc_mode); + ++ g_free (crtc_mode->name); ++ + G_OBJECT_CLASS (meta_crtc_mode_parent_class)->finalize (object); + } + + static void + meta_crtc_mode_init (MetaCrtcMode *crtc_mode) + { + } + + static void + meta_crtc_mode_class_init (MetaCrtcModeClass *klass) + { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = meta_crtc_mode_finalize; + } +-- +2.26.2 + diff --git a/SOURCES/0018-monitor-config-manager-Always-free-temporary-region-.patch b/SOURCES/0018-monitor-config-manager-Always-free-temporary-region-.patch new file mode 100644 index 0000000..3b5de4c --- /dev/null +++ b/SOURCES/0018-monitor-config-manager-Always-free-temporary-region-.patch @@ -0,0 +1,162 @@ +From f70261f80302d9f4ffd62f9dbae3d515b5778467 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Sun, 21 Jul 2019 18:18:14 +0200 +Subject: [PATCH 18/28] monitor-config-manager: Always free temporary region on + error + +During the config parsing we are allocating a temporary rectangles region +however in case that we find an error we return prematurely but in some cases +(when not using identical global scale, or when not using adjacent neighbors) +we didn't free the region list before. + +Instead of caring of doing this manually everytime, let's just use an +auto-pointer to manage the region lifecycle. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor-config-manager.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/src/backends/meta-monitor-config-manager.c b/src/backends/meta-monitor-config-manager.c +index cb67e11e7..59a20d449 100644 +--- a/src/backends/meta-monitor-config-manager.c ++++ b/src/backends/meta-monitor-config-manager.c +@@ -1578,134 +1578,129 @@ meta_logical_monitor_configs_have_monitor (GList *logical_monitor_conf + { + MetaLogicalMonitorConfig *logical_monitor_config = l->data; + GList *k; + + for (k = logical_monitor_config->monitor_configs; k; k = k->next) + { + MetaMonitorConfig *monitor_config = k->data; + + if (meta_monitor_spec_equals (monitor_spec, + monitor_config->monitor_spec)) + return TRUE; + } + } + + return FALSE; + } + + static gboolean + meta_monitors_config_is_monitor_enabled (MetaMonitorsConfig *config, + MetaMonitorSpec *monitor_spec) + { + return meta_logical_monitor_configs_have_monitor (config->logical_monitor_configs, + monitor_spec); + } + + gboolean + meta_verify_monitors_config (MetaMonitorsConfig *config, + MetaMonitorManager *monitor_manager, + GError **error) + { ++ g_autoptr (GList) region = NULL; + int min_x, min_y; + gboolean has_primary; +- GList *region; + GList *l; + gboolean global_scale_required; + + if (!config->logical_monitor_configs) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Monitors config incomplete"); + return FALSE; + } + + global_scale_required = + !!(meta_monitor_manager_get_capabilities (monitor_manager) & + META_MONITOR_MANAGER_CAPABILITY_GLOBAL_SCALE_REQUIRED); + + min_x = INT_MAX; + min_y = INT_MAX; +- region = NULL; + has_primary = FALSE; + for (l = config->logical_monitor_configs; l; l = l->next) + { + MetaLogicalMonitorConfig *logical_monitor_config = l->data; + + if (global_scale_required) + { + MetaLogicalMonitorConfig *prev_logical_monitor_config = + l->prev ? l->prev->data : NULL; + + if (prev_logical_monitor_config && + (prev_logical_monitor_config->scale != + logical_monitor_config->scale)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Logical monitor scales must be identical"); + return FALSE; + } + } + + if (meta_rectangle_overlaps_with_region (region, + &logical_monitor_config->layout)) + { +- g_list_free (region); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Logical monitors overlap"); + return FALSE; + } + + if (has_primary && logical_monitor_config->is_primary) + { +- g_list_free (region); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Config contains multiple primary logical monitors"); + return FALSE; + } + else if (logical_monitor_config->is_primary) + { + has_primary = TRUE; + } + + if (!has_adjecent_neighbour (config, logical_monitor_config)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Logical monitors not adjecent"); + return FALSE; + } + + min_x = MIN (logical_monitor_config->layout.x, min_x); + min_y = MIN (logical_monitor_config->layout.y, min_y); + + region = g_list_prepend (region, &logical_monitor_config->layout); + } + +- g_list_free (region); +- + for (l = config->disabled_monitor_specs; l; l = l->next) + { + MetaMonitorSpec *monitor_spec = l->data; + + if (meta_monitors_config_is_monitor_enabled (config, monitor_spec)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Assigned monitor explicitly disabled"); + return FALSE; + } + } + + if (min_x != 0 || min_y != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Logical monitors positions are offset"); + return FALSE; + } + + if (!has_primary) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Config is missing primary logical"); + return FALSE; + } + + return TRUE; + } +-- +2.26.2 + diff --git a/SOURCES/0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch b/SOURCES/0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch new file mode 100644 index 0000000..1b0410d --- /dev/null +++ b/SOURCES/0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch @@ -0,0 +1,116 @@ +From 9de0b3df99d1c2fabe03d06c0e9fdec040aafca8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Mon, 22 Jul 2019 00:05:05 +0200 +Subject: [PATCH 19/28] monitor-config-store: Use autopointers to cleanup parse + context and buffer + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor-config-store.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c +index 770bef734..e24ce707a 100644 +--- a/src/backends/meta-monitor-config-store.c ++++ b/src/backends/meta-monitor-config-store.c +@@ -1060,95 +1060,92 @@ handle_text (GMarkupParseContext *context, + { + g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, + "Invalid mode flag %.*s", (int) text_len, text); + } + + return; + } + + case STATE_MONITOR_UNDERSCANNING: + { + read_bool (text, text_len, + &parser->current_monitor_config->enable_underscanning, + error); + return; + } + } + } + + static const GMarkupParser config_parser = { + .start_element = handle_start_element, + .end_element = handle_end_element, + .text = handle_text + }; + + static gboolean + read_config_file (MetaMonitorConfigStore *config_store, + GFile *file, + MetaMonitorsConfigFlag extra_config_flags, + GError **error) + { +- char *buffer; ++ g_autoptr (GMarkupParseContext) parse_context = NULL; ++ g_autofree char *buffer = NULL; + gsize size; + ConfigParser parser; +- GMarkupParseContext *parse_context; + + if (!g_file_load_contents (file, NULL, &buffer, &size, NULL, error)) + return FALSE; + + parser = (ConfigParser) { + .state = STATE_INITIAL, + .config_store = config_store, + .extra_config_flags = extra_config_flags, + }; + + parse_context = g_markup_parse_context_new (&config_parser, + G_MARKUP_TREAT_CDATA_AS_TEXT | + G_MARKUP_PREFIX_ERROR_POSITION, + &parser, NULL); + if (!g_markup_parse_context_parse (parse_context, buffer, size, error)) + { + g_list_free_full (parser.current_logical_monitor_configs, + (GDestroyNotify) meta_logical_monitor_config_free); + g_clear_pointer (&parser.current_monitor_spec, + meta_monitor_spec_free); + g_free (parser.current_monitor_mode_spec); + g_clear_pointer (&parser.current_monitor_config, + meta_monitor_config_free); + g_clear_pointer (&parser.current_logical_monitor_config, + meta_logical_monitor_config_free); + return FALSE; + } + +- g_markup_parse_context_free (parse_context); +- g_free (buffer); +- + return TRUE; + } + + MetaMonitorsConfig * + meta_monitor_config_store_lookup (MetaMonitorConfigStore *config_store, + MetaMonitorsConfigKey *key) + { + return META_MONITORS_CONFIG (g_hash_table_lookup (config_store->configs, + key)); + } + + static void + append_monitor_spec (GString *buffer, + MetaMonitorSpec *monitor_spec, + const char *indentation) + { + g_string_append_printf (buffer, "%s\n", indentation); + g_string_append_printf (buffer, "%s %s\n", + indentation, + monitor_spec->connector); + g_string_append_printf (buffer, "%s %s\n", + indentation, + monitor_spec->vendor); + g_string_append_printf (buffer, "%s %s\n", + indentation, + monitor_spec->product); + g_string_append_printf (buffer, "%s %s\n", + indentation, + monitor_spec->serial); + g_string_append_printf (buffer, "%s\n", indentation); +-- +2.26.2 + diff --git a/SOURCES/0020-monitor-Free-the-existing-mode-if-replacing-it.patch b/SOURCES/0020-monitor-Free-the-existing-mode-if-replacing-it.patch new file mode 100644 index 0000000..7b3bbd6 --- /dev/null +++ b/SOURCES/0020-monitor-Free-the-existing-mode-if-replacing-it.patch @@ -0,0 +1,85 @@ +From 4020cddaf71e8868c03f0136964a6429af313b54 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 24 Jul 2019 15:40:06 +0200 +Subject: [PATCH 20/28] monitor: Free the existing mode if replacing it + +When adding a mode and replacing it, we need to free it after that we've added +it to the table. Since the mode_ids table has not ownership on the mode id or +on the mode itself, we need to free it once replaced. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c +index 9a412a612..ec583aa13 100644 +--- a/src/backends/meta-monitor.c ++++ b/src/backends/meta-monitor.c +@@ -437,60 +437,63 @@ generate_mode_id (MetaMonitorModeSpec *monitor_mode_spec) + is_interlaced = !!(monitor_mode_spec->flags & META_CRTC_MODE_FLAG_INTERLACE); + g_ascii_dtostr (refresh_rate_str, G_ASCII_DTOSTR_BUF_SIZE, + monitor_mode_spec->refresh_rate); + + return g_strdup_printf ("%dx%d%s@%s", + monitor_mode_spec->width, + monitor_mode_spec->height, + is_interlaced ? "i" : "", + refresh_rate_str); + } + + static gboolean + meta_monitor_add_mode (MetaMonitor *monitor, + MetaMonitorMode *monitor_mode, + gboolean replace) + { + MetaMonitorPrivate *priv = meta_monitor_get_instance_private (monitor); + MetaMonitorMode *existing_mode; + + existing_mode = g_hash_table_lookup (priv->mode_ids, + meta_monitor_mode_get_id (monitor_mode)); + if (existing_mode && !replace) + return FALSE; + + if (existing_mode) + priv->modes = g_list_remove (priv->modes, existing_mode); + + priv->modes = g_list_append (priv->modes, monitor_mode); + g_hash_table_replace (priv->mode_ids, monitor_mode->id, monitor_mode); + ++ if (existing_mode) ++ meta_monitor_mode_free (existing_mode); ++ + return TRUE; + } + + static MetaMonitorModeSpec + meta_monitor_create_spec (MetaMonitor *monitor, + int width, + int height, + MetaCrtcMode *crtc_mode) + { + MetaOutput *output = meta_monitor_get_main_output (monitor); + + if (meta_monitor_transform_is_rotated (output->panel_orientation_transform)) + { + int temp = width; + width = height; + height = temp; + } + + return (MetaMonitorModeSpec) { + .width = width, + .height = height, + .refresh_rate = crtc_mode->refresh_rate, + .flags = crtc_mode->flags & HANDLED_CRTC_MODE_FLAGS + }; + } + + static void + meta_monitor_normal_generate_modes (MetaMonitorNormal *monitor_normal) + { + MetaMonitor *monitor = META_MONITOR (monitor_normal); +-- +2.26.2 + diff --git a/SOURCES/0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch b/SOURCES/0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch new file mode 100644 index 0000000..e39a759 --- /dev/null +++ b/SOURCES/0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch @@ -0,0 +1,86 @@ +From c4c29246f96ff959db7054c60d9aa76fb45b9e91 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 24 Jul 2019 15:41:14 +0200 +Subject: [PATCH 21/28] monitor: Use delete link to free the tiled modes while + iterating + +We iterate over a temporary list of tiled modes when adding them, but the list +isn't free'd during the iteration. + +So use GList's delete_link instead of remove_link. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/backends/meta-monitor.c b/src/backends/meta-monitor.c +index ec583aa13..ff959b3bc 100644 +--- a/src/backends/meta-monitor.c ++++ b/src/backends/meta-monitor.c +@@ -901,61 +901,61 @@ generate_tiled_monitor_modes (MetaMonitorTiled *monitor_tiled) + + main_output = meta_monitor_get_main_output (META_MONITOR (monitor_tiled)); + + for (i = 0; i < main_output->n_modes; i++) + { + MetaCrtcMode *reference_crtc_mode = main_output->modes[i]; + MetaMonitorMode *mode; + gboolean is_preferred; + + if (!is_crtc_mode_tiled (main_output, reference_crtc_mode)) + continue; + + mode = create_tiled_monitor_mode (monitor_tiled, reference_crtc_mode, + &is_preferred); + if (!mode) + continue; + + tiled_modes = g_list_append (tiled_modes, mode); + + if (is_monitor_mode_assigned (monitor, mode)) + monitor_priv->current_mode = mode; + + if (is_preferred) + monitor_priv->preferred_mode = mode; + } + + while ((l = tiled_modes)) + { + MetaMonitorMode *mode = l->data; + +- tiled_modes = g_list_remove_link (tiled_modes, l); ++ tiled_modes = g_list_delete_link (tiled_modes, l); + + if (!meta_monitor_add_mode (monitor, mode, FALSE)) + { + meta_monitor_mode_free (mode); + continue; + } + + if (!monitor_priv->preferred_mode) + { + if (!best_mode || + mode->spec.refresh_rate > best_mode->spec.refresh_rate) + best_mode = mode; + } + } + + if (best_mode) + monitor_priv->preferred_mode = best_mode; + } + + static MetaMonitorMode * + create_untiled_monitor_mode (MetaMonitorTiled *monitor_tiled, + MetaOutput *main_output, + MetaCrtcMode *crtc_mode) + { + MetaMonitor *monitor = META_MONITOR (monitor_tiled); + MetaMonitorPrivate *monitor_priv = + meta_monitor_get_instance_private (monitor); + MetaMonitorModeTiled *mode; + GList *l; + int i; +-- +2.26.2 + diff --git a/SOURCES/0022-monitor-config-store-Check-if-a-config-is-system-one.patch b/SOURCES/0022-monitor-config-store-Check-if-a-config-is-system-one.patch new file mode 100644 index 0000000..3b7cfe0 --- /dev/null +++ b/SOURCES/0022-monitor-config-store-Check-if-a-config-is-system-one.patch @@ -0,0 +1,92 @@ +From 05b226e20e267f1b4368186727e0fbc4b0b43ac6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 24 Jul 2019 17:22:15 +0200 +Subject: [PATCH 22/28] monitor-config-store: Check if a config is system one + before removing it + +On meta_monitor_config_store_remove() we save configs if removing a non-system +config, however we were doing the check after the configuration was removed from +the has table, and then potentially destroyed. Causing a memory error. + +So, do the check before the removal. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor-config-store.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/backends/meta-monitor-config-store.c b/src/backends/meta-monitor-config-store.c +index e24ce707a..7b0b448ea 100644 +--- a/src/backends/meta-monitor-config-store.c ++++ b/src/backends/meta-monitor-config-store.c +@@ -1425,63 +1425,66 @@ maybe_save_configs (MetaMonitorConfigStore *config_store) + /* + * If a custom file is used, it means we are run by the test suite. When this + * is done, avoid replacing the user configuration file with test data, + * except if a custom write file is set as well. + */ + if (!config_store->custom_read_file || config_store->custom_write_file) + meta_monitor_config_store_save (config_store); + } + + static gboolean + is_system_config (MetaMonitorsConfig *config) + { + return !!(config->flags & META_MONITORS_CONFIG_FLAG_SYSTEM_CONFIG); + } + + void + meta_monitor_config_store_add (MetaMonitorConfigStore *config_store, + MetaMonitorsConfig *config) + { + g_hash_table_replace (config_store->configs, + config->key, g_object_ref (config)); + + if (!is_system_config (config)) + maybe_save_configs (config_store); + } + + void + meta_monitor_config_store_remove (MetaMonitorConfigStore *config_store, + MetaMonitorsConfig *config) + { ++ gboolean system_config; ++ ++ system_config = is_system_config (config); + g_hash_table_remove (config_store->configs, config->key); + +- if (!is_system_config (config)) ++ if (!system_config) + maybe_save_configs (config_store); + } + + gboolean + meta_monitor_config_store_set_custom (MetaMonitorConfigStore *config_store, + const char *read_path, + const char *write_path, + GError **error) + { + g_clear_object (&config_store->custom_read_file); + g_clear_object (&config_store->custom_write_file); + g_hash_table_remove_all (config_store->configs); + + config_store->custom_read_file = g_file_new_for_path (read_path); + if (write_path) + config_store->custom_write_file = g_file_new_for_path (write_path); + + return read_config_file (config_store, + config_store->custom_read_file, + META_MONITORS_CONFIG_FLAG_NONE, + error); + } + + int + meta_monitor_config_store_get_config_count (MetaMonitorConfigStore *config_store) + { + return (int) g_hash_table_size (config_store->configs); + } + + MetaMonitorManager * +-- +2.26.2 + diff --git a/SOURCES/0023-monitor-config-migration-Unref-the-new-config-once-a.patch b/SOURCES/0023-monitor-config-migration-Unref-the-new-config-once-a.patch new file mode 100644 index 0000000..15c58b2 --- /dev/null +++ b/SOURCES/0023-monitor-config-migration-Unref-the-new-config-once-a.patch @@ -0,0 +1,120 @@ +From d585e6d6f15122ca58995603cfc67bfeb111b0d8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 01:24:01 +0200 +Subject: [PATCH 23/28] monitor-config-migration: Unref the new config once + added to the store + +When migrating the configurations we've a leak because the config is passed to +the store that takes its ownership via meta_monitor_config_store_add(), but we +never relase the reference of the newly created object. + +So use an auto-pointer to manage the object lifetime when returning. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor-config-migration.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/backends/meta-monitor-config-migration.c b/src/backends/meta-monitor-config-migration.c +index d619dc433..ed6c80184 100644 +--- a/src/backends/meta-monitor-config-migration.c ++++ b/src/backends/meta-monitor-config-migration.c +@@ -1067,94 +1067,93 @@ find_disabled_monitor_specs (MetaLegacyMonitorsConfig *legacy_config) + MetaOutputKey *output_key = &legacy_config->keys[i]; + MetaOutputConfig *output_config = &legacy_config->outputs[i]; + MetaMonitorSpec *monitor_spec; + + if (output_config->enabled) + continue; + + monitor_spec = g_new0 (MetaMonitorSpec, 1); + *monitor_spec = (MetaMonitorSpec) { + .connector = output_key->connector, + .vendor = output_key->vendor, + .product = output_key->product, + .serial = output_key->serial + }; + + disabled_monitors = g_list_prepend (disabled_monitors, monitor_spec); + } + + return disabled_monitors; + } + + static void + migrate_config (gpointer key, + gpointer value, + gpointer user_data) + { + MetaLegacyMonitorsConfig *legacy_config = key; + MetaMonitorConfigStore *config_store = user_data; + MetaMonitorManager *monitor_manager = + meta_monitor_config_store_get_monitor_manager (config_store); ++ g_autoptr (MetaMonitorsConfig) config = NULL; + GList *logical_monitor_configs; + MetaLogicalMonitorLayoutMode layout_mode; + GError *error = NULL; + GList *disabled_monitor_specs; +- MetaMonitorsConfig *config; + + logical_monitor_configs = derive_logical_monitor_configs (legacy_config, + config_store, + &error); + if (!logical_monitor_configs) + { + g_autofree char *config_name = NULL; + + config_name = generate_config_name (legacy_config); + g_warning ("Failed to migrate monitor configuration for %s: %s", + config_name, error->message); + return; + } + + disabled_monitor_specs = find_disabled_monitor_specs (legacy_config); + + layout_mode = META_LOGICAL_MONITOR_LAYOUT_MODE_PHYSICAL; + config = meta_monitors_config_new_full (logical_monitor_configs, + disabled_monitor_specs, + layout_mode, + META_MONITORS_CONFIG_FLAG_MIGRATED); + if (!meta_verify_monitors_config (config, monitor_manager, &error)) + { + g_autofree char *config_name = NULL; + + config_name = generate_config_name (legacy_config); + g_warning ("Ignoring invalid monitor configuration for %s: %s", + config_name, error->message); +- g_object_unref (config); + return; + } + + meta_monitor_config_store_add (config_store, config); + } + + gboolean + meta_migrate_old_monitors_config (MetaMonitorConfigStore *config_store, + GFile *in_file, + GError **error) + { + g_autoptr (GHashTable) configs = NULL; + + configs = load_config_file (in_file, error); + if (!configs) + return FALSE; + + g_hash_table_foreach (configs, migrate_config, config_store); + + return TRUE; + } + + gboolean + meta_migrate_old_user_monitors_config (MetaMonitorConfigStore *config_store, + GError **error) + { + g_autofree char *backup_path = NULL; + g_autoptr (GFile) backup_file = NULL; + g_autofree char *user_file_path = NULL; + g_autoptr (GFile) user_file = NULL; +-- +2.26.2 + diff --git a/SOURCES/0024-monitor-config-migration-Free-the-output-key-on-inva.patch b/SOURCES/0024-monitor-config-migration-Free-the-output-key-on-inva.patch new file mode 100644 index 0000000..7af5917 --- /dev/null +++ b/SOURCES/0024-monitor-config-migration-Free-the-output-key-on-inva.patch @@ -0,0 +1,86 @@ +From c07364d65d3e6353076b02c97ce63dfe00aaedc7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 01:21:28 +0200 +Subject: [PATCH 24/28] monitor-config-migration: Free the output key on + invalid spec + +In create_monitor_config we assume that we take the ownership of the output_key +values, however if we have an early return because an invalid spec is set, we +don't free it. + +So cleanup it on failure, as it happens for other cases. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/backends/meta-monitor-config-migration.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/backends/meta-monitor-config-migration.c b/src/backends/meta-monitor-config-migration.c +index ed6c80184..26393ef02 100644 +--- a/src/backends/meta-monitor-config-migration.c ++++ b/src/backends/meta-monitor-config-migration.c +@@ -655,60 +655,61 @@ load_config_file (GFile *file, + g_free (parser.output_field); + g_hash_table_destroy (parser.configs); + + return NULL; + } + + return parser.configs; + } + + static MetaMonitorConfig * + create_monitor_config (MetaOutputKey *output_key, + MetaOutputConfig *output_config, + int mode_width, + int mode_height, + GError **error) + { + MetaMonitorModeSpec *mode_spec; + MetaMonitorSpec *monitor_spec; + MetaMonitorConfig *monitor_config; + + mode_spec = g_new0 (MetaMonitorModeSpec, 1); + *mode_spec = (MetaMonitorModeSpec) { + .width = mode_width, + .height = mode_height, + .refresh_rate = output_config->refresh_rate + }; + + if (!meta_verify_monitor_mode_spec (mode_spec, error)) + { + g_free (mode_spec); ++ free_output_key (output_key); + return NULL; + } + + monitor_spec = g_new0 (MetaMonitorSpec, 1); + *monitor_spec = (MetaMonitorSpec) { + .connector = output_key->connector, + .vendor = output_key->vendor, + .product = output_key->product, + .serial = output_key->serial + }; + + monitor_config = g_new0 (MetaMonitorConfig, 1); + *monitor_config = (MetaMonitorConfig) { + .monitor_spec = monitor_spec, + .mode_spec = mode_spec, + .enable_underscanning = output_config->is_underscanning + }; + + if (!meta_verify_monitor_config (monitor_config, error)) + { + meta_monitor_config_free (monitor_config); + return NULL; + } + + return monitor_config; + } + + typedef struct _MonitorTile + { + MetaOutputKey *output_key; +-- +2.26.2 + diff --git a/SOURCES/0025-compositor-Use-meta_window_actor_from_window-to-get-.patch b/SOURCES/0025-compositor-Use-meta_window_actor_from_window-to-get-.patch new file mode 100644 index 0000000..0186c8d --- /dev/null +++ b/SOURCES/0025-compositor-Use-meta_window_actor_from_window-to-get-.patch @@ -0,0 +1,532 @@ +From a6d6b14306727692bffdadd09bca239aebc867c4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 02:02:21 +0200 +Subject: [PATCH 25/28] compositor: Use meta_window_actor_from_window to get + the actor + +Use this utility function instead of repeating the cast all the time. + +Also in some case, warn if the returned value isn't valid. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/compositor/compositor.c | 58 +++++++++++++++++++++++++++---------- + 1 file changed, 42 insertions(+), 16 deletions(-) + +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index 799bcddf5..d02926171 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -116,61 +116,64 @@ meta_finish_workspace_switch (MetaCompositor *compositor) + void + meta_switch_workspace_completed (MetaCompositor *compositor) + { + /* FIXME -- must redo stacking order */ + compositor->switch_workspace_in_progress--; + if (compositor->switch_workspace_in_progress < 0) + { + g_warning ("Error in workspace_switch accounting!"); + compositor->switch_workspace_in_progress = 0; + } + + if (!compositor->switch_workspace_in_progress) + meta_finish_workspace_switch (compositor); + } + + void + meta_compositor_destroy (MetaCompositor *compositor) + { + clutter_threads_remove_repaint_func (compositor->pre_paint_func_id); + clutter_threads_remove_repaint_func (compositor->post_paint_func_id); + + if (compositor->have_x11_sync_object) + meta_sync_ring_destroy (); + } + + static void + process_damage (MetaCompositor *compositor, + XDamageNotifyEvent *event, + MetaWindow *window) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ g_return_if_fail (window_actor); ++ + meta_window_actor_process_x11_damage (window_actor, event); + + compositor->frame_has_updated_xsurfaces = TRUE; + } + + /* compat helper */ + static MetaCompositor * + get_compositor_for_screen (MetaScreen *screen) + { + return screen->display->compositor; + } + + /** + * meta_get_stage_for_screen: + * @screen: a #MetaScreen + * + * Returns: (transfer none): The #ClutterStage for the screen + */ + ClutterActor * + meta_get_stage_for_screen (MetaScreen *screen) + { + MetaCompositor *compositor = get_compositor_for_screen (screen); + return compositor->stage; + } + + /** + * meta_get_window_group_for_screen: + * @screen: a #MetaScreen + * + * Returns: (transfer none): The window group corresponding to @screen +@@ -707,135 +710,146 @@ meta_shape_cow_for_window (MetaCompositor *compositor, + meta_window_get_frame_rect (window, &rect); + + window_bounds.x = rect.x; + window_bounds.y = rect.y; + window_bounds.width = rect.width; + window_bounds.height = rect.height; + + meta_screen_get_size (display->screen, &width, &height); + screen_rect.x = 0; + screen_rect.y = 0; + screen_rect.width = width; + screen_rect.height = height; + + output_region = XFixesCreateRegion (xdisplay, &window_bounds, 1); + + XFixesInvertRegion (xdisplay, output_region, &screen_rect, output_region); + XFixesSetWindowShapeRegion (xdisplay, compositor->output, ShapeBounding, 0, 0, output_region); + XFixesDestroyRegion (xdisplay, output_region); + } + } + + static void + set_unredirected_window (MetaCompositor *compositor, + MetaWindow *window) + { + if (compositor->unredirected_window == window) + return; + + if (compositor->unredirected_window != NULL) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window)); ++ MetaWindowActor *window_actor = ++ meta_window_actor_from_window (compositor->unredirected_window); + meta_window_actor_set_unredirected (window_actor, FALSE); + } + + meta_shape_cow_for_window (compositor, window); + compositor->unredirected_window = window; + + if (compositor->unredirected_window != NULL) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window)); ++ MetaWindowActor *window_actor = ++ meta_window_actor_from_window (compositor->unredirected_window); + meta_window_actor_set_unredirected (window_actor, TRUE); + } + } + + void + meta_compositor_add_window (MetaCompositor *compositor, + MetaWindow *window) + { + MetaDisplay *display = compositor->display; + + meta_error_trap_push (display); + + meta_window_actor_new (window); + sync_actor_stacking (compositor); + + meta_error_trap_pop (display); + } + + void + meta_compositor_remove_window (MetaCompositor *compositor, + MetaWindow *window) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ if (!window_actor) ++ return; + + if (compositor->unredirected_window == window) + set_unredirected_window (compositor, NULL); + + meta_window_actor_queue_destroy (window_actor); + } + + void + meta_compositor_sync_updates_frozen (MetaCompositor *compositor, + MetaWindow *window) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ g_return_if_fail (window_actor); ++ + meta_window_actor_sync_updates_frozen (window_actor); + } + + void + meta_compositor_queue_frame_drawn (MetaCompositor *compositor, + MetaWindow *window, + gboolean no_delay_frame) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ g_return_if_fail (window_actor); ++ + meta_window_actor_queue_frame_drawn (window_actor, no_delay_frame); + } + + void + meta_compositor_window_shape_changed (MetaCompositor *compositor, + MetaWindow *window) + { +- MetaWindowActor *window_actor; +- window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ + if (!window_actor) + return; + + meta_window_actor_update_shape (window_actor); + } + + void + meta_compositor_window_opacity_changed (MetaCompositor *compositor, + MetaWindow *window) + { +- MetaWindowActor *window_actor; +- window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ + if (!window_actor) + return; + + meta_window_actor_update_opacity (window_actor); + } + + void + meta_compositor_window_surface_changed (MetaCompositor *compositor, + MetaWindow *window) + { + MetaWindowActor *window_actor; + window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); + if (!window_actor) + return; + + meta_window_actor_update_surface (window_actor); + } + + /** + * meta_compositor_process_event: (skip) + * @compositor: + * @event: + * @window: + * + */ + gboolean + meta_compositor_process_event (MetaCompositor *compositor, + XEvent *event, + MetaWindow *window) + { +@@ -872,81 +886,91 @@ meta_compositor_process_event (MetaCompositor *compositor, + } + } + + if (compositor->have_x11_sync_object) + meta_sync_ring_handle_event (event); + + /* Clutter needs to know about MapNotify events otherwise it will + think the stage is invisible */ + if (!meta_is_wayland_compositor () && event->type == MapNotify) + clutter_x11_handle_event (event); + + /* The above handling is basically just "observing" the events, so we return + * FALSE to indicate that the event should not be filtered out; if we have + * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example. + */ + return FALSE; + } + + gboolean + meta_compositor_filter_keybinding (MetaCompositor *compositor, + MetaKeyBinding *binding) + { + return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding); + } + + void + meta_compositor_show_window (MetaCompositor *compositor, + MetaWindow *window, + MetaCompEffect effect) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ g_return_if_fail (window_actor); ++ + meta_window_actor_show (window_actor, effect); + } + + void + meta_compositor_hide_window (MetaCompositor *compositor, + MetaWindow *window, + MetaCompEffect effect) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ if (!window_actor) ++ return; ++ + meta_window_actor_hide (window_actor, effect); + } + + void + meta_compositor_size_change_window (MetaCompositor *compositor, + MetaWindow *window, + MetaSizeChange which_change, + MetaRectangle *old_frame_rect, + MetaRectangle *old_buffer_rect) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); ++ ++ g_return_if_fail (window_actor); ++ + meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect); + } + + void + meta_compositor_switch_workspace (MetaCompositor *compositor, + MetaWorkspace *from, + MetaWorkspace *to, + MetaMotionDirection direction) + { + gint to_indx, from_indx; + + to_indx = meta_workspace_index (to); + from_indx = meta_workspace_index (from); + + compositor->switch_workspace_in_progress++; + + if (!meta_plugin_manager_switch_workspace (compositor->plugin_mgr, + from_indx, + to_indx, + direction)) + { + compositor->switch_workspace_in_progress--; + + /* We have to explicitely call this to fix up stacking order of the + * actors; this is because the abs stacking position of actors does not + * necessarily change during the window hiding/unhiding, only their + * relative position toward the destkop window. + */ + meta_finish_workspace_switch (compositor); + } +@@ -1093,61 +1117,61 @@ meta_compositor_sync_stack (MetaCompositor *compositor, + stack = g_list_copy (stack); /* The new stack of MetaWindow */ + old_stack = g_list_reverse (compositor->windows); /* The old stack of MetaWindowActor */ + compositor->windows = NULL; + + while (TRUE) + { + MetaWindowActor *old_actor = NULL, *stack_actor = NULL, *actor; + MetaWindow *old_window = NULL, *stack_window = NULL, *window; + + /* Find the remaining top actor in our existing stack (ignoring + * windows that have been hidden and are no longer animating) */ + while (old_stack) + { + old_actor = old_stack->data; + old_window = meta_window_actor_get_meta_window (old_actor); + + if ((old_window->hidden || old_window->unmanaging) && + !meta_window_actor_effect_in_progress (old_actor)) + { + old_stack = g_list_delete_link (old_stack, old_stack); + old_actor = NULL; + } + else + break; + } + + /* And the remaining top actor in the new stack */ + while (stack) + { + stack_window = stack->data; +- stack_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (stack_window)); ++ stack_actor = meta_window_actor_from_window (stack_window); + if (!stack_actor) + { + meta_verbose ("Failed to find corresponding MetaWindowActor " + "for window %s\n", meta_window_get_description (stack_window)); + stack = g_list_delete_link (stack, stack); + } + else + break; + } + + if (!old_actor && !stack_actor) /* Nothing more to stack */ + break; + + /* We usually prefer the window in the new stack, but if if we + * found a hidden window in the process of being animated out + * of existence in the old stack we use that instead. We've + * filtered out non-animating hidden windows above. + */ + if (old_actor && + (!stack_actor || old_window->hidden || old_window->unmanaging)) + { + actor = old_actor; + window = old_window; + } + else + { + actor = stack_actor; + window = stack_window; + } + +@@ -1159,63 +1183,65 @@ meta_compositor_sync_stack (MetaCompositor *compositor, + compositor->windows = g_list_prepend (compositor->windows, actor); + if (meta_window_actor_is_stereo (actor)) + stereo_window_count++; + + stack = g_list_remove (stack, window); + old_stack = g_list_remove (old_stack, actor); + } + + sync_actor_stacking (compositor); + + meta_stereo_set_have_stereo_windows (stereo_window_count > 0); + + if (compositor->top_window_actor) + g_signal_handlers_disconnect_by_func (compositor->top_window_actor, + on_top_window_actor_destroyed, + compositor); + + compositor->top_window_actor = get_top_visible_window_actor (compositor); + + if (compositor->top_window_actor) + g_signal_connect (compositor->top_window_actor, "destroy", + G_CALLBACK (on_top_window_actor_destroyed), + compositor); + } + + void + meta_compositor_sync_window_geometry (MetaCompositor *compositor, + MetaWindow *window, + gboolean did_placement) + { +- MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window)); ++ MetaWindowActor *window_actor = meta_window_actor_from_window (window); + MetaWindowActorChanges changes; + ++ g_return_if_fail (window_actor); ++ + changes = meta_window_actor_sync_actor_geometry (window_actor, did_placement); + + if (changes & META_WINDOW_ACTOR_CHANGE_SIZE) + meta_plugin_manager_event_size_changed (compositor->plugin_mgr, window_actor); + } + + static void + on_presented (ClutterStage *stage, + CoglFrameEvent event, + ClutterFrameInfo *frame_info, + MetaCompositor *compositor) + { + GList *l; + + if (event == COGL_FRAME_EVENT_COMPLETE) + { + gint64 presentation_time_cogl = frame_info->presentation_time; + gint64 presentation_time; + + if (presentation_time_cogl != 0) + { + /* Cogl reports presentation in terms of its own clock, which is + * guaranteed to be in nanoseconds but with no specified base. The + * normal case with the open source GPU drivers on Linux 3.8 and + * newer is that the base of cogl_get_clock_time() is that of + * clock_gettime(CLOCK_MONOTONIC), so the same as g_get_monotonic_time), + * but there's no exposure of that through the API. clock_gettime() + * is fairly fast, so calling it twice and subtracting to get a + * nearly-zero number is acceptable, if a litle ugly. + */ +@@ -1469,61 +1495,61 @@ meta_compositor_flash_screen (MetaCompositor *compositor, + + clutter_actor_save_easing_state (flash); + clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD); + clutter_actor_set_easing_duration (flash, FLASH_TIME_MS); + clutter_actor_set_opacity (flash, 192); + + transition = clutter_actor_get_transition (flash, "opacity"); + clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); + clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2); + + g_signal_connect (transition, "stopped", + G_CALLBACK (flash_out_completed), flash); + + clutter_actor_restore_easing_state (flash); + } + + static void + window_flash_out_completed (ClutterTimeline *timeline, + gboolean is_finished, + gpointer user_data) + { + ClutterActor *flash = CLUTTER_ACTOR (user_data); + clutter_actor_destroy (flash); + } + + void + meta_compositor_flash_window (MetaCompositor *compositor, + MetaWindow *window) + { + ClutterActor *window_actor = +- CLUTTER_ACTOR (meta_window_get_compositor_private (window)); ++ CLUTTER_ACTOR (meta_window_actor_from_window (window)); + ClutterActor *flash; + ClutterTransition *transition; + + flash = clutter_actor_new (); + clutter_actor_set_background_color (flash, CLUTTER_COLOR_Black); + clutter_actor_set_size (flash, window->rect.width, window->rect.height); + clutter_actor_set_position (flash, + window->custom_frame_extents.left, + window->custom_frame_extents.top); + clutter_actor_set_opacity (flash, 0); + clutter_actor_add_child (window_actor, flash); + + clutter_actor_save_easing_state (flash); + clutter_actor_set_easing_mode (flash, CLUTTER_EASE_IN_QUAD); + clutter_actor_set_easing_duration (flash, FLASH_TIME_MS); + clutter_actor_set_opacity (flash, 192); + + transition = clutter_actor_get_transition (flash, "opacity"); + clutter_timeline_set_auto_reverse (CLUTTER_TIMELINE (transition), TRUE); + clutter_timeline_set_repeat_count (CLUTTER_TIMELINE (transition), 2); + + g_signal_connect (transition, "stopped", + G_CALLBACK (window_flash_out_completed), flash); + + clutter_actor_restore_easing_state (flash); + } + + /** + * meta_compositor_monotonic_time_to_server_time: + * @display: a #MetaDisplay +-- +2.26.2 + diff --git a/SOURCES/0026-compositor-Fix-indentation-on-show-window.patch b/SOURCES/0026-compositor-Fix-indentation-on-show-window.patch new file mode 100644 index 0000000..810b845 --- /dev/null +++ b/SOURCES/0026-compositor-Fix-indentation-on-show-window.patch @@ -0,0 +1,80 @@ +From 15a7f8080788c54cf1ad3df0d969fb61b9dc315d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 02:02:44 +0200 +Subject: [PATCH 26/28] compositor: Fix indentation on show window + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/compositor/compositor.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index d02926171..65f5ab1f4 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -890,61 +890,61 @@ meta_compositor_process_event (MetaCompositor *compositor, + meta_sync_ring_handle_event (event); + + /* Clutter needs to know about MapNotify events otherwise it will + think the stage is invisible */ + if (!meta_is_wayland_compositor () && event->type == MapNotify) + clutter_x11_handle_event (event); + + /* The above handling is basically just "observing" the events, so we return + * FALSE to indicate that the event should not be filtered out; if we have + * GTK+ windows in the same process, GTK+ needs the ConfigureNotify event, for example. + */ + return FALSE; + } + + gboolean + meta_compositor_filter_keybinding (MetaCompositor *compositor, + MetaKeyBinding *binding) + { + return meta_plugin_manager_filter_keybinding (compositor->plugin_mgr, binding); + } + + void + meta_compositor_show_window (MetaCompositor *compositor, + MetaWindow *window, + MetaCompEffect effect) + { + MetaWindowActor *window_actor = meta_window_actor_from_window (window); + + g_return_if_fail (window_actor); + +- meta_window_actor_show (window_actor, effect); ++ meta_window_actor_show (window_actor, effect); + } + + void + meta_compositor_hide_window (MetaCompositor *compositor, + MetaWindow *window, + MetaCompEffect effect) + { + MetaWindowActor *window_actor = meta_window_actor_from_window (window); + + if (!window_actor) + return; + + meta_window_actor_hide (window_actor, effect); + } + + void + meta_compositor_size_change_window (MetaCompositor *compositor, + MetaWindow *window, + MetaSizeChange which_change, + MetaRectangle *old_frame_rect, + MetaRectangle *old_buffer_rect) + { + MetaWindowActor *window_actor = meta_window_actor_from_window (window); + + g_return_if_fail (window_actor); + + meta_window_actor_size_change (window_actor, which_change, old_frame_rect, old_buffer_rect); + } + + void +-- +2.26.2 + diff --git a/SOURCES/0027-window-actor-Unset-the-window-compositor-private-on-.patch b/SOURCES/0027-window-actor-Unset-the-window-compositor-private-on-.patch new file mode 100644 index 0000000..b843510 --- /dev/null +++ b/SOURCES/0027-window-actor-Unset-the-window-compositor-private-on-.patch @@ -0,0 +1,86 @@ +From 68bdb7ef345a2887ca8570fadbdca81404899b0a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Thu, 25 Jul 2019 02:10:07 +0200 +Subject: [PATCH 27/28] window-actor: Unset the window compositor private on + destruction + +A window actor could be destroyed before than the related Window (if for +example, it is explicitly removed from the stage or destroyed), in such case +we need to unset the compositor private for the window on disposition, or once +the window is actually destroyed, we will try to access to an invalid pointer, +and to remove an invalid window actor from the compositor. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + src/compositor/meta-window-actor.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c +index f1f86e14b..39198dbe1 100644 +--- a/src/compositor/meta-window-actor.c ++++ b/src/compositor/meta-window-actor.c +@@ -480,60 +480,61 @@ meta_window_actor_constructed (GObject *object) + } + + static void + meta_window_actor_dispose (GObject *object) + { + MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActorPrivate *priv = self->priv; + MetaCompositor *compositor = priv->compositor; + + if (priv->disposed) + return; + + priv->disposed = TRUE; + + if (priv->send_frame_messages_timer != 0) + { + g_source_remove (priv->send_frame_messages_timer); + priv->send_frame_messages_timer = 0; + } + + g_clear_pointer (&priv->shape_region, cairo_region_destroy); + g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); + + g_clear_pointer (&priv->shadow_class, g_free); + g_clear_pointer (&priv->focused_shadow, meta_shadow_unref); + g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref); + g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); + + compositor->windows = g_list_remove (compositor->windows, (gconstpointer) self); + ++ meta_window_set_compositor_private (priv->window, NULL); + g_clear_object (&priv->window); + + set_surface (self, NULL); + + G_OBJECT_CLASS (meta_window_actor_parent_class)->dispose (object); + } + + static void + meta_window_actor_finalize (GObject *object) + { + MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActorPrivate *priv = self->priv; + + g_list_free_full (priv->frames, (GDestroyNotify) frame_data_free); + + G_OBJECT_CLASS (meta_window_actor_parent_class)->finalize (object); + } + + static void + meta_window_actor_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) + { + MetaWindowActor *self = META_WINDOW_ACTOR (object); + MetaWindowActorPrivate *priv = self->priv; + + switch (prop_id) + { + case PROP_META_WINDOW: +-- +2.26.2 + diff --git a/SOURCES/0028-cleanup-Unref-GSource-s-once-attached.patch b/SOURCES/0028-cleanup-Unref-GSource-s-once-attached.patch new file mode 100644 index 0000000..6503ab7 --- /dev/null +++ b/SOURCES/0028-cleanup-Unref-GSource-s-once-attached.patch @@ -0,0 +1,432 @@ +From c483a57e848aa966eec6dfcb9d31786d83050a33 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= +Date: Wed, 24 Jul 2019 17:10:49 +0200 +Subject: [PATCH 28/28] cleanup: Unref GSource's once attached + +When a source is attached the main contaxt takes the ownership of it, so we +can safely them. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/682 +--- + clutter/clutter/clutter-backend.c | 1 + + clutter/clutter/clutter-master-clock-default.c | 2 +- + clutter/clutter/evdev/clutter-device-manager-evdev.c | 2 +- + src/backends/meta-screen-cast-stream-src.c | 1 + + src/backends/x11/meta-backend-x11.c | 3 ++- + src/wayland/meta-wayland.c | 2 +- + 6 files changed, 7 insertions(+), 4 deletions(-) + +diff --git a/clutter/clutter/clutter-backend.c b/clutter/clutter/clutter-backend.c +index 41ea3daed..df51464cc 100644 +--- a/clutter/clutter/clutter-backend.c ++++ b/clutter/clutter/clutter-backend.c +@@ -381,60 +381,61 @@ clutter_backend_real_create_context (ClutterBackend *backend, + if (clutter_backend_do_real_create_context (backend, all_known_drivers[j].driver_id, &internal_error)) + break; + + if (internal_error) + { + CLUTTER_NOTE (BACKEND, "Unable to use the %s driver: %s", + all_known_drivers[j].driver_desc, + internal_error->message); + g_clear_error (&internal_error); + } + } + } + } + + g_strfreev (known_drivers); + + if (backend->cogl_context == NULL) + { + if (internal_error != NULL) + g_propagate_error (error, internal_error); + else + g_set_error_literal (error, CLUTTER_INIT_ERROR, + CLUTTER_INIT_ERROR_BACKEND, + _("Unable to initialize the Clutter backend: no available drivers found.")); + + return FALSE; + } + + backend->cogl_source = cogl_glib_source_new (backend->cogl_context, G_PRIORITY_DEFAULT); + g_source_attach (backend->cogl_source, NULL); ++ g_source_unref (backend->cogl_source); + + return TRUE; + } + + static ClutterFeatureFlags + clutter_backend_real_get_features (ClutterBackend *backend) + { + ClutterFeatureFlags flags = 0; + + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_MULTIPLE_ONSCREEN)) + { + CLUTTER_NOTE (BACKEND, "Cogl supports multiple onscreen framebuffers"); + flags |= CLUTTER_FEATURE_STAGE_MULTIPLE; + } + else + { + CLUTTER_NOTE (BACKEND, "Cogl only supports one onscreen framebuffer"); + flags |= CLUTTER_FEATURE_STAGE_STATIC; + } + + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE)) + { + CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling"); + flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK; + } + else + CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling"); + + if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT)) + { +diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c +index 7b2df0df3..83b1eadcb 100644 +--- a/clutter/clutter/clutter-master-clock-default.c ++++ b/clutter/clutter/clutter-master-clock-default.c +@@ -577,61 +577,61 @@ clutter_clock_dispatch (GSource *source, + g_slist_free (stages); + + master_clock->prev_tick = master_clock->cur_tick; + + _clutter_threads_release_lock (); + + return TRUE; + } + + static void + clutter_master_clock_default_finalize (GObject *gobject) + { + ClutterMasterClockDefault *master_clock = CLUTTER_MASTER_CLOCK_DEFAULT (gobject); + + g_slist_free (master_clock->timelines); + + G_OBJECT_CLASS (clutter_master_clock_default_parent_class)->finalize (gobject); + } + + static void + clutter_master_clock_default_class_init (ClutterMasterClockDefaultClass *klass) + { + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = clutter_master_clock_default_finalize; + } + + static void + clutter_master_clock_default_init (ClutterMasterClockDefault *self) + { +- GSource *source; ++ g_autoptr (GSource) source = NULL; + + source = clutter_clock_source_new (self); + self->source = source; + + self->idle = FALSE; + self->ensure_next_iteration = FALSE; + self->paused = FALSE; + + #ifdef CLUTTER_ENABLE_DEBUG + self->frame_budget = G_USEC_PER_SEC / 60; + #endif + + g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW); + g_source_set_can_recurse (source, FALSE); + g_source_attach (source, NULL); + } + + static void + clutter_master_clock_default_add_timeline (ClutterMasterClock *clock, + ClutterTimeline *timeline) + { + ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock; + gboolean is_first; + + if (g_slist_find (master_clock->timelines, timeline)) + return; + + is_first = master_clock->timelines == NULL; + + master_clock->timelines = g_slist_prepend (master_clock->timelines, +diff --git a/clutter/clutter/evdev/clutter-device-manager-evdev.c b/clutter/clutter/evdev/clutter-device-manager-evdev.c +index 11cb4781a..49566c233 100644 +--- a/clutter/clutter/evdev/clutter-device-manager-evdev.c ++++ b/clutter/clutter/evdev/clutter-device-manager-evdev.c +@@ -706,61 +706,61 @@ clutter_event_dispatch (GSource *g_source, + /* Drop events if we don't have any stage to forward them to */ + if (!_clutter_input_device_get_stage (input_device)) + goto out; + + /* forward the event into clutter for emission etc. */ + _clutter_stage_queue_event (event->any.stage, event, FALSE); + + /* update the device states *after* the event */ + event_state = seat->button_state | + xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE); + _clutter_input_device_set_state (seat->core_pointer, event_state); + _clutter_input_device_set_state (seat->core_keyboard, event_state); + } + + out: + _clutter_threads_release_lock (); + + return TRUE; + } + static GSourceFuncs event_funcs = { + clutter_event_prepare, + clutter_event_check, + clutter_event_dispatch, + NULL + }; + + static ClutterEventSource * + clutter_event_source_new (ClutterDeviceManagerEvdev *manager_evdev) + { + ClutterDeviceManagerEvdevPrivate *priv = manager_evdev->priv; +- GSource *source; ++ g_autoptr (GSource) source = NULL; + ClutterEventSource *event_source; + gint fd; + + source = g_source_new (&event_funcs, sizeof (ClutterEventSource)); + event_source = (ClutterEventSource *) source; + + /* setup the source */ + event_source->manager_evdev = manager_evdev; + + fd = libinput_get_fd (priv->libinput); + event_source->event_poll_fd.fd = fd; + event_source->event_poll_fd.events = G_IO_IN; + + /* and finally configure and attach the GSource */ + g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); + g_source_add_poll (source, &event_source->event_poll_fd); + g_source_set_can_recurse (source, TRUE); + g_source_attach (source, NULL); + + return event_source; + } + + static void + clutter_event_source_free (ClutterEventSource *source) + { + GSource *g_source = (GSource *) source; + + CLUTTER_NOTE (EVENT, "Removing GSource for evdev device manager"); + + /* ignore the return value of close, it's not like we can do something +diff --git a/src/backends/meta-screen-cast-stream-src.c b/src/backends/meta-screen-cast-stream-src.c +index 457c0589e..254ef983d 100644 +--- a/src/backends/meta-screen-cast-stream-src.c ++++ b/src/backends/meta-screen-cast-stream-src.c +@@ -465,60 +465,61 @@ static void + init_spa_type (MetaSpaType *type, + struct spa_type_map *map) + { + spa_type_media_type_map (map, &type->media_type); + spa_type_media_subtype_map (map, &type->media_subtype); + spa_type_format_video_map (map, &type->format_video); + spa_type_video_format_map (map, &type->video_format); + } + + static MetaPipeWireSource * + create_pipewire_source (void) + { + MetaPipeWireSource *pipewire_source; + + pipewire_source = + (MetaPipeWireSource *) g_source_new (&pipewire_source_funcs, + sizeof (MetaPipeWireSource)); + pipewire_source->pipewire_loop = pw_loop_new (NULL); + if (!pipewire_source->pipewire_loop) + { + g_source_destroy ((GSource *) pipewire_source); + return NULL; + } + + g_source_add_unix_fd (&pipewire_source->base, + pw_loop_get_fd (pipewire_source->pipewire_loop), + G_IO_IN | G_IO_ERR); + + pw_loop_enter (pipewire_source->pipewire_loop); + g_source_attach (&pipewire_source->base, NULL); ++ g_source_unref (&pipewire_source->base); + + return pipewire_source; + } + + static const struct pw_remote_events remote_events = { + PW_VERSION_REMOTE_EVENTS, + .state_changed = on_state_changed, + }; + + static gboolean + meta_screen_cast_stream_src_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) + { + MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (initable); + MetaScreenCastStreamSrcPrivate *priv = + meta_screen_cast_stream_src_get_instance_private (src); + + priv->pipewire_source = create_pipewire_source (); + if (!priv->pipewire_source) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Failed to create PipeWire source"); + return FALSE; + } + + priv->pipewire_core = pw_core_new (priv->pipewire_source->pipewire_loop, + NULL); + if (!priv->pipewire_core) + { +diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c +index 3f8645e93..b9acf48c0 100644 +--- a/src/backends/x11/meta-backend-x11.c ++++ b/src/backends/x11/meta-backend-x11.c +@@ -449,71 +449,72 @@ x_event_source_dispatch (GSource *source, + gpointer user_data) + { + XEventSource *x_source = (XEventSource *) source; + MetaBackend *backend = x_source->backend; + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + + while (XPending (priv->xdisplay)) + { + XEvent event; + + XNextEvent (priv->xdisplay, &event); + + handle_host_xevent (backend, &event); + } + + return TRUE; + } + + static GSourceFuncs x_event_funcs = { + x_event_source_prepare, + x_event_source_check, + x_event_source_dispatch, + }; + + static GSource * + x_event_source_new (MetaBackend *backend) + { + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); +- GSource *source; ++ g_autoptr (GSource) source = NULL; + XEventSource *x_source; + + source = g_source_new (&x_event_funcs, sizeof (XEventSource)); + x_source = (XEventSource *) source; + x_source->backend = backend; + x_source->event_poll_fd.fd = ConnectionNumber (priv->xdisplay); + x_source->event_poll_fd.events = G_IO_IN; + g_source_add_poll (source, &x_source->event_poll_fd); + + g_source_attach (source, NULL); ++ + return source; + } + + static void + on_monitors_changed (MetaMonitorManager *manager, + MetaBackend *backend) + { + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + + priv->cached_current_logical_monitor = NULL; + } + + static void + meta_backend_x11_post_init (MetaBackend *backend) + { + MetaBackendX11 *x11 = META_BACKEND_X11 (backend); + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + MetaMonitorManager *monitor_manager; + int major, minor; + gboolean has_xi = FALSE; + + priv->source = x_event_source_new (backend); + + if (!XSyncQueryExtension (priv->xdisplay, &priv->xsync_event_base, &priv->xsync_error_base) || + !XSyncInitialize (priv->xdisplay, &major, &minor)) + meta_fatal ("Could not initialize XSync"); + + priv->counter = find_idletime_counter (priv); + if (priv->counter == None) +diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c +index bab6b4ac4..44f48a0ee 100644 +--- a/src/wayland/meta-wayland.c ++++ b/src/wayland/meta-wayland.c +@@ -325,61 +325,61 @@ meta_wayland_pre_clutter_init (void) + } + + static bool + meta_xwayland_global_filter (const struct wl_client *client, + const struct wl_global *global, + void *data) + { + MetaWaylandCompositor *compositor = (MetaWaylandCompositor *) data; + MetaXWaylandManager *xwayland_manager = &compositor->xwayland_manager; + + /* Keyboard grabbing protocol is for Xwayland only */ + if (client != xwayland_manager->client) + return (wl_global_get_interface (global) != + &zwp_xwayland_keyboard_grab_manager_v1_interface); + + /* All others are visible to all clients */ + return true; + } + + void + meta_wayland_override_display_name (char *display_name) + { + g_clear_pointer (&_display_name_override, g_free); + _display_name_override = g_strdup (display_name); + } + + void + meta_wayland_init (void) + { + MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default (); +- GSource *wayland_event_source; ++ g_autoptr (GSource) wayland_event_source = NULL; + + wayland_event_source = wayland_event_source_new (compositor->wayland_display); + + /* XXX: Here we are setting the wayland event source to have a + * slightly lower priority than the X event source, because we are + * much more likely to get confused being told about surface changes + * relating to X clients when we don't know what's happened to them + * according to the X protocol. + */ + g_source_set_priority (wayland_event_source, GDK_PRIORITY_EVENTS + 1); + g_source_attach (wayland_event_source, NULL); + + if (!wl_global_create (compositor->wayland_display, + &wl_compositor_interface, + META_WL_COMPOSITOR_VERSION, + compositor, compositor_bind)) + g_error ("Failed to register the global wl_compositor"); + + wl_display_init_shm (compositor->wayland_display); + + meta_wayland_outputs_init (compositor); + meta_wayland_data_device_manager_init (compositor); + meta_wayland_subsurfaces_init (compositor); + meta_wayland_shell_init (compositor); + meta_wayland_pointer_gestures_init (compositor); + meta_wayland_tablet_manager_init (compositor); + meta_wayland_seat_init (compositor); + meta_wayland_relative_pointer_init (compositor); + meta_wayland_pointer_constraints_init (compositor); + meta_wayland_xdg_foreign_init (compositor); +-- +2.26.2 + diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec index 964b556..a323819 100644 --- a/SPECS/mutter.spec +++ b/SPECS/mutter.spec @@ -10,7 +10,7 @@ Name: mutter Version: 3.28.3 -Release: 26%{?dist} +Release: 28%{?dist} Summary: Window and compositing manager based on Clutter License: GPLv2+ @@ -126,6 +126,48 @@ Patch295: fix-extended-osk-characters.patch # Only treat WM_PROTOCOLS messages as WM_PROTOCOL messages (#1846242) Patch296: 0001-stage-x11-Check-that-message-is-WM_PROTOCOLS-before-.patch +# Turn stacking warning into debug log (#1811029) +Patch297: 0001-stack-tracker-Fix-coding-style-of-meta_stack_op_appl.patch +Patch298: 0002-stack-tracker-Don-t-log-warnings-on-race-conditions.patch + +# Backport of upstream fixes +# https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/682 + +Patch401: 0001-cogl-Use-autopointers-to-free-structs-on-return.patch +Patch402: 0002-cogl-Define-autoptr-cleanup-functions-for-Cogl-types.patch +Patch403: 0003-cogl-vertex-buffer-Don-t-try-to-use-free-d-data.patch +Patch404: 0004-cogl-onscreen-template-Unref-the-swap-chain.patch +Patch405: 0005-cogl-framebuffer-Unref-the-config-swap-chain-if-set.patch +Patch406: 0006-clutter-backend-Use-an-auto-pointer-to-handle-the-te.patch +Patch407: 0007-clutter-Keep-a-device-reference-with-events.patch +Patch408: 0008-clutter-event-Use-all-events-Hash-table-as-a-Set-wit.patch +Patch409: 0009-clutter-actor-Take-the-marging-boxed-type-if-valid.patch +Patch410: 0010-clutter-actor-meta-Notify-when-actor-property-change.patch +Patch411: 0011-clutter-actor-meta-Unset-the-actor-if-disposed-calli.patch +Patch412: 0012-clutter-stage-manager-Pause-the-master-clock-when-al.patch +Patch413: 0013-cally-stage-Set-the-keyfocus-to-NULL-if-the-stage-is.patch +Patch414: 0014-cally-stage-Monitor-key-focus-actor-via-destroyed-si.patch +Patch415: 0015-group-Free-group-if-returning-early.patch +Patch416: 0016-surface-actor-Destroy-the-pending-damage-region-on-d.patch +Patch417: 0017-CrtcMode-Free-the-mode-name-on-finalize.patch +Patch418: 0018-monitor-config-manager-Always-free-temporary-region-.patch +Patch419: 0019-monitor-config-store-Use-autopointers-to-cleanup-par.patch +Patch420: 0020-monitor-Free-the-existing-mode-if-replacing-it.patch +Patch421: 0021-monitor-Use-delete-link-to-free-the-tiled-modes-whil.patch +Patch422: 0022-monitor-config-store-Check-if-a-config-is-system-one.patch +Patch423: 0023-monitor-config-migration-Unref-the-new-config-once-a.patch +Patch424: 0024-monitor-config-migration-Free-the-output-key-on-inva.patch +Patch425: 0025-compositor-Use-meta_window_actor_from_window-to-get-.patch +Patch426: 0026-compositor-Fix-indentation-on-show-window.patch +Patch427: 0027-window-actor-Unset-the-window-compositor-private-on-.patch +Patch428: 0028-cleanup-Unref-GSource-s-once-attached.patch + +# Leaks fixes +Patch501: 0001-cally-Fix-state-set-leak.patch +Patch502: 0002-barriers-Fix-leak-in-meta_barrier_destroy.patch +Patch503: 0003-barriers-Free-backend-implementation-at-dispose-time.patch +Patch504: 0004-src-Export-MetaWaylandX11-to-introspection.patch + BuildRequires: chrpath BuildRequires: pango-devel BuildRequires: startup-notification-devel @@ -281,6 +323,14 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : %{_libdir}/pkgconfig/* %changelog +* Wed Oct 14 2020 Ray Strode - 3.28.3-28 +- Try to fix leaks + Resolves: #1717000 + +* Mon Jun 22 2020 Jonas Ådahl ) - 3.28.3-27 +- Turn stacking warning into debug log + Resolves: #1811029 + * Mon Jun 22 2020 Jonas Ådahl ) - 3.28.3-26 - Only treat WM_PROTOCOLS messages as WM_PROTOCOL messages Resolves: #1846242