[gnome-shell/wip/carlosg/interactive-workspace-switching: 4/4] windowManager: Make workspace switching gestures follow motion



commit ebe6f59d7e3c3b520b5d52ddf39be6a64ec3f80b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Jul 13 23:38:03 2018 +0200

    windowManager: Make workspace switching gestures follow motion
    
    When 4fg swipe motion happens, set up early the workspace switching
    animation with all surrounding workspaces. This allows us to move
    all content back and forth in any direction. This works on both
    touchcreens and touchpads.
    
    When the gesture is activated, the same data is reused to follow
    up with the tween animation.
    
    The threshold has been also doubled, it was fairly small to start
    with, and feels better now that workspaces stick to fingers.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=788994

 js/ui/windowManager.js | 126 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 107 insertions(+), 19 deletions(-)
---
diff --git a/js/ui/windowManager.js b/js/ui/windowManager.js
index 18f393dda..a88d4f9a0 100644
--- a/js/ui/windowManager.js
+++ b/js/ui/windowManager.js
@@ -3,6 +3,7 @@
 const Clutter = imports.gi.Clutter;
 const GLib = imports.gi.GLib;
 const Gio = imports.gi.Gio;
+const GObject = imports.gi.GObject;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
 const Meta = imports.gi.Meta;
@@ -34,6 +35,7 @@ var WINDOW_ANIMATION_TIME = 0.25;
 var DIM_BRIGHTNESS = -0.3;
 var DIM_TIME = 0.500;
 var UNDIM_TIME = 0.250;
+var MOTION_THRESHOLD = 100;
 
 var ONE_SECOND = 1000; // in ms
 
@@ -495,13 +497,8 @@ var TouchpadWorkspaceSwitchAction = new Lang.Class({
     },
 
     _checkActivated() {
-        const MOTION_THRESHOLD = 50;
-        let allowedModes = Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW;
         let dir;
 
-        if ((allowedModes & Main.actionMode) == 0)
-            return;
-
         if (this._dy < -MOTION_THRESHOLD)
             dir = Meta.MotionDirection.DOWN;
         else if (this._dy > MOTION_THRESHOLD)
@@ -511,26 +508,35 @@ var TouchpadWorkspaceSwitchAction = new Lang.Class({
         else if (this._dx > MOTION_THRESHOLD)
             dir = Meta.MotionDirection.LEFT;
         else
-            return;
+            return false;
 
         this.emit('activated', dir);
+        return true;
     },
 
     _handleEvent(actor, event) {
+        let allowedModes = Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW;
+
         if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
             return Clutter.EVENT_PROPAGATE;
 
         if (event.get_touchpad_gesture_finger_count() != 4)
             return Clutter.EVENT_PROPAGATE;
 
+        if ((allowedModes & Main.actionMode) == 0)
+            return Clutter.EVENT_PROPAGATE;
+
         if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
             let [dx, dy] = event.get_gesture_motion_delta();
 
-            this._dx += dx;
-            this._dy += dy;
+            // Scale deltas up a bit to make it feel snappier
+            this._dx += dx * 2;
+            this._dy += dy * 2;
+            this.emit('motion', this._dx, this._dy);
         } else {
-            if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.END)
-                this._checkActivated();
+            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;
@@ -544,14 +550,14 @@ Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
 var WorkspaceSwitchAction = new Lang.Class({
     Name: 'WorkspaceSwitchAction',
     Extends: Clutter.SwipeAction,
-    Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] } },
+    Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] },
+               'motion':    { param_types: [GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE] },
+               'cancel':    { param_types: [] }},
 
     _init() {
-        const MOTION_THRESHOLD = 50;
-
         this.parent();
         this.set_n_touch_points(4);
-        this.set_threshold_trigger_distance(MOTION_THRESHOLD, MOTION_THRESHOLD);
+        this._swept = false;
 
         global.display.connect('grab-op-begin', () => {
             this.cancel();
@@ -561,13 +567,35 @@ var WorkspaceSwitchAction = new Lang.Class({
     vfunc_gesture_prepare(actor) {
         let allowedModes = Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW;
 
+        this._swept = false;
+
         if (!this.parent(actor))
             return false;
 
         return (allowedModes & Main.actionMode);
     },
 
-    vfunc_swept(actor, direction) {
+    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) < MOTION_THRESHOLD &&
+            Math.abs(y - yPress) < MOTION_THRESHOLD) {
+            this.emit('cancel');
+            return;
+        }
+
         let dir;
 
         if (direction & Clutter.SwipeDirection.UP)
@@ -579,6 +607,7 @@ var WorkspaceSwitchAction = new Lang.Class({
         else if (direction & Clutter.SwipeDirection.RIGHT)
             dir = Meta.MotionDirection.LEFT;
 
+        this._swept = true;
         this.emit('activated', dir);
     }
 });
@@ -700,7 +729,14 @@ var WindowManager = new Lang.Class({
         this._isWorkspacePrepended = false;
 
         this._switchData = null;
-        this._shellwm.connect('kill-switch-workspace', this._switchWorkspaceDone.bind(this));
+        this._shellwm.connect('kill-switch-workspace', (shellwm) => {
+            if (this._switchData) {
+                if (this._switchData.inProgress)
+                    this._switchWorkspaceDone(shellwm);
+                else if (!this._switchData.gestureActivated)
+                    this._finishWorkspaceSwitch(this._switchData);
+            }
+        });
         this._shellwm.connect('kill-window-effects', (shellwm, actor) => {
             this._minimizeWindowDone(shellwm, actor);
             this._mapWindowDone(shellwm, actor);
@@ -982,12 +1018,16 @@ var WindowManager = new Lang.Class({
                                                            false, -1, 1);
 
         let gesture = new WorkspaceSwitchAction();
+        gesture.connect('motion', this._switchWorkspaceMotion.bind(this));
         gesture.connect('activated', this._actionSwitchWorkspace.bind(this));
+        gesture.connect('cancel', this._switchWorkspaceCancel.bind(this));
         global.stage.add_action(gesture);
 
         // This is not a normal Clutter.GestureAction, doesn't need add_action()
         gesture = new TouchpadWorkspaceSwitchAction(global.stage);
+        gesture.connect('motion', this._switchWorkspaceMotion.bind(this));
         gesture.connect('activated', this._actionSwitchWorkspace.bind(this));
+        gesture.connect('cancel', this._switchWorkspaceCancel.bind(this));
 
         gesture = new AppSwitchAction();
         gesture.connect('activated', this._switchApp.bind(this));
@@ -1016,11 +1056,52 @@ var WindowManager = new Lang.Class({
         return this._currentPadOsd.actor;
     },
 
+    _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;
+        Tweener.addTween(switchData.container,
+                         { x: 0,
+                           y: 0,
+                           time: WINDOW_ANIMATION_TIME,
+                           transition: 'easeOutQuad',
+                           onComplete: this._finishWorkspaceSwitch,
+                           onCompleteScope: this,
+                           onCompleteParams: [switchData],
+                         });
+    },
+
     _actionSwitchWorkspace(action, direction) {
         let workspaceManager = global.workspace_manager;
         let activeWorkspace = workspaceManager.get_active_workspace();
         let newWs = activeWorkspace.get_neighbor(direction);
-        this.actionMoveWorkspace(newWs);
+
+        if (newWs == activeWorkspace) {
+            this._switchWorkspaceCancel();
+        } else {
+            this._switchData.gestureActivated = true;
+            this.actionMoveWorkspace(newWs);
+        }
     },
 
     _lookupIndex(windows, metaWindow) {
@@ -1762,6 +1843,8 @@ var WindowManager = new Lang.Class({
         switchData.movingWindowBin = new Clutter.Actor();
         switchData.windows = [];
         switchData.surroundings = {};
+        switchData.gestureActivated = false;
+        switchData.inProgress = false;
 
         switchData.container = new Clutter.Actor();
         switchData.container.add_actor(switchData.curGroup);
@@ -1857,6 +1940,13 @@ var WindowManager = new Lang.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._switchData.inProgress = true;
+
         let [xDest, yDest] = this._getPositionForDirection(direction);
 
         /* @direction is the direction that the "camera" moves, so the
@@ -1866,8 +1956,6 @@ var WindowManager = new Lang.Class({
         xDest = -xDest;
         yDest = -yDest;
 
-        this._prepareWorkspaceSwitch(from, to, direction);
-
         Tweener.addTween(this._switchData.container,
                          { x: xDest,
                            y: yDest,


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