gnome-shell r79 - trunk/js/ui



Author: otaylor
Date: Sun Nov 23 04:12:34 2008
New Revision: 79
URL: http://svn.gnome.org/viewvc/gnome-shell?rev=79&view=rev

Log:
Use a Tweener "Frame Ticker" with a ClutterTimeline backend

Call Tweener.setFrameTicker() with a custom object that bridges to
ClutterTimeline to get new frame notifications. Combined with a
hack to dynamically adjust the frame ticker's frame rate when
Clutter drops frames, this means that our animations play in the
intended time even if rendering is too slow to maintain a full
60HZ frame rate.

http://bugzilla.gnome.org/show_bug.cgi?id=561745

Modified:
   trunk/js/ui/main.js

Modified: trunk/js/ui/main.js
==============================================================================
--- trunk/js/ui/main.js	(original)
+++ trunk/js/ui/main.js	Sun Nov 23 04:12:34 2008
@@ -1,7 +1,9 @@
 /* -*- mode: js2; js2-basic-offset: 4; -*- */
 
-const Shell = imports.gi.Shell;
 const Clutter = imports.gi.Clutter;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+const Tweener = imports.tweener.tweener;
 
 const Panel = imports.ui.panel;
 const Overlay = imports.ui.overlay;
@@ -16,9 +18,76 @@
 let run_dialog = null;
 let wm = null;
 
+// The "FrameTicker" object is an object used to feed new frames to Tweener
+// so it can update values and redraw. The default frame ticker for
+// Tweener just uses a simple timeout at a fixed frame rate and has no idea
+// of "catching up" by dropping frames.
+//
+// We substitute it with custom frame ticker here that connects Tweener to
+// a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a whole lot more
+// sophisticated than a simple timeout at a fixed frame rate, but at least
+// it knows how to drop frames. (See HippoAnimationManager for a more
+// sophisticated view of continous time updates; even better is to pay
+// attention to the vertical vblank and sync to that when possible.)
+//
+function ClutterFrameTicker() {
+    this._init();
+}
+
+ClutterFrameTicker.prototype = {
+    TARGET_FRAME_RATE : 60,
+
+    _init : function() {
+	// We don't have a finite duration; tweener will tell us to stop
+	// when we need to stop, so use 1000 seconds as "infinity"
+	this._timeline = new Clutter.Timeline({ fps: this.TARGET_FRAME_RATE,
+	                                        duration: 1000*1000 });
+	this._frame = 0;
+
+	let me = this;
+	this._timeline.connect('new-frame',
+	    function(timeline, frame) {
+		me._onNewFrame(frame);
+	    });
+    },
+
+    _onNewFrame : function(frame) {
+	// Unfortunately the interface to to send a new frame to tweener
+	// is a simple "next frame" and there is no provision for signaling
+	// that frames have been skipped or just telling it the new time.
+	// But what it actually does internally is just:
+	//
+	//  _currentTime += 1000/_ticker.FRAME_RATE;
+	//
+	// So by dynamically adjusting the value of FRAME_RATE we can trick
+	// it into dealing with dropped frames.
+
+	let delta = frame - this._frame;
+	if (delta == 0)
+	    this.FRAME_RATE = this.TARGET_FRAME_RATE;
+	else
+	    this.FRAME_RATE = this.TARGET_FRAME_RATE / delta;
+	this._frame = frame;
+	this.emit('prepare-frame');
+    },
+
+    start : function() {
+	this._timeline.start();
+    },
+
+    stop : function() {
+	this._timeline.stop();
+	this._frame = 0;
+    }
+};
+
+Signals.addSignalMethods(ClutterFrameTicker.prototype);
+
 function start() {
     let global = Shell.global_get();
 
+    Tweener.setFrameTicker(new ClutterFrameTicker());
+
     // The background color really only matters if there is no desktop
     // window (say, nautilus) running. We set it mostly so things look good
     // when we are running inside Xephyr.



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