Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/Gestures/Backends/ToucheggBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ private class Gala.ToucheggBackend : Object, GestureBackend {
signal_params.get ("(uudiut)", out type, out direction, out percentage, out fingers,
out performed_on_device_type, out elapsed_time);

#if HAS_MUTTER49
if (Meta.Util.is_wayland_compositor () && performed_on_device_type != DeviceType.TOUCHSCREEN) {
#else
if (Meta.Util.is_wayland_compositor () && performed_on_device_type != DeviceType.TOUCHSCREEN && type != PINCH) {
#endif
return;
}

Expand Down
95 changes: 95 additions & 0 deletions lib/Gestures/Backends/TouchpadPinchBackend.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2026 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: GPL-3.0-or-later
*
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
*/

private class Gala.TouchpadPinchBackend : Object, GestureBackend {
private enum State {
NONE,
IGNORED,
ONGOING
}

public Clutter.Actor actor { get; construct; }

private State state = NONE;
private double percentage = 0.0;

public TouchpadPinchBackend (Clutter.Actor actor) {
Object (actor: actor);
}

construct {
actor.captured_event.connect (handle_event);
}

public override void cancel_gesture () {
state = IGNORED;
}

private bool handle_event (Clutter.Event event) {
if (event.get_type () != TOUCHPAD_PINCH) {
return Clutter.EVENT_PROPAGATE;
}

if (state != ONGOING && (event.get_gesture_phase () == END || event.get_gesture_phase () == CANCEL)) {
reset ();
return Clutter.EVENT_PROPAGATE;
}

if (state == IGNORED) {
return Clutter.EVENT_PROPAGATE;
}

if (state == NONE && event.get_gesture_phase () != BEGIN) {
/* We never got a begin phase so something else initially handled the gesture
but disappeared. Don't start handling it now. Will probably never happen */
return Clutter.EVENT_PROPAGATE;
}

if (state != ONGOING) {
var gesture = new Gesture ();
gesture.direction = OUT;
gesture.type = event.get_type ();
gesture.fingers = (int) event.get_touchpad_gesture_finger_count ();
gesture.performed_on_device_type = event.get_source_device ().get_device_type ();

if (!on_gesture_detected (gesture, event.get_time ())) {
state = IGNORED;
return Clutter.EVENT_PROPAGATE;
}

state = ONGOING;
}

if (event.get_gesture_phase () == UPDATE) {
/* When the gesture ends the pinch scale is already reset */
percentage = event.get_gesture_pinch_scale () - 1.0;
}

switch (event.get_gesture_phase ()) {
case BEGIN:
on_begin (0, event.get_time ());
break;

case UPDATE:
on_update (percentage, event.get_time ());
break;

case END:
case CANCEL:
on_end (percentage, event.get_time ());
reset ();
break;
}

return Clutter.EVENT_STOP;
}

private void reset () {
state = NONE;
percentage = 0.0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Authored by: Leonhard Kargl <leo.kargl@proton.me>
*/

private class Gala.TouchpadBackend : Object, GestureBackend {
private class Gala.TouchpadSwipeBackend : Object, GestureBackend {
public enum Group {
NONE,
MULTITASKING_VIEW,
Expand All @@ -26,19 +26,19 @@ private class Gala.TouchpadBackend : Object, GestureBackend {
public Clutter.Actor actor { get; construct; }
public Group group { get; construct; }

private static List<TouchpadBackend> instances = new List<TouchpadBackend> ();
private static List<TouchpadSwipeBackend> instances = new List<TouchpadSwipeBackend> ();

private State state = NONE;
private GestureDirection direction = UNKNOWN;
private double distance_x = 0;
private double distance_y = 0;
private double distance = 0;

public TouchpadBackend (Clutter.Actor actor, Group group) {
public TouchpadSwipeBackend (Clutter.Actor actor, Group group) {
Object (actor: actor, group: group);
}

~TouchpadBackend () {
~TouchpadSwipeBackend () {
instances.remove (this);
}

Expand Down
8 changes: 6 additions & 2 deletions lib/Gestures/Triggers/GlobalTrigger.vala
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,12 @@ public class Gala.GlobalTrigger : Object, GestureTrigger {
}

internal void enable_backends (GestureController controller) {
var group = action == MULTITASKING_VIEW || action == SWITCH_WORKSPACE ? TouchpadBackend.Group.MULTITASKING_VIEW : TouchpadBackend.Group.NONE;
var group = action == MULTITASKING_VIEW || action == SWITCH_WORKSPACE ? TouchpadSwipeBackend.Group.MULTITASKING_VIEW : TouchpadSwipeBackend.Group.NONE;
controller.enable_backend (ToucheggBackend.get_default ());
controller.enable_backend (new TouchpadBackend (wm.stage, group));
controller.enable_backend (new TouchpadSwipeBackend (wm.stage, group));
#if HAS_MUTTER49
// On mutter < 49 there is a bug that pinch gestures aren't delivered when over a window so rely on touch egg there
controller.enable_backend (new TouchpadPinchBackend (wm.stage));
#endif
}
}
3 changes: 2 additions & 1 deletion lib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ gala_lib_sources = files(
'Effects/ShadowEffect.vala',
'Gestures/Backends/GestureBackend.vala',
'Gestures/Backends/ToucheggBackend.vala',
'Gestures/Backends/TouchpadBackend.vala',
'Gestures/Backends/TouchpadPinchBackend.vala',
'Gestures/Backends/TouchpadSwipeBackend.vala',
'Gestures/Backends/ScrollBackend.vala',
'Gestures/Targets/ActorTarget.vala',
'Gestures/Targets/GestureTarget.vala',
Expand Down
2 changes: 1 addition & 1 deletion po/POTFILES
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ lib/Effects/RoundedCornersEffect.vala
lib/Effects/ShadowEffect.vala
lib/Gestures/Backends/GestureBackend.vala
lib/Gestures/Backends/ToucheggBackend.vala
lib/Gestures/Backends/TouchpadBackend.vala
lib/Gestures/Backends/TouchpadSwipeBackend.vala
lib/Gestures/Backends/ScrollBackend.vala
lib/Gestures/Targets/ActorTarget.vala
lib/Gestures/Targets/GestureTarget.vala
Expand Down