Skip to content

Commit

Permalink
Gestures: Add more details and introduce on_gesture_handled
Browse files Browse the repository at this point in the history
Add information about whether a gesture will be handled. This might be used to
determine whether events are supposed to be consumed.
Add information about the origin of a gesture. This might be used to determine
whether a gesture should be handled (e.g. only allow swipe from screen edge).
Add common GestureBackend interface that all backends have to implement.
Add a on_gesture_handled signal to the GestureTracker which runs if and only if
true was returned in on_gesture_detected. Before it is emitted prepare_gesture_handling
will be called on the backend. This will be needed for the upcoming PanBackend to avoid
conflicts in event consuming.
Add a utility get_action to the GestureSettings that gets the corresponding action for a gesture.
This allows to remove some duplicated code.
  • Loading branch information
leolost2605 committed Dec 15, 2024
1 parent c164204 commit ed01957
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 92 deletions.
16 changes: 16 additions & 0 deletions src/Gestures/Gesture.vala
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,25 @@ namespace Gala {
}

public class Gesture {
public const float INVALID_COORD = float.MAX;

public Clutter.EventType type;
public GestureDirection direction;
public int fingers;
public Clutter.InputDeviceType performed_on_device_type;

/**
* The x coordinate of the initial contact point for the gesture.
* Doesn't have to be set. In that case it is set to {@link INVALID_COORD}.
* Currently the only backend not setting this is {@link GestureTracker.enable_touchpad}.
*/
public float origin_x = INVALID_COORD;

/**
* The y coordinate of the initial contact point for the gesture.
* Doesn't have to be set. In that case it is set to {@link INVALID_COORD}.
* Currently the only backend not setting this is {@link GestureTracker.enable_touchpad}.
*/
public float origin_y = INVALID_COORD;
}
}
45 changes: 45 additions & 0 deletions src/Gestures/GestureSettings.vala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
* Utility class to access the gesture settings. Easily accessible through GestureTracker.settings.
*/
public class Gala.GestureSettings : Object {
public enum GestureAction {
NONE,
SWITCH_WORKSPACE,
MOVE_TO_WORKSPACE,
SWITCH_WINDOWS,
MULTITASKING_VIEW
}

private static GLib.Settings gala_settings;
private static GLib.Settings touchpad_settings;

Expand Down Expand Up @@ -69,4 +77,41 @@ public class Gala.GestureSettings : Object {
public static string get_string (string setting_id) {
return gala_settings.get_string (setting_id);
}

public static GestureAction get_action (Gesture gesture) {
if (gesture.type == TOUCHPAD_SWIPE) {
var fingers = gesture.fingers;

if (gesture.direction == LEFT || gesture.direction == RIGHT) {
var three_finger_swipe_horizontal = get_string ("three-finger-swipe-horizontal");
var four_finger_swipe_horizontal = get_string ("four-finger-swipe-horizontal");

if (fingers == 3 && three_finger_swipe_horizontal == "switch-to-workspace" ||
fingers == 4 && four_finger_swipe_horizontal == "switch-to-workspace") {
return SWITCH_WORKSPACE;
}

if (fingers == 3 && three_finger_swipe_horizontal == "move-to-workspace" ||
fingers == 4 && four_finger_swipe_horizontal == "move-to-workspace") {
return MOVE_TO_WORKSPACE;
}


if (fingers == 3 && three_finger_swipe_horizontal == "switch-windows" ||
fingers == 4 && four_finger_swipe_horizontal == "switch-windows") {
return SWITCH_WINDOWS;
}
} else if (gesture.direction == UP || gesture.direction == DOWN) {
var three_finger_swipe_up = get_string ("three-finger-swipe-up");
var four_finger_swipe_up = get_string ("four-finger-swipe-up");

if (fingers == 3 && three_finger_swipe_up == "multitasking-view" ||
fingers == 4 && four_finger_swipe_up == "multitasking-view") {
return MULTITASKING_VIEW;
}
}
}

return NONE;
}
}
38 changes: 32 additions & 6 deletions src/Gestures/GestureTracker.vala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

public interface Gala.GestureBackend : Object {
public signal bool on_gesture_detected (Gesture gesture, uint32 timestamp);
public signal void on_begin (double delta, uint64 time);
public signal void on_update (double delta, uint64 time);
public signal void on_end (double delta, uint64 time);

public virtual void prepare_gesture_handling () { }
}

/**
* Allow to use multi-touch gestures from different sources (backends).
* Usage:
Expand Down Expand Up @@ -68,11 +77,24 @@ public class Gala.GestureTracker : Object {

/**
* Emitted when a new gesture is detected.
* If the receiving code needs to handle this gesture, it should call to connect_handlers to
* start receiving updates.
* This should only be used to determine whether the gesture should be handled. This shouldn't
* do any preparations instead those should be done in {@link on_gesture_handled}. This is because
* the backend might have to do some preparations itself before you are allowed to do some to avoid
* conflicts.
* @param gesture Information about the gesture.
* @return true if the gesture will be handled false otherwise. If false is returned the other
* signals may still be emitted but aren't guaranteed to be.
*/
public signal void on_gesture_detected (Gesture gesture);
public signal bool on_gesture_detected (Gesture gesture);

/**
* Emitted if true was returned form {@link on_gesture_detected}. This should
* be used to do any preparations for gesture handling and to call {@link connect_handlers} to
* start receiving updates.
* @param gesture the same gesture as in {@link on_gesture_detected}
* @param timestamp the timestamp of the event that initiated the gesture or {@link Meta.CURRENT_TIME}.
*/
public signal void on_gesture_handled (Gesture gesture, uint32 timestamp);

/**
* Emitted right after on_gesture_detected with the initial gesture information.
Expand Down Expand Up @@ -201,10 +223,14 @@ public class Gala.GestureTracker : Object {
return value;
}

private void gesture_detected (Gesture gesture) {
if (enabled) {
on_gesture_detected (gesture);
private bool gesture_detected (GestureBackend backend, Gesture gesture, uint32 timestamp) {
if (enabled && on_gesture_detected (gesture)) {
backend.prepare_gesture_handling ();
on_gesture_handled (gesture, timestamp);
return true;
}

return false;
}

private void gesture_begin (double percentage, uint64 elapsed_time) {
Expand Down
21 changes: 10 additions & 11 deletions src/Gestures/ScrollBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,13 @@
/**
* This gesture backend transforms the touchpad scroll events received by an actor into gestures.
*/
public class Gala.ScrollBackend : Object {
public class Gala.ScrollBackend : Object, GestureBackend {
// Mutter does not expose the size of the touchpad, so we use the same values as GTK apps.
// From GNOME Shell, TOUCHPAD_BASE_[WIDTH|HEIGHT] / SCROLL_MULTIPLIER
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/swipeTracker.js
private const double FINISH_DELTA_HORIZONTAL = 40;
private const double FINISH_DELTA_VERTICAL = 30;

public signal void on_gesture_detected (Gesture gesture);
public signal void on_begin (double delta, uint64 time);
public signal void on_update (double delta, uint64 time);
public signal void on_end (double delta, uint64 time);

public Clutter.Actor actor { get; construct; }
public Clutter.Orientation orientation { get; construct; }
public GestureSettings settings { get; construct; }
Expand Down Expand Up @@ -62,7 +57,7 @@ public class Gala.ScrollBackend : Object {
return false;
}

uint64 time = event.get_time ();
var time = event.get_time ();
double x, y;
event.get_scroll_delta (out x, out y);

Expand All @@ -80,10 +75,12 @@ public class Gala.ScrollBackend : Object {

if (!started) {
if (delta_x != 0 || delta_y != 0) {
Gesture gesture = build_gesture (delta_x, delta_y, orientation);
float origin_x, origin_y;
event.get_coords (out origin_x, out origin_y);
Gesture gesture = build_gesture (origin_x, origin_y, delta_x, delta_y, orientation, time);
started = true;
direction = gesture.direction;
on_gesture_detected (gesture);
on_gesture_detected (gesture, time);

double delta = calculate_delta (delta_x, delta_y, direction);
on_begin (delta, time);
Expand Down Expand Up @@ -114,7 +111,7 @@ public class Gala.ScrollBackend : Object {
&& event.get_scroll_direction () == Clutter.ScrollDirection.SMOOTH;
}

private static Gesture build_gesture (double delta_x, double delta_y, Clutter.Orientation orientation) {
private static Gesture build_gesture (float origin_x, float origin_y, double delta_x, double delta_y, Clutter.Orientation orientation, uint32 timestamp) {
GestureDirection direction;
if (orientation == Clutter.Orientation.HORIZONTAL) {
direction = delta_x > 0 ? GestureDirection.RIGHT : GestureDirection.LEFT;
Expand All @@ -126,7 +123,9 @@ public class Gala.ScrollBackend : Object {
type = Clutter.EventType.SCROLL,
direction = direction,
fingers = 2,
performed_on_device_type = Clutter.InputDeviceType.TOUCHPAD_DEVICE
performed_on_device_type = Clutter.InputDeviceType.TOUCHPAD_DEVICE,
origin_x = origin_x,
origin_y = origin_y
};
}

Expand Down
9 changes: 2 additions & 7 deletions src/Gestures/ToucheggBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,7 @@
* Singleton class to manage the connection with Touchégg daemon and receive touch events.
* See: [[https://github.com/JoseExposito/touchegg]]
*/
public class Gala.ToucheggBackend : Object {
public signal void on_gesture_detected (Gesture gesture);
public signal void on_begin (double delta, uint64 time);
public signal void on_update (double delta, uint64 time);
public signal void on_end (double delta, uint64 time);

public class Gala.ToucheggBackend : Object, GestureBackend {
/**
* Gesture type as returned by the daemon.
*/
Expand Down Expand Up @@ -202,7 +197,7 @@ public class Gala.ToucheggBackend : Object {
switch (signal_name) {
case DBUS_ON_GESTURE_BEGIN:
Idle.add (() => {
on_gesture_detected (make_gesture (type, direction, fingers, performed_on_device_type));
on_gesture_detected (make_gesture (type, direction, fingers, performed_on_device_type), Meta.CURRENT_TIME);
on_begin (delta, elapsed_time);
return false;
});
Expand Down
43 changes: 20 additions & 23 deletions src/Widgets/MultitaskingView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,16 @@ namespace Gala {
multitasking_gesture_tracker = new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION);
multitasking_gesture_tracker.enable_touchpad ();
multitasking_gesture_tracker.on_gesture_detected.connect (on_multitasking_gesture_detected);
multitasking_gesture_tracker.on_gesture_handled.connect (() => toggle (true, false));

workspace_gesture_tracker = new GestureTracker (AnimationDuration.WORKSPACE_SWITCH_MIN, AnimationDuration.WORKSPACE_SWITCH);
workspace_gesture_tracker.enable_touchpad ();
workspace_gesture_tracker.enable_scroll (this, Clutter.Orientation.HORIZONTAL);
workspace_gesture_tracker.on_gesture_detected.connect (on_workspace_gesture_detected);
workspace_gesture_tracker.on_gesture_handled.connect ((gesture, timestamp) => {
var direction = workspace_gesture_tracker.settings.get_natural_scroll_direction (gesture);
switch_workspace_with_gesture (direction, timestamp);
});

workspaces = new Clutter.Actor ();

Expand Down Expand Up @@ -290,39 +295,31 @@ namespace Gala {
workspaces.add_transition ("nudge", nudge);
}

private void on_multitasking_gesture_detected (Gesture gesture) {
if (gesture.type != Clutter.EventType.TOUCHPAD_SWIPE ||
(gesture.fingers == 3 && GestureSettings.get_string ("three-finger-swipe-up") != "multitasking-view") ||
(gesture.fingers == 4 && GestureSettings.get_string ("four-finger-swipe-up") != "multitasking-view")
) {
return;
private bool on_multitasking_gesture_detected (Gesture gesture) {
if (GestureSettings.get_action (gesture) != MULTITASKING_VIEW) {
return false;
}

if (gesture.direction == GestureDirection.UP && !opened) {
toggle (true, false);
} else if (gesture.direction == GestureDirection.DOWN && opened) {
toggle (true, false);
if (gesture.direction == UP && !opened || gesture.direction == DOWN && opened) {
return true;
}

return false;
}

private void on_workspace_gesture_detected (Gesture gesture) {
private bool on_workspace_gesture_detected (Gesture gesture) {
if (!opened) {
return;
return false;
}

var can_handle_swipe = gesture.type == Clutter.EventType.TOUCHPAD_SWIPE &&
(gesture.direction == GestureDirection.LEFT || gesture.direction == GestureDirection.RIGHT);

var fingers = (gesture.fingers == 3 && Gala.GestureSettings.get_string ("three-finger-swipe-horizontal") == "switch-to-workspace") ||
(gesture.fingers == 4 && Gala.GestureSettings.get_string ("four-finger-swipe-horizontal") == "switch-to-workspace");

if (gesture.type == Clutter.EventType.SCROLL || (can_handle_swipe && fingers)) {
var direction = workspace_gesture_tracker.settings.get_natural_scroll_direction (gesture);
switch_workspace_with_gesture (direction);
if (gesture.type == SCROLL || GestureSettings.get_action (gesture) == SWITCH_WORKSPACE) {
return true;
}

return false;
}

private void switch_workspace_with_gesture (Meta.MotionDirection direction) {
private void switch_workspace_with_gesture (Meta.MotionDirection direction, uint32 timestamp) {
if (switching_workspace_in_progress) {
return;
}
Expand Down Expand Up @@ -380,7 +377,7 @@ namespace Gala {

switching_workspace_with_gesture = true;
if (target_workspace != null) {
target_workspace.activate (display.get_current_time ());
target_workspace.activate (timestamp);
}

if (is_nudge_animation) {
Expand Down
Loading

0 comments on commit ed01957

Please sign in to comment.