[gnome-shell/wip/gcampax/background: 7/7] LayoutManager: implement new design for the startup animation



commit 3e79d293f7d44a24d44f8d504f395531bcc766ac
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Mon Dec 24 15:46:21 2012 +0100

    LayoutManager: implement new design for the startup animation
    
    The design calls for two different startup animations, in the GDM
    and in the normal session case.
    In both cases, we implement fading from the previous situation
    by acquiring the root background pixmap and turning it into a TFP
    texture, which is then animated and blended by Clutter as normal.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=682429

 js/ui/layout.js |  104 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 js/ui/main.js   |    8 ++++
 2 files changed, 103 insertions(+), 9 deletions(-)
---
diff --git a/js/ui/layout.js b/js/ui/layout.js
index 53ea4bd..18200ed 100644
--- a/js/ui/layout.js
+++ b/js/ui/layout.js
@@ -1,6 +1,7 @@
 // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
 const Clutter = imports.gi.Clutter;
+const ClutterX11 = imports.gi.ClutterX11;
 const GObject = imports.gi.GObject;
 const Lang = imports.lang;
 const Mainloop = imports.mainloop;
@@ -15,9 +16,8 @@ const Params = imports.misc.params;
 const Tweener = imports.ui.tweener;
 
 const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
-const STARTUP_ANIMATION_TIME = 0.2;
+const STARTUP_ANIMATION_TIME = 1;
 const KEYBOARD_ANIMATION_TIME = 0.15;
-const PLYMOUTH_TRANSITION_TIME = 1;
 const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
 
 const MonitorConstraint = new Lang.Class({
@@ -171,7 +171,7 @@ const LayoutManager = new Lang.Class({
                               Lang.bind(this, this._panelBoxChanged));
 
         this.trayBox = new St.Widget({ name: 'trayBox',
-                                       layout_manager: new Clutter.BinLayout() }); 
+                                       layout_manager: new Clutter.BinLayout() });
         this.addChrome(this.trayBox);
 
         this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
@@ -197,7 +197,8 @@ const LayoutManager = new Lang.Class({
         Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
         Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
         Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
-        this._startupAnimation();
+
+        this._prepareStartupAnimation();
     },
 
     _overviewShowing: function() {
@@ -412,21 +413,106 @@ const LayoutManager = new Lang.Class({
         return this._keyboardIndex;
     },
 
-    _startupAnimation: function() {
-        this.panelBox.translation_y = -this.panelBox.height;
+    _acquireRootBackground: function() {
+        let rootpmap = Shell.util_get_root_background();
+        let texture = ClutterX11.TexturePixmap.new_with_pixmap(rootpmap);
+        // The texture size might not match the screen size, for example
+        // if the session has a different XRandR configuration than the greeter
+        texture.x = 0;
+        texture.y = 0;
+        texture.width = global.screen_width;
+        texture.height = global.screen_height;
+        texture.set_automatic(true);
+
+        this._rootTexture = texture;
+    },
+
+    // Startup Animations
+    //
+    // We have two different animations, depending on whether we're a greeter
+    // or a normal session.
+    //
+    // In the greeter, we want to animate the panel from the top, and smoothly
+    // fade the login dialog on top of whatever plymouth left on screen, which we
+    // grab as a X11 texture_from_pixmap.
+    // Here we just have the code to animate the panel, the login dialog animation
+    // is handled by modalDialog.js
+    //
+    // In a normal session, we want to take the root background, which now holds
+    // the final frame of the GDM greeter, and slide it from the bottom, while
+    // at the same time scaling the UI contents of the new shell on top of the
+    // stage background.
+    //
+    // Usually, we don't want to paint the stage background color because the
+    // MetaBackgroundActor inside global.window_group covers the entirety of the
+    // screen. So, we set no_clear_hint at the end of the animation.
+
+    _prepareStartupAnimation: function() {
+        // Set ourselves to FULLSCREEN input mode while the animation is running
+        // so events don't get delivered to X11 windows (which are distorted by the animation)
+        global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
+
+        this._acquireRootBackground();
 
+        if (Main.sessionMode.isGreeter) {
+            global.stage.insert_child_below(this._rootTexture, null);
+
+            this._panelBox.translation_y = -this._panelBox.height;
+        } else {
+            global.stage.insert_child_above(this._rootTexture, null);
+
+            this.uiGroup.set_pivot_point(0.5, 0.5);
+            this.uiGroup.scale_x = this.uiGroup.scale_y = 0;
+        }
+    },
+
+    startupAnimation: function() {
+        if (Main.sessionMode.isGreeter)
+            this._startupAnimationGreeter();
+        else
+            this._startupAnimationSession();
+    },
+
+    _startupAnimationGreeter: function() {
+        // Don't animate the strut
         this._freezeUpdateRegions();
 
-        Tweener.addTween(this.panelBox,
+        Tweener.addTween(this._panelBox,
                          { translation_y: 0,
                            time: STARTUP_ANIMATION_TIME,
                            transition: 'easeOutQuad',
                            onComplete: this._startupAnimationComplete,
-                           onCompleteScope: this
-                         });
+                           onCompleteScope: this });
+    },
+
+    _startupAnimationSession: function() {
+        // Don't animate the strut
+        this._freezeUpdateRegions();
+
+        Tweener.addTween(this._rootTexture,
+                         { translation_y: -global.screen_height,
+                           time: STARTUP_ANIMATION_TIME,
+                           transition: 'linear' });
+
+        Tweener.addTween(this.uiGroup,
+                         { scale_x: 1,
+                           scale_y: 1,
+                           time: STARTUP_ANIMATION_TIME,
+                           transition: 'easeOutQuad',
+                           onComplete: this._startupAnimationComplete,
+                           onCompleteScope: this });
     },
 
     _startupAnimationComplete: function() {
+        // At this point, the UI group is covering everything, so
+        // we no longer need to clear the stage
+        global.stage.no_clear_hint = true;
+
+        global.stage_input_mode = Shell.StageInputMode.NORMAL;
+
+        this._rootTexture.destroy();
+        this._rootTexture = null;
+
         this.emit('panel-box-changed');
         this._thawUpdateRegions();
     },
diff --git a/js/ui/main.js b/js/ui/main.js
index a5d35e3..e79ba60 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -175,6 +175,14 @@ function start() {
 
     ExtensionDownloader.init();
     ExtensionSystem.init();
+
+    // Run the startup animation as soon as the mainloop is idle enough
+    // This is necessary to have it smooth and without interruptions from
+    // completed IO tasks
+    GLib.idle_add(GLib.PRIORITY_LOW, function() {
+        layoutManager.startupAnimation();
+        return false;
+    });
 }
 
 let _workspaces = [];



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