From d64d491f635389e79195f796caea5c9445f15312 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Fri, 21 Jan 2011 19:47:54 +0100
Subject: [PATCH] workspaces-view: Use overview swipe-scrolling

Remove the swipe-scrolling implementation in WorkspacesView and
use the new overview facility.

https://bugzilla.gnome.org/show_bug.cgi?id=635034
---
 js/ui/workspace.js      |   16 ++---
 js/ui/workspacesView.js |  183 +++++++++++++----------------------------------
 2 files changed, 56 insertions(+), 143 deletions(-)

diff --git a/js/ui/workspace.js b/js/ui/workspace.js
index 6002492..e44f558 100644
--- a/js/ui/workspace.js
+++ b/js/ui/workspace.js
@@ -517,20 +517,10 @@ Workspace.prototype = {
         // Without this the drop area will be overlapped.
         this._windowOverlaysGroup.set_size(0, 0);
 
-        this.actor = new Clutter.Group({ reactive: true });
+        this.actor = new Clutter.Group();
         this.actor._delegate = this;
 
         this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
-        this.actor.connect('button-release-event', Lang.bind(this,
-            function(actor, event) {
-                // Only switch to the workspace when there's no application
-                // windows open. The problem is that it's too easy to miss
-                // an app window and get the wrong one focused.
-                if (this._windows.length == 0) {
-                    this.metaWorkspace.activate(event.get_time());
-                    Main.overview.hide();
-                }
-            }));
 
         // Items in _windowOverlaysGroup should not be scaled, so we don't
         // add them to this.actor, but to its parent whenever it changes
@@ -605,6 +595,10 @@ Workspace.prototype = {
         return this._lookupIndex(metaWindow) >= 0;
     },
 
+    isEmpty: function() {
+        return this._windows.length == 0;
+    },
+
     setShowOnlyWindows: function(showOnlyWindows, reposition) {
         this._showOnlyWindows = showOnlyWindows;
         this._resetCloneVisibility();
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index 7478003..40b7320 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -45,6 +45,8 @@ WorkspacesView.prototype = {
                 this._spacing = node.get_length('spacing');
                 this._computeWorkspacePositions();
             }));
+        this.actor.connect('notify::mapped',
+                           Lang.bind(this, this._onMappedChanged));
 
         this._width = width;
         this._height = height;
@@ -55,10 +57,9 @@ WorkspacesView.prototype = {
         this._activeWorkspaceY = 0; // y offset of active ws while dragging
         this._lostWorkspaces = [];
         this._animating = false; // tweening
-        this._scrolling = false; // dragging desktop
+        this._scrolling = false; // swipe-scrolling
         this._animatingScroll = false; // programatically updating the adjustment
         this._inDrag = false; // dragging a window
-        this._lastMotionTime = -1; // used to track "stopping" while dragging workspaces
 
         let activeWorkspaceIndex = global.screen.get_active_workspace_index();
         this._workspaces = workspaces;
@@ -89,10 +90,6 @@ WorkspacesView.prototype = {
         this._scrollAdjustment.connect('notify::value',
                                        Lang.bind(this, this._onScroll));
 
-        this._dragIndex = -1;
-
-        this._buttonPressId = 0;
-        this._capturedEventId = 0;
         this._timeoutId = 0;
 
         this._windowSelectionAppId = null;
@@ -113,6 +110,8 @@ WorkspacesView.prototype = {
                                                         Lang.bind(this, this._dragBegin));
         this._windowDragEndId = Main.overview.connect('window-drag-end',
                                                       Lang.bind(this, this._dragEnd));
+        this._swipeScrollBeginId = 0;
+        this._swipeScrollEndId = 0;
     },
 
     _lookupWorkspaceForMetaWindow: function (metaWindow) {
@@ -290,8 +289,6 @@ WorkspacesView.prototype = {
         if (this._inDrag)
             scale *= WORKSPACE_DRAGGING_SCALE;
 
-        this._setWorkspaceDraggable(active, true);
-
         let _width = this._workspaces[0].actor.width * scale;
         let _height = this._workspaces[0].actor.height * scale;
 
@@ -323,128 +320,6 @@ WorkspacesView.prototype = {
         this._updateScrollAdjustment(active, showAnimation);
     },
 
-    // _setWorkspaceDraggable:
-    // @index: workspace index
-    // @draggable: whether workspace @index should be draggable
-    //
-    // If @draggable is %true, set up workspace @index to allow switching
-    // workspaces by dragging the desktop - if a draggable workspace has
-    // been set up before, it will be reset before the new one is made
-    // draggable.
-    // If @draggable is %false, workspace @index is reset to no longer allow
-    // dragging.
-    _setWorkspaceDraggable: function(index, draggable) {
-        if (index < 0 || index >= global.n_workspaces)
-            return;
-
-        let dragActor = this._workspaces[index].actor;
-
-        if (draggable) {
-            this._workspaces[index].actor.reactive = true;
-
-            // reset old draggable workspace
-            if (this._dragIndex > -1)
-                this._setWorkspaceDraggable(this._dragIndex, false);
-
-            this._dragIndex = index;
-            this._buttonPressId = dragActor.connect('button-press-event',
-                                      Lang.bind(this, this._onButtonPress));
-        } else {
-            this._dragIndex = -1;
-
-            if (this._buttonPressId > 0) {
-                if (dragActor.get_stage())
-                    dragActor.disconnect(this._buttonPressId);
-                this._buttonPressId = 0;
-            }
-
-            if (this._capturedEventId > 0) {
-                global.stage.disconnect(this._capturedEventId);
-                this._capturedEventId = 0;
-            }
-        }
-    },
-
-    // start dragging the active workspace
-    _onButtonPress: function(actor, event) {
-        if (actor != event.get_source())
-            return;
-
-        if (this._dragIndex == -1)
-            return;
-
-        let [stageX, stageY] = event.get_coords();
-        this._dragStartX = this._dragX = stageX;
-        this._scrolling = true;
-        this._capturedEventId = global.stage.connect('captured-event',
-            Lang.bind(this, this._onCapturedEvent));
-    },
-
-    // handle captured events while dragging a workspace
-    _onCapturedEvent: function(actor, event) {
-        let active = global.screen.get_active_workspace_index();
-        let stageX, stageY;
-
-        switch (event.type()) {
-            case Clutter.EventType.BUTTON_RELEASE:
-                this._scrolling = false;
-
-                [stageX, stageY] = event.get_coords();
-
-                // default to snapping back to the original workspace
-                let activate = this._dragIndex;
-                let last = global.screen.n_workspaces - 1;
-
-                // If the user has moved more than half a workspace, we want to "settle"
-                // to the new workspace even if the user stops dragging rather "throws"
-                // by releasing during the drag.
-                let noStop = Math.abs(activate - this._scrollAdjustment.value) > 0.5;
-
-                let difference = stageX > this._dragStartX ? -1 : 1;
-                if (St.Widget.get_default_direction() == St.TextDirection.RTL)
-                    difference *= -1;
-
-                // We detect if the user is stopped by comparing the timestamp of the button
-                // release with the timestamp of the last motion. Experimentally, a difference
-                // of 0 or 1 millisecond indicates that the mouse is in motion, a larger
-                // difference indicates that the mouse is stopped.
-                if ((this._lastMotionTime > 0 && this._lastMotionTime > event.get_time() - 2) || noStop) {
-                    if (activate + difference >= 0 &&
-                        activate + difference <= last)
-                        activate += difference;
-                }
-
-                if (activate != active) {
-                    let workspace = this._workspaces[activate].metaWorkspace;
-                    workspace.activate(global.get_current_time());
-                } else {
-                    this._scrollToActive(true);
-                }
-
-                if (stageX == this._dragStartX)
-                    // no motion? It's a click!
-                    return false;
-
-                return true;
-
-            case Clutter.EventType.MOTION:
-                [stageX, stageY] = event.get_coords();
-                let dx = this._dragX - stageX;
-                let primary = global.get_primary_monitor();
-
-                if (St.Widget.get_default_direction() == St.TextDirection.RTL)
-                    this._scrollAdjustment.value -= (dx / primary.width);
-                else
-                    this._scrollAdjustment.value += (dx / primary.width);
-                this._dragX = stageX;
-                this._lastMotionTime = event.get_time();
-
-                return true;
-        }
-
-        return false;
-    },
-
     // Update workspace actors parameters to the values calculated in
     // _computeWorkspacePositions()
     // @showAnimation: iff %true, transition between states
@@ -454,7 +329,6 @@ WorkspacesView.prototype = {
         let targetWorkspaceCurrentX = this._workspaces[active].x;
         let dx = targetWorkspaceNewX - targetWorkspaceCurrentX;
 
-        this._setWorkspaceDraggable(active, true);
         this._animating = showAnimation;
 
         for (let w = 0; w < this._workspaces.length; w++) {
@@ -606,7 +480,6 @@ WorkspacesView.prototype = {
         global.window_manager.disconnect(this._switchWorkspaceNotifyId);
         global.screen.disconnect(this._restackedNotifyId);
 
-        this._setWorkspaceDraggable(this._dragIndex, false);
         if (this._timeoutId) {
             Mainloop.source_remove(this._timeoutId);
             this._timeoutId = 0;
@@ -629,6 +502,21 @@ WorkspacesView.prototype = {
         }
     },
 
+    _onMappedChanged: function() {
+        if (this.actor.mapped) {
+            let direction = Overview.SwipeScrollDirection.HORIZONTAL;
+            Main.overview.setScrollAdjustment(this._scrollAdjustment,
+                                              direction);
+            this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
+                                                             Lang.bind(this, this._swipeScrollBegin));
+            this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
+                                                           Lang.bind(this, this._swipeScrollEnd));
+        } else {
+            Main.overview.disconnect(this._swipeScrollBeginId);
+            Main.overview.disconnect(this._swipeScrollEndId);
+        }
+    },
+
     _dragBegin: function() {
         if (this._scrolling)
             return;
@@ -736,6 +624,37 @@ WorkspacesView.prototype = {
             this._workspaces[i].setReservedSlot(null);
     },
 
+    _swipeScrollBegin: function() {
+        this._scrolling = true;
+    },
+
+    _swipeScrollEnd: function(overview, result) {
+        this._scrolling = false;
+
+        if (result == Overview.SwipeScrollResult.CLICK) {
+            let [x, y, mod] = global.get_pointer();
+            let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
+                                                      x, y);
+
+            // Only switch to the workspace when there's no application
+            // windows open. The problem is that it's too easy to miss
+            // an app window and get the wrong one focused.
+            let active = global.screen.get_active_workspace_index();
+            if (this._workspaces[active].isEmpty() &&
+                this.actor.contains(actor))
+                Main.overview.hide();
+        }
+
+        if (result == Overview.SwipeScrollResult.SWIPE)
+            // The active workspace has changed; while swipe-scrolling
+            // has already taken care of the positioning, the cached
+            // positions need to be updated
+            this._computeWorkspacePositions();
+
+        // Make sure title captions etc are shown as necessary
+        this._updateVisibility();
+    },
+
     // sync the workspaces' positions to the value of the scroll adjustment
     // and change the active workspace if appropriate
     _onScroll: function(adj) {
-- 
1.7.3.4