Skip to content

Commit 0e82d63

Browse files
Gestures: Add more details and introduce on_gesture_handled (#2168)
Co-authored-by: Leo <[email protected]>
1 parent 6f0093a commit 0e82d63

File tree

8 files changed

+156
-91
lines changed

8 files changed

+156
-91
lines changed

src/Gestures/Gesture.vala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,25 @@ namespace Gala {
3535
}
3636

3737
public class Gesture {
38+
public const float INVALID_COORD = float.MAX;
39+
3840
public Clutter.EventType type;
3941
public GestureDirection direction;
4042
public int fingers;
4143
public Clutter.InputDeviceType performed_on_device_type;
44+
45+
/**
46+
* The x coordinate of the initial contact point for the gesture.
47+
* Doesn't have to be set. In that case it is set to {@link INVALID_COORD}.
48+
* Currently the only backend not setting this is {@link GestureTracker.enable_touchpad}.
49+
*/
50+
public float origin_x = INVALID_COORD;
51+
52+
/**
53+
* The y coordinate of the initial contact point for the gesture.
54+
* Doesn't have to be set. In that case it is set to {@link INVALID_COORD}.
55+
* Currently the only backend not setting this is {@link GestureTracker.enable_touchpad}.
56+
*/
57+
public float origin_y = INVALID_COORD;
4258
}
4359
}

src/Gestures/GestureSettings.vala

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
* Utility class to access the gesture settings. Easily accessible through GestureTracker.settings.
2121
*/
2222
public class Gala.GestureSettings : Object {
23+
public enum GestureAction {
24+
NONE,
25+
SWITCH_WORKSPACE,
26+
MOVE_TO_WORKSPACE,
27+
SWITCH_WINDOWS,
28+
MULTITASKING_VIEW
29+
}
30+
2331
private static GLib.Settings gala_settings;
2432
private static GLib.Settings touchpad_settings;
2533

@@ -69,4 +77,41 @@ public class Gala.GestureSettings : Object {
6977
public static string get_string (string setting_id) {
7078
return gala_settings.get_string (setting_id);
7179
}
80+
81+
public static GestureAction get_action (Gesture gesture) {
82+
if (gesture.type == TOUCHPAD_SWIPE) {
83+
var fingers = gesture.fingers;
84+
85+
if (gesture.direction == LEFT || gesture.direction == RIGHT) {
86+
var three_finger_swipe_horizontal = get_string ("three-finger-swipe-horizontal");
87+
var four_finger_swipe_horizontal = get_string ("four-finger-swipe-horizontal");
88+
89+
if (fingers == 3 && three_finger_swipe_horizontal == "switch-to-workspace" ||
90+
fingers == 4 && four_finger_swipe_horizontal == "switch-to-workspace") {
91+
return SWITCH_WORKSPACE;
92+
}
93+
94+
if (fingers == 3 && three_finger_swipe_horizontal == "move-to-workspace" ||
95+
fingers == 4 && four_finger_swipe_horizontal == "move-to-workspace") {
96+
return MOVE_TO_WORKSPACE;
97+
}
98+
99+
100+
if (fingers == 3 && three_finger_swipe_horizontal == "switch-windows" ||
101+
fingers == 4 && four_finger_swipe_horizontal == "switch-windows") {
102+
return SWITCH_WINDOWS;
103+
}
104+
} else if (gesture.direction == UP || gesture.direction == DOWN) {
105+
var three_finger_swipe_up = get_string ("three-finger-swipe-up");
106+
var four_finger_swipe_up = get_string ("four-finger-swipe-up");
107+
108+
if (fingers == 3 && three_finger_swipe_up == "multitasking-view" ||
109+
fingers == 4 && four_finger_swipe_up == "multitasking-view") {
110+
return MULTITASKING_VIEW;
111+
}
112+
}
113+
}
114+
115+
return NONE;
116+
}
72117
}

src/Gestures/GestureTracker.vala

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@
1616
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1717
*/
1818

19+
public interface Gala.GestureBackend : Object {
20+
public signal bool on_gesture_detected (Gesture gesture, uint32 timestamp);
21+
public signal void on_begin (double delta, uint64 time);
22+
public signal void on_update (double delta, uint64 time);
23+
public signal void on_end (double delta, uint64 time);
24+
25+
public virtual void prepare_gesture_handling () { }
26+
}
27+
1928
/**
2029
* Allow to use multi-touch gestures from different sources (backends).
2130
* Usage:
@@ -68,11 +77,24 @@ public class Gala.GestureTracker : Object {
6877

6978
/**
7079
* Emitted when a new gesture is detected.
71-
* If the receiving code needs to handle this gesture, it should call to connect_handlers to
72-
* start receiving updates.
80+
* This should only be used to determine whether the gesture should be handled. This shouldn't
81+
* do any preparations instead those should be done in {@link on_gesture_handled}. This is because
82+
* the backend might have to do some preparations itself before you are allowed to do some to avoid
83+
* conflicts.
7384
* @param gesture Information about the gesture.
85+
* @return true if the gesture will be handled false otherwise. If false is returned the other
86+
* signals may still be emitted but aren't guaranteed to be.
7487
*/
75-
public signal void on_gesture_detected (Gesture gesture);
88+
public signal bool on_gesture_detected (Gesture gesture);
89+
90+
/**
91+
* Emitted if true was returned form {@link on_gesture_detected}. This should
92+
* be used to do any preparations for gesture handling and to call {@link connect_handlers} to
93+
* start receiving updates.
94+
* @param gesture the same gesture as in {@link on_gesture_detected}
95+
* @param timestamp the timestamp of the event that initiated the gesture or {@link Meta.CURRENT_TIME}.
96+
*/
97+
public signal void on_gesture_handled (Gesture gesture, uint32 timestamp);
7698

7799
/**
78100
* Emitted right after on_gesture_detected with the initial gesture information.
@@ -205,10 +227,14 @@ public class Gala.GestureTracker : Object {
205227
return value;
206228
}
207229

208-
private void gesture_detected (Gesture gesture) {
209-
if (enabled) {
210-
on_gesture_detected (gesture);
230+
private bool gesture_detected (GestureBackend backend, Gesture gesture, uint32 timestamp) {
231+
if (enabled && on_gesture_detected (gesture)) {
232+
backend.prepare_gesture_handling ();
233+
on_gesture_handled (gesture, timestamp);
234+
return true;
211235
}
236+
237+
return false;
212238
}
213239

214240
private void gesture_begin (double percentage, uint64 elapsed_time) {

src/Gestures/ScrollBackend.vala

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,13 @@
1919
/**
2020
* This gesture backend transforms the touchpad scroll events received by an actor into gestures.
2121
*/
22-
public class Gala.ScrollBackend : Object {
22+
public class Gala.ScrollBackend : Object, GestureBackend {
2323
// Mutter does not expose the size of the touchpad, so we use the same values as GTK apps.
2424
// From GNOME Shell, TOUCHPAD_BASE_[WIDTH|HEIGHT] / SCROLL_MULTIPLIER
2525
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/swipeTracker.js
2626
private const double FINISH_DELTA_HORIZONTAL = 40;
2727
private const double FINISH_DELTA_VERTICAL = 30;
2828

29-
public signal void on_gesture_detected (Gesture gesture);
30-
public signal void on_begin (double delta, uint64 time);
31-
public signal void on_update (double delta, uint64 time);
32-
public signal void on_end (double delta, uint64 time);
33-
3429
public Clutter.Actor actor { get; construct; }
3530
public Clutter.Orientation orientation { get; construct; }
3631
public GestureSettings settings { get; construct; }
@@ -62,7 +57,7 @@ public class Gala.ScrollBackend : Object {
6257
return false;
6358
}
6459

65-
uint64 time = event.get_time ();
60+
var time = event.get_time ();
6661
double x, y;
6762
event.get_scroll_delta (out x, out y);
6863

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

8176
if (!started) {
8277
if (delta_x != 0 || delta_y != 0) {
83-
Gesture gesture = build_gesture (delta_x, delta_y, orientation);
78+
float origin_x, origin_y;
79+
event.get_coords (out origin_x, out origin_y);
80+
Gesture gesture = build_gesture (origin_x, origin_y, delta_x, delta_y, orientation, time);
8481
started = true;
8582
direction = gesture.direction;
86-
on_gesture_detected (gesture);
83+
on_gesture_detected (gesture, time);
8784

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

117-
private static Gesture build_gesture (double delta_x, double delta_y, Clutter.Orientation orientation) {
114+
private static Gesture build_gesture (float origin_x, float origin_y, double delta_x, double delta_y, Clutter.Orientation orientation, uint32 timestamp) {
118115
GestureDirection direction;
119116
if (orientation == Clutter.Orientation.HORIZONTAL) {
120117
direction = delta_x > 0 ? GestureDirection.RIGHT : GestureDirection.LEFT;
@@ -126,7 +123,9 @@ public class Gala.ScrollBackend : Object {
126123
type = Clutter.EventType.SCROLL,
127124
direction = direction,
128125
fingers = 2,
129-
performed_on_device_type = Clutter.InputDeviceType.TOUCHPAD_DEVICE
126+
performed_on_device_type = Clutter.InputDeviceType.TOUCHPAD_DEVICE,
127+
origin_x = origin_x,
128+
origin_y = origin_y
130129
};
131130
}
132131

src/Gestures/ToucheggBackend.vala

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@
2020
* Singleton class to manage the connection with Touchégg daemon and receive touch events.
2121
* See: [[https://github.com/JoseExposito/touchegg]]
2222
*/
23-
public class Gala.ToucheggBackend : Object {
24-
public signal void on_gesture_detected (Gesture gesture);
25-
public signal void on_begin (double delta, uint64 time);
26-
public signal void on_update (double delta, uint64 time);
27-
public signal void on_end (double delta, uint64 time);
28-
23+
public class Gala.ToucheggBackend : Object, GestureBackend {
2924
/**
3025
* Gesture type as returned by the daemon.
3126
*/
@@ -202,7 +197,7 @@ public class Gala.ToucheggBackend : Object {
202197
switch (signal_name) {
203198
case DBUS_ON_GESTURE_BEGIN:
204199
Idle.add (() => {
205-
on_gesture_detected (make_gesture (type, direction, fingers, performed_on_device_type));
200+
on_gesture_detected (make_gesture (type, direction, fingers, performed_on_device_type), Meta.CURRENT_TIME);
206201
on_begin (delta, elapsed_time);
207202
return false;
208203
});

src/Widgets/MultitaskingView.vala

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,13 @@ namespace Gala {
7171
multitasking_gesture_tracker = new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION);
7272
multitasking_gesture_tracker.enable_touchpad ();
7373
multitasking_gesture_tracker.on_gesture_detected.connect (on_multitasking_gesture_detected);
74+
multitasking_gesture_tracker.on_gesture_handled.connect (() => toggle (true, false));
7475

7576
workspace_gesture_tracker = new GestureTracker (AnimationDuration.WORKSPACE_SWITCH_MIN, AnimationDuration.WORKSPACE_SWITCH);
7677
workspace_gesture_tracker.enable_touchpad ();
7778
workspace_gesture_tracker.enable_scroll (this, Clutter.Orientation.HORIZONTAL);
7879
workspace_gesture_tracker.on_gesture_detected.connect (on_workspace_gesture_detected);
80+
workspace_gesture_tracker.on_gesture_handled.connect (switch_workspace_with_gesture);
7981

8082
workspaces = new Clutter.Actor ();
8183

@@ -290,43 +292,37 @@ namespace Gala {
290292
workspaces.add_transition ("nudge", nudge);
291293
}
292294

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

301-
if (gesture.direction == GestureDirection.UP && !opened) {
302-
toggle (true, false);
303-
} else if (gesture.direction == GestureDirection.DOWN && opened) {
304-
toggle (true, false);
300+
if (gesture.direction == UP && !opened || gesture.direction == DOWN && opened) {
301+
return true;
305302
}
303+
304+
return false;
306305
}
307306

308-
private void on_workspace_gesture_detected (Gesture gesture) {
307+
private bool on_workspace_gesture_detected (Gesture gesture) {
309308
if (!opened) {
310-
return;
309+
return false;
311310
}
312311

313-
var can_handle_swipe = gesture.type == Clutter.EventType.TOUCHPAD_SWIPE &&
314-
(gesture.direction == GestureDirection.LEFT || gesture.direction == GestureDirection.RIGHT);
315-
316-
var fingers = (gesture.fingers == 3 && Gala.GestureSettings.get_string ("three-finger-swipe-horizontal") == "switch-to-workspace") ||
317-
(gesture.fingers == 4 && Gala.GestureSettings.get_string ("four-finger-swipe-horizontal") == "switch-to-workspace");
318-
319-
if (gesture.type == Clutter.EventType.SCROLL || (can_handle_swipe && fingers)) {
320-
var direction = workspace_gesture_tracker.settings.get_natural_scroll_direction (gesture);
321-
switch_workspace_with_gesture (direction);
312+
if (gesture.type == SCROLL || GestureSettings.get_action (gesture) == SWITCH_WORKSPACE) {
313+
return true;
322314
}
315+
316+
return false;
323317
}
324318

325-
private void switch_workspace_with_gesture (Meta.MotionDirection direction) {
319+
private void switch_workspace_with_gesture (Gesture gesture, uint32 timestamp) {
326320
if (switching_workspace_in_progress) {
327321
return;
328322
}
329323

324+
var direction = workspace_gesture_tracker.settings.get_natural_scroll_direction (gesture);
325+
330326
unowned var manager = display.get_workspace_manager ();
331327
var num_workspaces = manager.get_n_workspaces ();
332328
var relative_dir = (direction == Meta.MotionDirection.LEFT) ? -1 : 1;

src/WindowManager.vala

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ namespace Gala {
120120
gesture_tracker = new GestureTracker (AnimationDuration.WORKSPACE_SWITCH_MIN, AnimationDuration.WORKSPACE_SWITCH);
121121
gesture_tracker.enable_touchpad ();
122122
gesture_tracker.on_gesture_detected.connect (on_gesture_detected);
123+
gesture_tracker.on_gesture_handled.connect (on_gesture_handled);
123124

124125
info = Meta.PluginInfo () {name = "Gala", version = Config.VERSION, author = "Gala Developers",
125126
license = "GPLv3", description = "A nice elementary window manager"};
@@ -553,57 +554,41 @@ namespace Gala {
553554
}
554555
}
555556

556-
private void on_gesture_detected (Gesture gesture) {
557+
private bool on_gesture_detected (Gesture gesture) {
557558
if (workspace_view.is_opened ()) {
558-
return;
559-
}
560-
561-
if (gesture.type != Clutter.EventType.TOUCHPAD_SWIPE ||
562-
(gesture.direction != GestureDirection.LEFT && gesture.direction != GestureDirection.RIGHT)) {
563-
return;
559+
return false;
564560
}
565561

566-
unowned var display = get_display ();
567-
568-
var fingers = gesture.fingers;
569-
570-
var three_finger_swipe_horizontal = GestureSettings.get_string ("three-finger-swipe-horizontal");
571-
var four_finger_swipe_horizontal = GestureSettings.get_string ("four-finger-swipe-horizontal");
572-
573-
var three_fingers_switch_to_workspace = fingers == 3 && three_finger_swipe_horizontal == "switch-to-workspace";
574-
var four_fingers_switch_to_workspace = fingers == 4 && four_finger_swipe_horizontal == "switch-to-workspace";
575-
576-
var three_fingers_move_to_workspace = fingers == 3 && three_finger_swipe_horizontal == "move-to-workspace";
577-
var four_fingers_move_to_workspace = fingers == 4 && four_finger_swipe_horizontal == "move-to-workspace";
578-
579-
var three_fingers_switch_windows = fingers == 3 && three_finger_swipe_horizontal == "switch-windows";
580-
var four_fingers_switch_windows = fingers == 4 && four_finger_swipe_horizontal == "switch-windows";
562+
var action = GestureSettings.get_action (gesture);
563+
switch_workspace_with_gesture = action == SWITCH_WORKSPACE || action == MOVE_TO_WORKSPACE;
564+
return switch_workspace_with_gesture || (action == SWITCH_WINDOWS && !window_switcher.opened);
565+
}
581566

582-
switch_workspace_with_gesture = three_fingers_switch_to_workspace || four_fingers_switch_to_workspace;
583-
if (switch_workspace_with_gesture) {
584-
var direction = gesture_tracker.settings.get_natural_scroll_direction (gesture);
585-
switch_to_next_workspace (direction, display.get_current_time ());
586-
return;
587-
}
567+
private void on_gesture_handled (Gesture gesture, uint32 timestamp) {
568+
var direction = gesture_tracker.settings.get_natural_scroll_direction (gesture);
588569

589-
switch_workspace_with_gesture = three_fingers_move_to_workspace || four_fingers_move_to_workspace;
590-
if (switch_workspace_with_gesture) {
591-
unowned var manager = display.get_workspace_manager ();
570+
switch (GestureSettings.get_action (gesture)) {
571+
case MOVE_TO_WORKSPACE:
572+
unowned var display = get_display ();
573+
unowned var manager = display.get_workspace_manager ();
592574

593-
var direction = gesture_tracker.settings.get_natural_scroll_direction (gesture);
575+
moving = display.focus_window;
576+
if (moving != null) {
577+
moving.change_workspace (manager.get_active_workspace ().get_neighbor (direction));
578+
}
579+
switch_to_next_workspace (direction, timestamp);
580+
break;
594581

595-
moving = display.focus_window;
596-
if (moving != null) {
597-
moving.change_workspace (manager.get_active_workspace ().get_neighbor (direction));
598-
}
582+
case SWITCH_WORKSPACE:
583+
switch_to_next_workspace (direction, timestamp);
584+
break;
599585

600-
switch_to_next_workspace (direction, display.get_current_time ());
601-
return;
602-
}
586+
case SWITCH_WINDOWS:
587+
window_switcher.handle_gesture (gesture.direction);
588+
break;
603589

604-
var switch_windows = three_fingers_switch_windows || four_fingers_switch_windows;
605-
if (switch_windows && !window_switcher.opened) {
606-
window_switcher.handle_gesture (gesture.direction);
590+
default:
591+
break;
607592
}
608593
}
609594

0 commit comments

Comments
 (0)