Skip to content
Closed
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
43 changes: 24 additions & 19 deletions src/Gestures/Gesture.vala
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

namespace Gala {
/**
* Physical direction of the gesture. This direction doesn't follow natural scroll preferences.
* Physical direction of the gesture.
*/
public enum GestureDirection {
UNKNOWN = 0,
Expand All @@ -34,26 +34,31 @@ namespace Gala {
OUT = 6,
}

public class Gesture {
public const float INVALID_COORD = float.MAX;
/**
* Action triggered by the gesture.
*/
public class GestureAction {
public enum Type {
NONE,
CUSTOM, // Means we have less than three fingers. Usually only emitted if we are interacting with a component itself e.g. MultitaskingView
SWITCH_WORKSPACE,
MOVE_TO_WORKSPACE,
SWITCH_WINDOWS,
MULTITASKING_VIEW,
ZOOM
}

public Clutter.EventType type;
public GestureDirection direction;
public int fingers;
public Clutter.InputDeviceType performed_on_device_type;
public enum Direction {
FORWARD,
BACKWARD
}

/**
* 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;
public GestureAction (Type type, Direction direction) {
this.type = type;
this.direction = direction;
}

/**
* 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;
public Type type;
public Direction direction;
}
}
101 changes: 50 additions & 51 deletions src/Gestures/GestureSettings.vala
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,6 @@
* 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 All @@ -36,82 +28,89 @@ public class Gala.GestureSettings : Object {
touchpad_settings = new GLib.Settings ("org.gnome.desktop.peripherals.touchpad");
}

public bool is_natural_scroll_enabled (Clutter.InputDeviceType device_type) {
public static bool is_natural_scroll_enabled (Clutter.InputDeviceType device_type) {
return (device_type == Clutter.InputDeviceType.TOUCHSCREEN_DEVICE)
? true
: touchpad_settings.get_boolean ("natural-scroll");
}

public Meta.MotionDirection? get_direction (Gesture gesture) {
switch (gesture.direction) {
case GestureDirection.UP:
return Meta.MotionDirection.UP;
case GestureDirection.DOWN:
return Meta.MotionDirection.DOWN;
case GestureDirection.LEFT:
return Meta.MotionDirection.LEFT;
case GestureDirection.RIGHT:
return Meta.MotionDirection.RIGHT;
default:
return null;
}
public static string get_string (string setting_id) {
return gala_settings.get_string (setting_id);
}

public Meta.MotionDirection? get_natural_scroll_direction (Gesture gesture) {
bool natural_scroll = is_natural_scroll_enabled (gesture.performed_on_device_type);

switch (gesture.direction) {
case GestureDirection.UP:
return natural_scroll ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP;
case GestureDirection.DOWN:
return natural_scroll ? Meta.MotionDirection.UP : Meta.MotionDirection.DOWN;
case GestureDirection.LEFT:
return natural_scroll ? Meta.MotionDirection.RIGHT : Meta.MotionDirection.LEFT;
case GestureDirection.RIGHT:
return natural_scroll ? Meta.MotionDirection.LEFT : Meta.MotionDirection.RIGHT;
private static GestureAction.Direction get_action_direction (GestureDirection direction) {
switch (direction) {
case LEFT:
case RIGHT:
return direction == RIGHT ? GestureAction.Direction.FORWARD : GestureAction.Direction.BACKWARD;

case DOWN:
case UP:
return direction == UP ? GestureAction.Direction.FORWARD : GestureAction.Direction.BACKWARD;

case IN:
case OUT:
return direction == IN ? GestureAction.Direction.FORWARD : GestureAction.Direction.BACKWARD;

default:
return null;
return FORWARD;
}
}

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;
public static GestureAction get_action (int fingers, GestureDirection direction) {
if (fingers <= 2) {
return new GestureAction (CUSTOM, get_action_direction (direction));
}

if (gesture.direction == LEFT || gesture.direction == RIGHT) {
switch (direction) {
case RIGHT:
case LEFT:
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;
return new GestureAction (SWITCH_WORKSPACE, get_action_direction (direction));
}

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


if (fingers == 3 && three_finger_swipe_horizontal == "switch-windows" ||
fingers == 4 && four_finger_swipe_horizontal == "switch-windows") {
return SWITCH_WINDOWS;
return new GestureAction (SWITCH_WINDOWS, get_action_direction (direction));
}
} else if (gesture.direction == UP || gesture.direction == DOWN) {

break;

case UP:
case 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 new GestureAction (MULTITASKING_VIEW, get_action_direction (direction));
}
}

break;

case IN:
case OUT:
if ((fingers == 3 && GestureSettings.get_string ("three-finger-pinch") == "zoom") ||
(fingers == 4 && GestureSettings.get_string ("four-finger-pinch") == "zoom")
) {
return new GestureAction (ZOOM, get_action_direction (direction));
}

break;

default:
break;
}

return NONE;
return new GestureAction (NONE, FORWARD);
}
}
18 changes: 9 additions & 9 deletions src/Gestures/GestureTracker.vala
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

public interface Gala.GestureBackend : Object {
public signal bool on_gesture_detected (Gesture gesture, uint32 timestamp);
public signal bool on_gesture_detected (GestureAction action, 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);
Expand Down Expand Up @@ -83,20 +83,20 @@ public class Gala.GestureTracker : Object {
* 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.
* @param action 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 bool on_gesture_detected (Gesture gesture);
public signal bool on_gesture_detected (GestureAction action);

/**
* 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 action 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);
public signal void on_gesture_handled (GestureAction action, uint32 timestamp);

/**
* Emitted right after on_gesture_detected with the initial gesture information.
Expand Down Expand Up @@ -171,7 +171,7 @@ public class Gala.GestureTracker : Object {
* @param orientation If we are interested in the horizontal or vertical axis.
*/
public void enable_scroll (Clutter.Actor actor, Clutter.Orientation orientation) {
scroll_backend = new ScrollBackend (actor, orientation, settings);
scroll_backend = new ScrollBackend (actor, orientation);
scroll_backend.on_gesture_detected.connect (gesture_detected);
scroll_backend.on_begin.connect (gesture_begin);
scroll_backend.on_update.connect (gesture_update);
Expand Down Expand Up @@ -246,10 +246,10 @@ public class Gala.GestureTracker : Object {
return value;
}

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

Expand Down
62 changes: 27 additions & 35 deletions src/Gestures/ScrollBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,21 @@ public class Gala.ScrollBackend : Object, GestureBackend {

public Clutter.Actor actor { get; construct; }
public Clutter.Orientation orientation { get; construct; }
public GestureSettings settings { get; construct; }

private bool started;
private double delta_x;
private double delta_y;
private GestureDirection direction;
private GestureAction.Direction direction;

construct {
started = false;
delta_x = 0;
delta_y = 0;
direction = GestureDirection.UNKNOWN;
direction = FORWARD;
}

public ScrollBackend (Clutter.Actor actor, Clutter.Orientation orientation, GestureSettings settings) {
Object (actor: actor, orientation: orientation, settings: settings);
public ScrollBackend (Clutter.Actor actor, Clutter.Orientation orientation) {
Object (actor: actor, orientation: orientation);

actor.scroll_event.connect (on_scroll_event);
}
Expand All @@ -64,7 +63,7 @@ public class Gala.ScrollBackend : Object, GestureBackend {
// Scroll events apply the natural scroll preferences out of the box
// Standardize them so the direction matches the physical direction of the gesture and the
// GestureTracker user can decide if it wants to follow natural scroll settings or not
bool natural_scroll = settings.is_natural_scroll_enabled (Clutter.InputDeviceType.TOUCHPAD_DEVICE);
bool natural_scroll = GestureSettings.is_natural_scroll_enabled (Clutter.InputDeviceType.TOUCHPAD_DEVICE);
if (natural_scroll) {
x *= -1;
y *= -1;
Expand All @@ -77,21 +76,21 @@ public class Gala.ScrollBackend : Object, GestureBackend {
if (delta_x != 0 || delta_y != 0) {
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);
GestureAction action = build_gesture (delta_x, delta_y);
started = true;
direction = gesture.direction;
on_gesture_detected (gesture, time);
direction = action.direction;
on_gesture_detected (action, time);

double delta = calculate_delta (delta_x, delta_y, direction);
double delta = calculate_delta (delta_x, delta_y);
on_begin (delta, time);
}
} else {
double delta = calculate_delta (delta_x, delta_y, direction);
double delta = calculate_delta (delta_x, delta_y);
if (x == 0 && y == 0) {
started = false;
delta_x = 0;
delta_y = 0;
direction = GestureDirection.UNKNOWN;
direction = FORWARD;
on_end (delta, time);
} else {
on_update (delta, time);
Expand All @@ -101,41 +100,34 @@ public class Gala.ScrollBackend : Object, GestureBackend {
return true;
}

#if HAS_MUTTER45
private static bool can_handle_event (Clutter.Event event) {
#else
private static bool can_handle_event (Clutter.ScrollEvent event) {
#endif
return event.get_type () == Clutter.EventType.SCROLL
&& event.get_source_device ().get_device_type () == Clutter.InputDeviceType.TOUCHPAD_DEVICE
&& event.get_scroll_direction () == Clutter.ScrollDirection.SMOOTH;
}

private static Gesture build_gesture (float origin_x, float origin_y, double delta_x, double delta_y, Clutter.Orientation orientation, uint32 timestamp) {
private GestureAction build_gesture (double delta_x, double delta_y) {
GestureDirection direction;
if (orientation == Clutter.Orientation.HORIZONTAL) {
if (orientation == HORIZONTAL) {
direction = delta_x > 0 ? GestureDirection.RIGHT : GestureDirection.LEFT;
} else {
direction = delta_y > 0 ? GestureDirection.DOWN : GestureDirection.UP;
}

return new Gesture () {
type = Clutter.EventType.SCROLL,
direction = direction,
fingers = 2,
performed_on_device_type = Clutter.InputDeviceType.TOUCHPAD_DEVICE,
origin_x = origin_x,
origin_y = origin_y
};
return GestureSettings.get_action (2, direction);
}

private static double calculate_delta (double delta_x, double delta_y, GestureDirection direction) {
bool is_horizontal = (direction == GestureDirection.LEFT || direction == GestureDirection.RIGHT);
private double calculate_delta (double delta_x, double delta_y) {
bool is_horizontal = orientation == HORIZONTAL;
double used_delta = is_horizontal ? delta_x : delta_y;
double finish_delta = is_horizontal ? FINISH_DELTA_HORIZONTAL : FINISH_DELTA_VERTICAL;

bool is_positive = (direction == GestureDirection.RIGHT || direction == GestureDirection.DOWN);
bool is_positive = direction == FORWARD;

return (used_delta / finish_delta) * (is_positive ? 1 : -1);
}

#if HAS_MUTTER45
private static bool can_handle_event (Clutter.Event event) {
#else
private static bool can_handle_event (Clutter.ScrollEvent event) {
#endif
return event.get_type () == Clutter.EventType.SCROLL
&& event.get_source_device ().get_device_type () == Clutter.InputDeviceType.TOUCHPAD_DEVICE
&& event.get_scroll_direction () == Clutter.ScrollDirection.SMOOTH;
}
}
Loading
Loading