Skip to content

Commit da35598

Browse files
authored
Merge branch 'main' into leolost/interruptible-workspace-switch-mtv
2 parents e6af97a + c7d14d6 commit da35598

File tree

11 files changed

+256
-90
lines changed

11 files changed

+256
-90
lines changed

data/gala.gschema.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414
<value nick="switch-to-workspace-last" value="10" />
1515
</enum>
1616

17+
<enum id="SuperScrollAction">
18+
<value nick="none" value="0" />
19+
<value nick="switch-workspace" value="1" />
20+
<value nick="zoom" value="2" />
21+
</enum>
22+
1723
<schema path="/io/elementary/desktop/screensaver/" id="io.elementary.desktop.screensaver">
1824
<key type="b" name="lock-on-suspend">
1925
<default>true</default>
@@ -96,6 +102,11 @@
96102
<summary>Whether hotcorners should be enabled when fullscreen window is opened</summary>
97103
<description></description>
98104
</key>
105+
<key enum="SuperScrollAction" name="super-scroll-action">
106+
<default>"none"</default>
107+
<summary>What action should be performed on Super + Scroll</summary>
108+
<description></description>
109+
</key>
99110
</schema>
100111

101112
<schema path="/io/elementary/desktop/wm/keybindings/" id="io.elementary.desktop.wm.keybindings">

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/SuperScrollAction.vala

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* SPDX-License-Identifier: GPL-3.0-or-later
3+
* SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io)
4+
*/
5+
6+
public class Gala.SuperScrollAction : Clutter.Action {
7+
public signal bool triggered (uint32 timestamp, double dx, double dy);
8+
9+
public Meta.Display display { private get; construct; }
10+
11+
public SuperScrollAction (Meta.Display display) {
12+
Object (display: display);
13+
}
14+
15+
public override bool handle_event (Clutter.Event event) {
16+
if (
17+
event.get_type () == SCROLL &&
18+
(event.get_state () & display.compositor_modifiers) != 0
19+
) {
20+
double dx = 0.0, dy = 0.0;
21+
switch (event.get_scroll_direction ()) {
22+
case LEFT:
23+
dx = -1.0;
24+
break;
25+
case RIGHT:
26+
dx = 1.0;
27+
break;
28+
case UP:
29+
dy = 1.0;
30+
break;
31+
case DOWN:
32+
dy = -1.0;
33+
break;
34+
default:
35+
break;
36+
}
37+
38+
// TODO: support natural scroll settings
39+
40+
return triggered (event.get_time (), dx, dy);
41+
}
42+
43+
return Clutter.EVENT_PROPAGATE;
44+
}
45+
}

src/Widgets/MultitaskingView.vala

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ namespace Gala {
6666
multitasking_gesture_tracker = new GestureTracker (ANIMATION_DURATION, ANIMATION_DURATION);
6767
multitasking_gesture_tracker.enable_touchpad ();
6868
multitasking_gesture_tracker.on_gesture_detected.connect (on_multitasking_gesture_detected);
69+
multitasking_gesture_tracker.on_gesture_handled.connect (() => toggle (true, false));
6970

7071
workspace_gesture_tracker = new GestureTracker (AnimationDuration.WORKSPACE_SWITCH_MIN, AnimationDuration.WORKSPACE_SWITCH);
7172
workspace_gesture_tracker.enable_touchpad ();
7273
workspace_gesture_tracker.enable_scroll (this, Clutter.Orientation.HORIZONTAL);
7374
workspace_gesture_tracker.on_gesture_detected.connect (on_workspace_gesture_detected);
75+
workspace_gesture_tracker.on_gesture_handled.connect (switch_workspace_with_gesture);
7476

7577
workspaces = new Clutter.Actor ();
7678

@@ -285,39 +287,33 @@ namespace Gala {
285287
workspaces.add_transition ("nudge", nudge);
286288
}
287289

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

296-
if (gesture.direction == GestureDirection.UP && !opened) {
297-
toggle (true, false);
298-
} else if (gesture.direction == GestureDirection.DOWN && opened) {
299-
toggle (true, false);
295+
if (gesture.direction == UP && !opened || gesture.direction == DOWN && opened) {
296+
return true;
300297
}
298+
299+
return false;
301300
}
302301

303-
private void on_workspace_gesture_detected (Gesture gesture) {
302+
private bool on_workspace_gesture_detected (Gesture gesture) {
304303
if (!opened) {
305-
return;
304+
return false;
306305
}
307306

308-
var can_handle_swipe = gesture.type == Clutter.EventType.TOUCHPAD_SWIPE &&
309-
(gesture.direction == GestureDirection.LEFT || gesture.direction == GestureDirection.RIGHT);
310-
311-
var fingers = (gesture.fingers == 3 && Gala.GestureSettings.get_string ("three-finger-swipe-horizontal") == "switch-to-workspace") ||
312-
(gesture.fingers == 4 && Gala.GestureSettings.get_string ("four-finger-swipe-horizontal") == "switch-to-workspace");
313-
314-
if (gesture.type == Clutter.EventType.SCROLL || (can_handle_swipe && fingers)) {
315-
var direction = workspace_gesture_tracker.settings.get_natural_scroll_direction (gesture);
316-
switch_workspace_with_gesture (direction);
307+
if (gesture.type == SCROLL || GestureSettings.get_action (gesture) == SWITCH_WORKSPACE) {
308+
return true;
317309
}
310+
311+
return false;
318312
}
319313

320314
private void switch_workspace_with_gesture (Meta.MotionDirection direction) {
315+
var direction = workspace_gesture_tracker.settings.get_natural_scroll_direction (gesture);
316+
321317
unowned var manager = display.get_workspace_manager ();
322318
var num_workspaces = manager.get_n_workspaces ();
323319
var relative_dir = (direction == Meta.MotionDirection.LEFT) ? -1 : 1;

0 commit comments

Comments
 (0)