diff --git a/lib/Gestures/Triggers/SwipeTrigger.vala b/lib/Gestures/Triggers/SwipeTrigger.vala index 6af501d9e..8d4f8150a 100644 --- a/lib/Gestures/Triggers/SwipeTrigger.vala +++ b/lib/Gestures/Triggers/SwipeTrigger.vala @@ -11,11 +11,14 @@ * It enables touchpad and (once supported) touchscreen backends for the given actor. */ public class Gala.SwipeTrigger : Object, GestureTrigger { - public Clutter.Actor actor { get; construct; } public Clutter.Orientation orientation { get; construct; } + private weak Clutter.Actor actor; public SwipeTrigger (Clutter.Actor actor, Clutter.Orientation orientation) { - Object (actor: actor, orientation: orientation); + Object (orientation: orientation); + + this.actor = actor; + actor.add_weak_pointer (&this.actor); } internal bool triggers (Gesture gesture) { @@ -25,7 +28,7 @@ public class Gala.SwipeTrigger : Object, GestureTrigger { ); } - internal void enable_backends (GestureController controller) { + internal void enable_backends (GestureController controller) requires (actor != null) { controller.enable_backend (new ScrollBackend (actor, orientation, new GestureSettings ())); } } diff --git a/tests/lib/SwipeTriggerTest.vala b/tests/lib/SwipeTriggerTest.vala new file mode 100644 index 000000000..b937bb3c9 --- /dev/null +++ b/tests/lib/SwipeTriggerTest.vala @@ -0,0 +1,62 @@ +/* + * Copyright 2026 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Authored by: Leonhard Kargl + */ + +public class Gala.SwipeTriggerTest : MutterTestCase { + private Clutter.Actor? actor; + private SwipeTrigger? trigger; + + public SwipeTriggerTest () { + Object (name: "SwipeTriggerTest"); + } + + construct { + add_test ("Test finalize trigger first", test_finalize_trigger_first); + add_test ("Test finalize actor first", test_finalize_actor_first); + add_test ("Test finalize actor and enable backend", test_finalize_actor_and_enable_backend); + } + + public override void set_up () { + actor = new Clutter.Actor (); + trigger = new SwipeTrigger (actor, Clutter.Orientation.HORIZONTAL); + } + + public override void tear_down () { + trigger = null; + actor = null; + } + + private void test_finalize_trigger_first () { + assert_finalize_object (ref trigger); + assert_finalize_object (ref actor); + } + + private void test_finalize_actor_first () { + // We can finalize the actor first because the swipe trigger only holds a weak reference to it + assert_finalize_object (ref actor); + assert_finalize_object (ref trigger); + } + + private void test_finalize_actor_and_enable_backend () { + // We can finalize the actor first because the swipe trigger only holds a weak reference to it + assert_finalize_object (ref actor); + + // Enabling the backend after the actor has been finalized should not cause a crash + // but print a warning + Test.expect_message (null, LEVEL_CRITICAL, "*assertion 'actor != null' failed"); + + var controller = new GestureController (CUSTOM); + trigger.enable_backends (controller); + + Test.assert_expected_messages (); + + assert_finalize_object (ref trigger); + } +} + +public int main (string[] args) { + return new Gala.SwipeTriggerTest ().run (args); +} diff --git a/tests/lib/meson.build b/tests/lib/meson.build index 6a341ff14..aae6fb5f4 100644 --- a/tests/lib/meson.build +++ b/tests/lib/meson.build @@ -2,6 +2,7 @@ tests = [ 'GestureControllerTest', 'PropertyTargetTest', 'SetupTest', + 'SwipeTriggerTest', ] foreach test : tests