[gnome-shell/wip/overviewTransitions: 7/7] workspace: Fade in instead of zoom to return desktop



commit 69344bf462c811b8b5a0dd83ea31e80e13fd6c97
Author: Carlos Soriano <carlos soriano89 gmail com>
Date:   Mon Jul 14 19:06:08 2014 +0200

    workspace: Fade in instead of zoom to return desktop
    
    The zooming animation of the windows looks nice when animating
    from the workspace display page, but looks weird from others pages
    like apps page or search page since the windows comes from nowhere
    with a initial position not known for the user.
    
    Instead of that just fade the desktop with the windows in its
    original position.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=732901

 js/ui/overview.js       |    2 +-
 js/ui/viewSelector.js   |   39 +++++++--
 js/ui/workspace.js      |  217 +++++++++++++++++++++++++++++++++++++++--------
 js/ui/workspacesView.js |   63 ++++++++++----
 4 files changed, 261 insertions(+), 60 deletions(-)
---
diff --git a/js/ui/overview.js b/js/ui/overview.js
index fc9f055..50e42e6 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -623,7 +623,7 @@ const Overview = new Lang.Class({
         this.animationInProgress = true;
         this.visibleTarget = false;
 
-        this.viewSelector.zoomFromOverview();
+        this.viewSelector.animateFromOverview();
 
         // Make other elements fade out.
         Tweener.addTween(this._stack,
diff --git a/js/ui/viewSelector.js b/js/ui/viewSelector.js
index bf2d733..4351e72 100644
--- a/js/ui/viewSelector.js
+++ b/js/ui/viewSelector.js
@@ -260,6 +260,20 @@ const ViewSelector = new Lang.Class({
                     this._stageKeyPressId = 0;
                 }
             }));
+        Main.overview.connect('shown', Lang.bind(this,
+            function() {
+                // If we were animating from the desktop view to the
+                // apps page the workspace page were visible, allowing
+                // the windows to animate, but now we no longer want to
+                // show it given that we are now on the apps page or
+                // search page.
+                if (this._activePage != this._workspacesPage)
+                    this._workspacesPage.opacity = 0;
+            }));
+        Main.overview.connect('hidden', Lang.bind(this,
+            function() {
+                this._activePage = null;
+            }));
 
         Main.wm.addKeybinding('toggle-application-view',
                               new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
@@ -295,29 +309,38 @@ const ViewSelector = new Lang.Class({
     },
 
     _toggleAppsPage: function() {
-        Main.overview.show();
         this._showAppsButton.checked = !this._showAppsButton.checked;
+        Main.overview.show();
     },
 
     showApps: function() {
-        Main.overview.show();
         this._showAppsButton.checked = true;
+        Main.overview.show();
     },
 
     show: function() {
         this.reset();
-
-        this._workspacesDisplay.show();
+        this._workspacesDisplay.show(this._showAppsButton.checked);
         this._activePage = null;
-        this._showPage(this._workspacesPage);
+        if (this._showAppsButton.checked)
+            this._showPage(this._appsPage);
+        else
+            this._showPage(this._workspacesPage);
 
         if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
             Main.overview.fadeOutDesktop();
     },
 
-    zoomFromOverview: function() {
-        this._showAppsButton.checked = false;
-        this._workspacesDisplay.zoomFromOverview();
+    animateFromOverview: function() {
+        // Make sure workspace page is fully visible to allow
+        // workspace.js do the animation of the windows
+        this._workspacesPage.opacity = 255;
+
+        let showingWindowsFromOverview = this._activePage == this._workspacesPage;
+        if (!showingWindowsFromOverview)
+            this._showAppsButton.checked = false;
+
+        this._workspacesDisplay.animateFromOverview(!showingWindowsFromOverview);
 
         if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
             Main.overview.fadeInDesktop();
diff --git a/js/ui/workspace.js b/js/ui/workspace.js
index ec012c0..35b2dd6 100644
--- a/js/ui/workspace.js
+++ b/js/ui/workspace.js
@@ -34,6 +34,8 @@ const DRAGGING_WINDOW_OPACITY = 100;
 const LAYOUT_SCALE_WEIGHT = 1;
 const LAYOUT_SPACE_WEIGHT = 0.1;
 
+const WINDOW_ANIMATION_MAX_NUMBER_BLENDING = 3;
+
 function _interpolate(start, end, step) {
     return start + (end - start) * step;
 }
@@ -1258,10 +1260,11 @@ const Workspace = new Lang.Class({
             return;
         }
 
-        // We will reposition windows when enter again overview anyway.
+        // We will reposition windows anyway when enter again overview or when ending the windows
+        // animations whith fade animation.
         // In this way we avoid unwanted animations of windows repositioning while
-        // animating overview
-        if (this.leavingOverview)
+        // animating overview.
+        if (this.leavingOverview || this._animatingWindowsFade)
             return;
 
         let initialPositioning = flags & WindowPositionFlags.INITIAL;
@@ -1562,14 +1565,156 @@ const Workspace = new Lang.Class({
         return false;
     },
 
-    // Animate the full-screen to Overview transition.
-    zoomToOverview : function() {
+    fadeToOverview: function() {
+        // Unlikely with current code, but make sure
+        if (this._windows.length == 0)
+            return;
+
+        // We don't want to reposition windows while animating in this way.
+        this._animatingWindowsFade = true;
+
+        if (this._repositionWindowsId > 0) {
+            Mainloop.source_remove(this._repositionWindowsId);
+            this._repositionWindowsId = 0;
+        }
+
+        // Special case maximized windows, since it doesn't make sense
+        // to animate windows below in the stack
+        let firstMaximizedWindow = this._windows.length - 1;
+        let maximizedWindow = false;
+        for (; firstMaximizedWindow >= 0 && !maximizedWindow; firstMaximizedWindow--)
+            maximizedWindow = this._windows[firstMaximizedWindow].metaWindow.maximized_horizontally &&
+                              this._windows[firstMaximizedWindow].metaWindow.maximized_vertically;
+
+        firstMaximizedWindow++;
+
+        let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING, this._windows.length - 
firstMaximizedWindow);
+        let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
+
+        // Animate the less recent accessed windows at the same time
+        // with one time slot
+        for (let i = this._windows.length - 1 - nTimeSlots; i >= 0; i--) {
+            if (i < firstMaximizedWindow) {
+                let overlay = this._windowOverlays[i];
+                if (overlay)
+                    this._windowOverlays[i].hide();
+                this._windows[i].actor.opacity = 0;
+            } else {
+                this._windows[i].actor.opacity = 255;
+                this._fadeWindow(i, windowBaseTime, 0, null);
+            }
+        }
+
+        let onCompleteWindowsAnimation =  Lang.bind(this, function() {
+            this._animatingWindowsFade = false;
+            this._recalculateWindowPositions(WindowPositionFlags.INITIAL);
+        });
+        // Animate gradually the most WINDOW_ANIMATION_MAX_NUMBER_BLENDING accessed windows hoping that
+        // those covers most of the screen so we can achieve a smooth transition.
+        for (let i = this._windows.length - 1; i > this._windows.length - 1 - nTimeSlots; i--) {
+            let onComplete = null;
+            if (i == this._windows.length -1)
+               onComplete = onCompleteWindowsAnimation;
+            let reverseIndex = (this._windows.length - 1) - i;
+            this._fadeWindow(i, windowBaseTime * (nTimeSlots - reverseIndex), 0, onComplete);
+        }
+
+    },
+
+    fadeFromOverview: function() {
+        this.leavingOverview = true;
+
+        for (let i = 0; i < this._windows.length; i++) {
+            let clone = this._windows[i];
+            Tweener.removeTweens(clone.actor);
+        }
+
+        if (this._repositionWindowsId > 0) {
+            Mainloop.source_remove(this._repositionWindowsId);
+            this._repositionWindowsId = 0;
+        }
+        this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
+                                                                           this._doneLeavingOverview));
+
+        if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
+
+
+        // Unlikely with current code, but make sure
+        if (this._windows.length == 0)
+            return;
+
+        // Special case maximized windows, since it doesn't make sense
+        // to animate windows below in the stack
+        let firstMaximizedWindow = this._windows.length - 1;
+        let maximizedWindow = false;
+        for (; firstMaximizedWindow >= 0 && !maximizedWindow; firstMaximizedWindow--)
+            maximizedWindow = this._windows[firstMaximizedWindow].metaWindow.maximized_horizontally &&
+                              this._windows[firstMaximizedWindow].metaWindow.maximized_vertically;
+
+        firstMaximizedWindow++;
+
+        let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING, this._windows.length - 
firstMaximizedWindow);
+        let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
+
+        // Animate the less recent accessed windows at the same time
+        for (let i = this._windows.length - 1 - nTimeSlots; i >= 0; i--) {
+            this._windows[i].actor.opacity = 0;
+            if (i < firstMaximizedWindow) {
+                let overlay = this._windowOverlays[i];
+                if (overlay)
+                    this._windowOverlays[i].hide();
+            } else {
+                this._fadeWindow(i, windowBaseTime * nTimeSlots, 255, null);
+            }
+        }
+
+        // Animate gradually the most WINDOW_ANIMATION_MAX_NUMBER_BLENDING accessed windows hoping that
+        // those covers most of the screen so we can achieve a smooth transition.
+        for (let i = this._windows.length - 1; i > this._windows.length - 1 - nTimeSlots; i--) {
+            let reverseIndex = this._windows.length - i;
+            this._windows[i].actor.opacity = 0;
+            this._fadeWindow(i, windowBaseTime * reverseIndex, 255, null);
+        }
+    },
+
+    _fadeWindow: function(index, time, opacity, onComplete) {
+        let clone = this._windows[index];
+        let overlay = this._windowOverlays[index];
+
+        if (overlay)
+            overlay.hide();
+
+        if (clone.metaWindow.showing_on_its_workspace()) {
+            let [origX, origY] = clone.getOriginalPosition();
+            clone.actor.scale_x = 1;
+            clone.actor.scale_y = 1;
+            clone.actor.x = origX;
+            clone.actor.y = origY;
+            Tweener.addTween(clone.actor,
+                             { time: time,
+                               opacity: opacity,
+                               transition: 'easeOutQuad',
+                               onComplete: Lang.bind(this, function() {
+                                   if (onComplete)
+                                       onComplete();
+                               })
+                             });
+        } else {
+            // The window is hidden
+            clone.actor.opacity = 0;
+            Mainloop.timeout_add_seconds(time, Lang.bind(this, function() {
+                if (onComplete)
+                    onComplete();
+            }));
+        }
+    },
+
+    zoomToOverview: function() {
         // Position and scale the windows.
         this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
     },
 
-    // Animates the return from Overview mode
-    zoomFromOverview : function() {
+    zoomFromOverview: function() {
         let currentWorkspace = global.screen.get_active_workspace();
 
         this.leavingOverview = true;
@@ -1590,35 +1735,37 @@ const Workspace = new Lang.Class({
             return;
 
         // Position and scale the windows.
-        for (let i = 0; i < this._windows.length; i++) {
-            let clone = this._windows[i];
-            let overlay = this._windowOverlays[i];
-
-            if (overlay)
-                overlay.hide();
+        for (let i = 0; i < this._windows.length; i++)
+           this._zoomWindowFromOverview(i);
+    },
 
-            if (clone.metaWindow.showing_on_its_workspace()) {
-                let [origX, origY] = clone.getOriginalPosition();
-
-                Tweener.addTween(clone.actor,
-                                 { x: origX,
-                                   y: origY,
-                                   scale_x: 1.0,
-                                   scale_y: 1.0,
-                                   time: Overview.ANIMATION_TIME,
-                                   opacity: 255,
-                                   transition: 'easeOutQuad'
-                                 });
-            } else {
-                // The window is hidden, make it shrink and fade it out
-                Tweener.addTween(clone.actor,
-                                 { scale_x: 0,
-                                   scale_y: 0,
-                                   opacity: 0,
-                                   time: Overview.ANIMATION_TIME,
-                                   transition: 'easeOutQuad'
-                                 });
-            }
+    _zoomWindowFromOverview: function(index) {
+        let clone = this._windows[index];
+        let overlay = this._windowOverlays[index];
+
+        if (overlay)
+            overlay.hide();
+
+        if (clone.metaWindow.showing_on_its_workspace()) {
+            let [origX, origY] = clone.getOriginalPosition();
+            Tweener.addTween(clone.actor,
+                             { x: origX,
+                               y: origY,
+                               scale_x: 1.0,
+                               scale_y: 1.0,
+                               time: Overview.ANIMATION_TIME,
+                               opacity: 255,
+                               transition: 'easeOutQuad'
+                             });
+        } else {
+            // The window is hidden, make it shrink and fade it out
+            Tweener.addTween(clone.actor,
+                             { scale_x: 0,
+                               scale_y: 0,
+                               opacity: 0,
+                               time: Overview.ANIMATION_TIME,
+                               transition: 'easeOutQuad'
+                             });
         }
     },
 
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
index 61df6ab..004ac81 100644
--- a/js/ui/workspacesView.js
+++ b/js/ui/workspacesView.js
@@ -21,6 +21,11 @@ const WORKSPACE_SWITCH_TIME = 0.25;
 // Note that mutter has a compile-time limit of 36
 const MAX_WORKSPACES = 16;
 
+const AnimationType = {
+    ZOOM: 0,
+    FADE: 1
+};
+
 const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
 
 const WorkspacesViewBase = new Lang.Class({
@@ -142,17 +147,25 @@ const WorkspacesView = new Lang.Class({
         return this._workspaces[active];
     },
 
-    zoomToOverview: function() {
-        for (let w = 0; w < this._workspaces.length; w++)
-            this._workspaces[w].zoomToOverview();
+    animateToOverview: function(animationType) {
+        for (let w = 0; w < this._workspaces.length; w++) {
+            if (animationType == AnimationType.ZOOM)
+                this._workspaces[w].zoomToOverview();
+            else
+                this._workspaces[w].fadeToOverview();
+        }
         this._updateWorkspaceActors(false);
     },
 
-    zoomFromOverview: function() {
+    animateFromOverview: function(animationType) {
         this.actor.remove_clip();
 
-        for (let w = 0; w < this._workspaces.length; w++)
-            this._workspaces[w].zoomFromOverview();
+        for (let w = 0; w < this._workspaces.length; w++) {
+            if (animationType == AnimationType.ZOOM)
+                this._workspaces[w].zoomFromOverview();
+            else
+                this._workspaces[w].fadeFromOverview();
+        }
     },
 
     syncStacking: function(stackIndices) {
@@ -365,12 +378,18 @@ const ExtraWorkspaceView = new Lang.Class({
         this._workspace.setActualGeometry(this._actualGeometry);
     },
 
-    zoomToOverview: function() {
-        this._workspace.zoomToOverview();
+    animateToOverview: function(animationType) {
+        if (animationType == AnimationType.ZOOM)
+            this._workspace.zoomToOverview();
+        else
+            this._workspace.fadeToOverview();
     },
 
-    zoomFromOverview: function() {
-        this._workspace.zoomFromOverview();
+    animateFromOverview: function(animationType) {
+        if (animationType == AnimationType.ZOOM)
+            this._workspace.zoomFromOverview();
+        else
+            this._workspace.fadeFromOverview();
     },
 
     syncStacking: function(stackIndices) {
@@ -462,10 +481,16 @@ const WorkspacesDisplay = new Lang.Class({
         return this._getPrimaryView().actor.navigate_focus(from, direction, false);
     },
 
-    show: function() {
+    show: function(fadeOnPrimary) {
         this._updateWorkspacesViews();
-        for (let i = 0; i < this._workspacesViews.length; i++)
-            this._workspacesViews[i].zoomToOverview();
+        for (let i = 0; i < this._workspacesViews.length; i++) {
+            let animationType;
+            if (fadeOnPrimary && i == this._primaryIndex)
+                animationType = AnimationType.FADE;
+            else
+                animationType = AnimationType.ZOOM;
+            this._workspacesViews[i].animateToOverview(animationType);
+        }
 
         this._restackedNotifyId =
             Main.overview.connect('windows-restacked',
@@ -474,9 +499,15 @@ const WorkspacesDisplay = new Lang.Class({
             this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, 
this._onScrollEvent));
     },
 
-    zoomFromOverview: function() {
-        for (let i = 0; i < this._workspacesViews.length; i++)
-            this._workspacesViews[i].zoomFromOverview();
+    animateFromOverview: function(fadeOnPrimary) {
+        for (let i = 0; i < this._workspacesViews.length; i++) {
+            let animationType;
+            if (fadeOnPrimary && i == this._primaryIndex)
+                animationType = AnimationType.FADE;
+            else
+                animationType = AnimationType.ZOOM;
+            this._workspacesViews[i].animateFromOverview(animationType);
+        }
     },
 
     hide: function() {


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