diff --git a/data/gala.gschema.xml b/data/gala.gschema.xml
index e6bff01ba..b727649b0 100644
--- a/data/gala.gschema.xml
+++ b/data/gala.gschema.xml
@@ -14,6 +14,12 @@
+
+
+
+
+
+
true
@@ -96,6 +102,11 @@
Whether hotcorners should be enabled when fullscreen window is opened
+
+ "none"
+ What action should be performed on Super + Scroll
+
+
diff --git a/src/SuperScrollAction.vala b/src/SuperScrollAction.vala
new file mode 100644
index 000000000..84698cb3a
--- /dev/null
+++ b/src/SuperScrollAction.vala
@@ -0,0 +1,45 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io)
+ */
+
+public class Gala.SuperScrollAction : Clutter.Action {
+ public signal bool triggered (uint32 timestamp, double dx, double dy);
+
+ public Meta.Display display { private get; construct; }
+
+ public SuperScrollAction (Meta.Display display) {
+ Object (display: display);
+ }
+
+ public override bool handle_event (Clutter.Event event) {
+ if (
+ event.get_type () == SCROLL &&
+ (event.get_state () & display.compositor_modifiers) != 0
+ ) {
+ double dx = 0.0, dy = 0.0;
+ switch (event.get_scroll_direction ()) {
+ case LEFT:
+ dx = -1.0;
+ break;
+ case RIGHT:
+ dx = 1.0;
+ break;
+ case UP:
+ dy = 1.0;
+ break;
+ case DOWN:
+ dy = -1.0;
+ break;
+ default:
+ break;
+ }
+
+ // TODO: support natural scroll settings
+
+ return triggered (event.get_time (), dx, dy);
+ }
+
+ return Clutter.EVENT_PROPAGATE;
+ }
+}
diff --git a/src/WindowManager.vala b/src/WindowManager.vala
index 5606d0488..8a1b90375 100644
--- a/src/WindowManager.vala
+++ b/src/WindowManager.vala
@@ -383,6 +383,10 @@ namespace Gala {
display.window_created.connect ((window) => window_created (window));
+ var scroll_action = new SuperScrollAction (display);
+ scroll_action.triggered.connect (handle_super_scroll);
+ stage.add_action_full ("wm-super-scroll-action", CAPTURE, scroll_action);
+
stage.show ();
plugin_manager.load_waiting_plugins ();
@@ -438,6 +442,23 @@ namespace Gala {
}
}
+
+ private bool handle_super_scroll (uint32 timestamp, double dx, double dy) {
+ if (behavior_settings.get_enum ("super-scroll-action") != 1) {
+ return Clutter.EVENT_PROPAGATE;
+ }
+
+ var d = dx.abs () > dy.abs () ? dx : dy;
+
+ if (d > 0) {
+ switch_to_next_workspace (Meta.MotionDirection.RIGHT, timestamp);
+ } else if (d < 0) {
+ switch_to_next_workspace (Meta.MotionDirection.LEFT, timestamp);
+ }
+
+ return Clutter.EVENT_STOP;
+ }
+
[CCode (instance_pos = -1)]
private void handle_cycle_workspaces (Meta.Display display, Meta.Window? window, Clutter.KeyEvent event,
Meta.KeyBinding binding) {
diff --git a/src/Zoom.vala b/src/Zoom.vala
index 9165bd1f7..e833f4134 100644
--- a/src/Zoom.vala
+++ b/src/Zoom.vala
@@ -19,6 +19,7 @@ public class Gala.Zoom : Object {
private ulong wins_handler_id = 0UL;
private GestureTracker gesture_tracker;
+ private GLib.Settings behavior_settings;
public Zoom (WindowManager wm) {
Object (wm: wm);
@@ -33,6 +34,12 @@ public class Gala.Zoom : Object {
gesture_tracker.enable_touchpad ();
gesture_tracker.on_gesture_detected.connect (on_gesture_detected);
gesture_tracker.on_gesture_handled.connect ((gesture) => zoom_with_gesture (gesture.direction));
+
+ behavior_settings = new GLib.Settings ("io.elementary.desktop.wm.behavior");
+
+ var scroll_action = new SuperScrollAction (display);
+ scroll_action.triggered.connect (handle_super_scroll);
+ display.get_stage ().add_action_full ("zoom-super-scroll-action", CAPTURE, scroll_action);
}
~Zoom () {
@@ -78,6 +85,22 @@ public class Gala.Zoom : Object {
return false;
}
+ private bool handle_super_scroll (uint32 timestamp, double dx, double dy) {
+ if (behavior_settings.get_enum ("super-scroll-action") != 2) {
+ return Clutter.EVENT_PROPAGATE;
+ }
+
+ var d = dx.abs () > dy.abs () ? dx : dy;
+
+ if (d > 0) {
+ zoom (SHORTCUT_DELTA, true, AnimationsSettings.get_enable_animations ());
+ } else if (d < 0) {
+ zoom (-SHORTCUT_DELTA, true, AnimationsSettings.get_enable_animations ());
+ }
+
+ return Clutter.EVENT_STOP;
+ }
+
private void zoom_with_gesture (GestureDirection direction) {
var initial_zoom = current_zoom;
var target_zoom = (direction == GestureDirection.IN)
diff --git a/src/meson.build b/src/meson.build
index 70d9d7b97..9660dd2b8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -14,6 +14,7 @@ gala_bin_sources = files(
'ScreenSaverManager.vala',
'ScreenshotManager.vala',
'SessionManager.vala',
+ 'SuperScrollAction.vala',
'WindowAttentionTracker.vala',
'WindowGrabTracker.vala',
'WindowListener.vala',