[gnome-shell/wip/exalm/gestures-part-3: 4/4] windowManager: Use SwipeTracker



commit 02d0f30d7f67f016af73b812a578f4d51f993317
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Sun Jun 30 17:15:44 2019 +0500

    windowManager: Use SwipeTracker
    
    Replace existing four-finger gestures with SwipeTracker.
    
    Since TouchpadWorkspaceSwitchAction and WorkspaceSwitchAction are now
    unused, remove them.
    
    Change programmatic workspace transition to use easeOutCubic interpolator
    to match the gesture.
    
    Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/756
    
    https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/826

 js/ui/windowManager.js | 386 +++++++++++++++++++++++--------------------------
 1 file changed, 177 insertions(+), 209 deletions(-)
---
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 7716bab741..7fa3262860 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -2,7 +2,6 @@
 /* exported WindowManager */
 
 const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
-const Signals = imports.signals;
 
 const AltTab = imports.ui.altTab;
 const AppFavorites = imports.ui.appFavorites;
@@ -15,6 +14,7 @@ const WindowMenu = imports.ui.windowMenu;
 const PadOsd = imports.ui.padOsd;
 const EdgeDragAction = imports.ui.edgeDragAction;
 const CloseDialog = imports.ui.closeDialog;
+const SwipeTracker = imports.ui.swipeTracker;
 const SwitchMonitor = imports.ui.switchMonitor;
 const IBusManager = imports.misc.ibusManager;
 
@@ -30,7 +30,6 @@ var WINDOW_ANIMATION_TIME = 250;
 var DIM_BRIGHTNESS = -0.3;
 var DIM_TIME = 500;
 var UNDIM_TIME = 250;
-var WS_MOTION_THRESHOLD = 100;
 var APP_MOTION_THRESHOLD = 30;
 
 var ONE_SECOND = 1000; // in ms
@@ -468,147 +467,6 @@ class TilePreview extends St.Widget {
     }
 });
 
-var TouchpadWorkspaceSwitchAction = class {
-    constructor(actor, allowedModes) {
-        this._allowedModes = allowedModes;
-        this._dx = 0;
-        this._dy = 0;
-        this._enabled = true;
-        actor.connect('captured-event', this._handleEvent.bind(this));
-        this._touchpadSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.peripherals.touchpad' });
-    }
-
-    get enabled() {
-        return this._enabled;
-    }
-
-    set enabled(enabled) {
-        if (this._enabled == enabled)
-            return;
-
-        this._enabled = enabled;
-        if (!enabled)
-            this.emit('cancel');
-    }
-
-    _checkActivated() {
-        let dir;
-
-        if (this._dy < -WS_MOTION_THRESHOLD)
-            dir = Meta.MotionDirection.DOWN;
-        else if (this._dy > WS_MOTION_THRESHOLD)
-            dir = Meta.MotionDirection.UP;
-        else if (this._dx < -WS_MOTION_THRESHOLD)
-            dir = Meta.MotionDirection.RIGHT;
-        else if (this._dx > WS_MOTION_THRESHOLD)
-            dir = Meta.MotionDirection.LEFT;
-        else
-            return false;
-
-        this.emit('activated', dir);
-        return true;
-    }
-
-    _handleEvent(actor, event) {
-        if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
-            return Clutter.EVENT_PROPAGATE;
-
-        if (event.get_touchpad_gesture_finger_count() != 4)
-            return Clutter.EVENT_PROPAGATE;
-
-        if ((this._allowedModes & Main.actionMode) == 0)
-            return Clutter.EVENT_PROPAGATE;
-
-        if (!this._enabled)
-            return Clutter.EVENT_PROPAGATE;
-
-        if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
-            let [dx, dy] = event.get_gesture_motion_delta();
-
-            // Scale deltas up a bit to make it feel snappier
-            this._dx += dx * 2;
-            if (!this._touchpadSettings.get_boolean('natural-scroll'))
-                this._dy -= dy * 2;
-            else
-                this._dy += dy * 2;
-
-            this.emit('motion', this._dx, this._dy);
-        } else {
-            if ((event.get_gesture_phase() == Clutter.TouchpadGesturePhase.END && !this._checkActivated()) ||
-                event.get_gesture_phase() == Clutter.TouchpadGesturePhase.CANCEL)
-                this.emit('cancel');
-
-            this._dx = 0;
-            this._dy = 0;
-        }
-
-        return Clutter.EVENT_STOP;
-    }
-};
-Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
-
-var WorkspaceSwitchAction = GObject.registerClass({
-    Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] },
-               'motion':    { param_types: [GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE] },
-               'cancel':    { param_types: [] } },
-}, class WorkspaceSwitchAction extends Clutter.SwipeAction {
-    _init(allowedModes) {
-        super._init();
-        this.set_n_touch_points(4);
-        this._swept = false;
-        this._allowedModes = allowedModes;
-
-        global.display.connect('grab-op-begin', () => {
-            this.cancel();
-        });
-    }
-
-    vfunc_gesture_prepare(actor) {
-        this._swept = false;
-
-        if (!super.vfunc_gesture_prepare(actor))
-            return false;
-
-        return this._allowedModes & Main.actionMode;
-    }
-
-    vfunc_gesture_progress(_actor) {
-        let [x, y] = this.get_motion_coords(0);
-        let [xPress, yPress] = this.get_press_coords(0);
-        this.emit('motion', x - xPress, y - yPress);
-        return true;
-    }
-
-    vfunc_gesture_cancel(_actor) {
-        if (!this._swept)
-            this.emit('cancel');
-    }
-
-    vfunc_swipe(actor, direction) {
-        let [x, y] = this.get_motion_coords(0);
-        let [xPress, yPress] = this.get_press_coords(0);
-        if (Math.abs(x - xPress) < WS_MOTION_THRESHOLD &&
-            Math.abs(y - yPress) < WS_MOTION_THRESHOLD) {
-            this.emit('cancel');
-            return;
-        }
-
-        let dir;
-
-        if (direction & Clutter.SwipeDirection.UP)
-            dir = Meta.MotionDirection.DOWN;
-        else if (direction & Clutter.SwipeDirection.DOWN)
-            dir = Meta.MotionDirection.UP;
-        else if (direction & Clutter.SwipeDirection.LEFT)
-            dir = Meta.MotionDirection.RIGHT;
-        else if (direction & Clutter.SwipeDirection.RIGHT)
-            dir = Meta.MotionDirection.LEFT;
-
-        this._swept = true;
-        this.emit('activated', dir);
-    }
-});
-
 var AppSwitchAction = GObject.registerClass({
     Signals: { 'activated': {} },
 }, class AppSwitchAction extends Clutter.GestureAction {
@@ -1054,10 +912,17 @@ var WindowManager = class {
         Main.overview.connect('showing', () => {
             for (let i = 0; i < this._dimmedWindows.length; i++)
                 this._undimWindow(this._dimmedWindows[i]);
+
+            if (this._switchData) {
+                if (this._switchData.gestureActivated)
+                    this._switchWorkspaceStop();
+                this._swipeTracker.enabled = false;
+            }
         });
         Main.overview.connect('hiding', () => {
             for (let i = 0; i < this._dimmedWindows.length; i++)
                 this._dimWindow(this._dimmedWindows[i]);
+            this._swipeTracker.enabled = true;
         });
 
         this._windowMenuManager = new WindowMenu.WindowMenuManager();
@@ -1069,17 +934,12 @@ var WindowManager = class {
                                                            false, -1, 1);
 
         let allowedModes = Shell.ActionMode.NORMAL;
-        let workspaceSwitchAction = new WorkspaceSwitchAction(allowedModes);
-        workspaceSwitchAction.connect('motion', this._switchWorkspaceMotion.bind(this));
-        workspaceSwitchAction.connect('activated', this._actionSwitchWorkspace.bind(this));
-        workspaceSwitchAction.connect('cancel', this._switchWorkspaceCancel.bind(this));
-        global.stage.add_action(workspaceSwitchAction);
-
-        // This is not a normal Clutter.GestureAction, doesn't need add_action()
-        let touchpadSwitchAction = new TouchpadWorkspaceSwitchAction(global.stage, allowedModes);
-        touchpadSwitchAction.connect('motion', this._switchWorkspaceMotion.bind(this));
-        touchpadSwitchAction.connect('activated', this._actionSwitchWorkspace.bind(this));
-        touchpadSwitchAction.connect('cancel', this._switchWorkspaceCancel.bind(this));
+        let swipeTracker = new SwipeTracker.SwipeTracker(global.stage,
+            allowedModes, false, false);
+        swipeTracker.connect('begin', this._switchWorkspaceBegin.bind(this));
+        swipeTracker.connect('update', this._switchWorkspaceUpdate.bind(this));
+        swipeTracker.connect('end', this._switchWorkspaceEnd.bind(this));
+        this._swipeTracker = swipeTracker;
 
         let appSwitchAction = new AppSwitchAction();
         appSwitchAction.connect('activated', this._switchApp.bind(this));
@@ -1121,52 +981,6 @@ var WindowManager = class {
         return this._currentPadOsd;
     }
 
-    _switchWorkspaceMotion(action, xRel, yRel) {
-        let workspaceManager = global.workspace_manager;
-        let activeWorkspace = workspaceManager.get_active_workspace();
-
-        if (!this._switchData)
-            this._prepareWorkspaceSwitch(activeWorkspace.index(), -1);
-
-        if (yRel < 0 && !this._switchData.surroundings[Meta.MotionDirection.DOWN])
-            yRel = 0;
-        if (yRel > 0 && !this._switchData.surroundings[Meta.MotionDirection.UP])
-            yRel = 0;
-        if (xRel < 0 && !this._switchData.surroundings[Meta.MotionDirection.RIGHT])
-            xRel = 0;
-        if (xRel > 0 && !this._switchData.surroundings[Meta.MotionDirection.LEFT])
-            xRel = 0;
-
-        this._switchData.container.set_position(xRel, yRel);
-    }
-
-    _switchWorkspaceCancel() {
-        if (!this._switchData || this._switchData.inProgress)
-            return;
-        let switchData = this._switchData;
-        this._switchData = null;
-        switchData.container.ease({
-            x: 0,
-            y: 0,
-            duration: WINDOW_ANIMATION_TIME,
-            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
-            onComplete: () => this._finishWorkspaceSwitch(switchData),
-        });
-    }
-
-    _actionSwitchWorkspace(action, direction) {
-        let workspaceManager = global.workspace_manager;
-        let activeWorkspace = workspaceManager.get_active_workspace();
-        let newWs = activeWorkspace.get_neighbor(direction);
-
-        if (newWs == activeWorkspace) {
-            this._switchWorkspaceCancel();
-        } else {
-            this._switchData.gestureActivated = true;
-            this.actionMoveWorkspace(newWs);
-        }
-    }
-
     _lookupIndex(windows, metaWindow) {
         for (let i = 0; i < windows.length; i++) {
             if (windows[i].metaWindow == metaWindow)
@@ -1280,7 +1094,8 @@ var WindowManager = class {
     }
 
     _shouldAnimate() {
-        return !Main.overview.visible;
+        return !(Main.overview.visible || (this._switchData &&
+            this._switchData.gestureActivated));
     }
 
     _shouldAnimateActor(actor, types) {
@@ -1860,13 +1675,15 @@ var WindowManager = class {
                 continue;
             }
 
+            let [x, y] = this._getPositionForDirection(dir, curWs, ws);
             let info = { index: ws.index(),
-                         actor: new Clutter.Actor() };
+                         actor: new Clutter.Actor(),
+                         xDest: x,
+                         yDest: y };
             switchData.surroundings[dir] = info;
             switchData.container.add_actor(info.actor);
             switchData.container.set_child_above_sibling(info.actor, null);
 
-            let [x, y] = this._getPositionForDirection(dir, curWs, ws);
             info.actor.set_position(x, y);
         }
 
@@ -1948,11 +1765,7 @@ var WindowManager = class {
             return;
         }
 
-        // If we come from a gesture, switchData will already be set,
-        // and we don't want to overwrite it.
-        if (!this._switchData)
-            this._prepareWorkspaceSwitch(from, to, direction);
-
+        this._prepareWorkspaceSwitch(from, to, direction);
         this._switchData.inProgress = true;
 
         let workspaceManager = global.workspace_manager;
@@ -1972,7 +1785,7 @@ var WindowManager = class {
             x: xDest,
             y: yDest,
             duration: WINDOW_ANIMATION_TIME,
-            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+            mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
             onComplete: () => this._switchWorkspaceDone(shellwm),
         });
     }
@@ -1982,6 +1795,161 @@ var WindowManager = class {
         shellwm.completed_switch_workspace();
     }
 
+    _directionForProgress(progress) {
+        if (global.workspace_manager.layout_rows == -1) {
+            return progress > 0 ? Meta.MotionDirection.DOWN
+                : Meta.MotionDirection.UP;
+        } else if (Clutter.get_default_text_direction() ==
+            Clutter.TextDirection.RTL) {
+            return progress > 0 ? Meta.MotionDirection.LEFT
+                : Meta.MotionDirection.RIGHT;
+        } else {
+            return progress > 0 ? Meta.MotionDirection.RIGHT
+                : Meta.MotionDirection.LEFT;
+        }
+    }
+
+    _getProgressRange() {
+        if (!this._switchData)
+            return [0, 0];
+
+        let lower = 0;
+        let upper = 0;
+
+        let horiz = global.workspace_manager.layout_rows != -1;
+        let baseDistance;
+        if (horiz)
+            baseDistance = global.screen_width;
+        else
+            baseDistance = global.screen_height;
+
+        let direction = this._directionForProgress(-1);
+        let info = this._switchData.surroundings[direction];
+        if (info != null) {
+            let distance = horiz ? info.xDest : info.yDest;
+            lower = -Math.abs(distance) / baseDistance;
+        }
+
+        direction = this._directionForProgress(1);
+        info = this._switchData.surroundings[direction];
+        if (info != null) {
+            let distance = horiz ? info.xDest : info.yDest;
+            upper = Math.abs(distance) / baseDistance;
+        }
+
+        return [lower, upper];
+    }
+
+    _switchWorkspaceBegin(tracker, monitor) {
+        if (Meta.prefs_get_workspaces_only_on_primary() &&
+            monitor != Main.layoutManager.primaryIndex)
+            return;
+
+        let horiz = global.workspace_manager.layout_rows != -1;
+        tracker.orientation = horiz ? Clutter.Orientation.HORIZONTAL
+            : Clutter.Orientation.VERTICAL;
+
+        let workspaceManager = global.workspace_manager;
+        let activeWorkspace = workspaceManager.get_active_workspace();
+
+        let baseDistance;
+        if (horiz)
+            baseDistance = global.screen_width;
+        else
+            baseDistance = global.screen_height;
+
+        let progress;
+        if (this._switchData && this._switchData.gestureActivated) {
+            this._switchData.container.remove_all_transitions();
+            if (!horiz)
+                progress = -this._switchData.container.y / baseDistance;
+            else if (Clutter.get_default_text_direction() ==
+                Clutter.TextDirection.RTL)
+                progress = this._switchData.container.x / baseDistance;
+            else
+                progress = -this._switchData.container.x / baseDistance;
+        } else {
+            this._prepareWorkspaceSwitch(activeWorkspace.index(), -1);
+            progress = 0;
+        }
+
+        let points = [];
+        let [lower, upper] = this._getProgressRange();
+
+        if (lower != 0)
+            points.push(lower);
+
+        points.push(0);
+
+        if (upper != 0)
+            points.push(upper);
+
+        tracker.confirmSwipe(baseDistance, points, progress, 0);
+    }
+
+    _switchWorkspaceUpdate(_tracker, progress) {
+        if (!this._switchData)
+            return;
+
+        let direction = this._directionForProgress(progress);
+        let info = this._switchData.surroundings[direction];
+        let xPos = 0;
+        let yPos = 0;
+        if (info) {
+            if (global.workspace_manager.layout_rows == -1)
+                yPos = Math.round(Math.abs(progress) * -info.yDest);
+            else
+                xPos = Math.round(Math.abs(progress) * -info.xDest);
+        }
+
+        this._switchData.container.set_position(xPos, yPos);
+    }
+
+    _switchWorkspaceEnd(_tracker, duration, endProgress) {
+        if (!this._switchData)
+            return;
+
+        let workspaceManager = global.workspace_manager;
+        let activeWorkspace = workspaceManager.get_active_workspace();
+        let newWs = activeWorkspace;
+        let xDest = 0;
+        let yDest = 0;
+        if (endProgress != 0) {
+            let direction = this._directionForProgress(endProgress);
+            newWs = activeWorkspace.get_neighbor(direction);
+            xDest = -this._switchData.surroundings[direction].xDest;
+            yDest = -this._switchData.surroundings[direction].yDest;
+        }
+
+        if (duration == 0) {
+            if (newWs != activeWorkspace)
+                this.actionMoveWorkspace(newWs);
+            this._switchWorkspaceStop();
+            return;
+        }
+
+        let switchData = this._switchData;
+        switchData.gestureActivated = true;
+
+        this._switchData.container.ease({
+            x: xDest,
+            y: yDest,
+            duration,
+            mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
+            onComplete: () => {
+                if (newWs != activeWorkspace)
+                    this.actionMoveWorkspace(newWs);
+                this._finishWorkspaceSwitch(switchData);
+            },
+        });
+    }
+
+    _switchWorkspaceStop() {
+        this._switchData.container.x = 0;
+        this._switchData.container.y = 0;
+        this._finishWorkspaceSwitch(this._switchData);
+    }
+
     _showTilePreview(shellwm, window, tileRect, monitorIndex) {
         if (!this._tilePreview)
             this._tilePreview = new TilePreview();


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]