Add a wrapper around tweener to do some extra integration
Automatically removes tweens on destroyed actors, and provides additional "animation started/stopped" callbacks (eg, for tracking whether or not to show window clone titles)
This commit is contained in:
parent
7d474b2217
commit
e79c776c2e
@ -1,8 +1,7 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const Big = imports.gi.Big;
|
const Big = imports.gi.Big;
|
||||||
const Tweener = imports.tweener.tweener;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
|
||||||
const DEFAULT_BUTTON_COLOR = new Clutter.Color();
|
const DEFAULT_BUTTON_COLOR = new Clutter.Color();
|
||||||
DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
|
DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
|
||||||
|
@ -5,11 +5,11 @@ const Gio = imports.gi.Gio;
|
|||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Tweener = imports.tweener.tweener;
|
|
||||||
|
|
||||||
const Overlay = imports.ui.overlay;
|
const Overlay = imports.ui.overlay;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const RunDialog = imports.ui.runDialog;
|
const RunDialog = imports.ui.runDialog;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
const WindowManager = imports.ui.windowManager;
|
const WindowManager = imports.ui.windowManager;
|
||||||
|
|
||||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
||||||
@ -21,78 +21,6 @@ let overlayActive = false;
|
|||||||
let runDialog = null;
|
let runDialog = null;
|
||||||
let wm = 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 = {
|
|
||||||
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.FRAME_RATE,
|
|
||||||
duration: 1000*1000 });
|
|
||||||
this._currentTime = 0;
|
|
||||||
this._frame = 0;
|
|
||||||
|
|
||||||
let me = this;
|
|
||||||
this._timeline.connect('new-frame',
|
|
||||||
function(timeline, frame) {
|
|
||||||
me._onNewFrame(frame);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
_onNewFrame : function(frame) {
|
|
||||||
// If there is a lot of setup to start the animation, then
|
|
||||||
// first frame number we get from clutter might be a long ways
|
|
||||||
// into the animation (or the animation might even be done).
|
|
||||||
// That looks bad, so we always start one frame into the
|
|
||||||
// animation then only do frame dropping from there.
|
|
||||||
let delta;
|
|
||||||
if (this._frame == 0)
|
|
||||||
delta = 1;
|
|
||||||
else
|
|
||||||
delta = frame - this._frame;
|
|
||||||
|
|
||||||
if (delta == 0) // protect against divide-by-0 if we get a frame twice
|
|
||||||
delta = 1;
|
|
||||||
|
|
||||||
// currentTime is in milliseconds
|
|
||||||
this._currentTime += (1000 * delta) / this.FRAME_RATE;
|
|
||||||
this._frame = frame;
|
|
||||||
this.emit('prepare-frame');
|
|
||||||
},
|
|
||||||
|
|
||||||
getTime : function() {
|
|
||||||
return this._currentTime;
|
|
||||||
},
|
|
||||||
|
|
||||||
start : function() {
|
|
||||||
this._timeline.start();
|
|
||||||
},
|
|
||||||
|
|
||||||
stop : function() {
|
|
||||||
this._timeline.stop();
|
|
||||||
this._frame = 0;
|
|
||||||
this._currentTime = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Signals.addSignalMethods(ClutterFrameTicker.prototype);
|
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
let global = Shell.Global.get();
|
let global = Shell.Global.get();
|
||||||
|
|
||||||
@ -101,7 +29,7 @@ function start() {
|
|||||||
global.grab_dbus_service();
|
global.grab_dbus_service();
|
||||||
global.start_task_panel();
|
global.start_task_panel();
|
||||||
|
|
||||||
Tweener.setFrameTicker(new ClutterFrameTicker());
|
Tweener.init();
|
||||||
|
|
||||||
// The background color really only matters if there is no desktop
|
// The background color really only matters if there is no desktop
|
||||||
// window (say, nautilus) running. We set it mostly so things look good
|
// window (say, nautilus) running. We set it mostly so things look good
|
||||||
|
@ -7,13 +7,13 @@ const Gtk = imports.gi.Gtk;
|
|||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Tweener = imports.tweener.tweener;
|
|
||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const DocDisplay = imports.ui.docDisplay;
|
const DocDisplay = imports.ui.docDisplay;
|
||||||
const GenericDisplay = imports.ui.genericDisplay;
|
const GenericDisplay = imports.ui.genericDisplay;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
const Workspaces = imports.ui.workspaces;
|
const Workspaces = imports.ui.workspaces;
|
||||||
|
|
||||||
const OVERLAY_BACKGROUND_COLOR = new Clutter.Color();
|
const OVERLAY_BACKGROUND_COLOR = new Clutter.Color();
|
||||||
|
255
js/ui/tweener.js
Normal file
255
js/ui/tweener.js
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
const Tweener = imports.tweener.tweener;
|
||||||
|
|
||||||
|
// This is a wrapper around imports.tweener.tweener that adds a bit of
|
||||||
|
// Clutter integration and some additional callbacks:
|
||||||
|
//
|
||||||
|
// 1. If the tweening target is a Clutter.Actor, then the tweenings
|
||||||
|
// will automatically be removed if the actor is destroyed
|
||||||
|
//
|
||||||
|
// 2. If target._delegate.onAnimationStart() exists, it will be
|
||||||
|
// called when the target starts being animated.
|
||||||
|
//
|
||||||
|
// 3. If target._delegate.onAnimationComplete() exists, it will be
|
||||||
|
// called once the target is no longer being animated.
|
||||||
|
//
|
||||||
|
// The onAnimationStart() and onAnimationComplete() callbacks differ
|
||||||
|
// from the tweener onStart and onComplete parameters, in that (1)
|
||||||
|
// they track whether or not the target has *any* tweens attached to
|
||||||
|
// it, as opposed to be called for *each* tween, and (2)
|
||||||
|
// onAnimationComplete() is always called when the object stops being
|
||||||
|
// animated, regardless of whether it stopped normally or abnormally.
|
||||||
|
//
|
||||||
|
// onAnimationComplete() is called at idle time, which means that if a
|
||||||
|
// tween completes and then another is added before returning to the
|
||||||
|
// main loop, the complete callback will not be called (until the new
|
||||||
|
// tween finishes).
|
||||||
|
|
||||||
|
|
||||||
|
// ActionScript Tweener methods that imports.tweener.tweener doesn't
|
||||||
|
// currently implement: getTweens, getVersion, registerTransition,
|
||||||
|
// setTimeScale, updateTime.
|
||||||
|
|
||||||
|
// imports.tweener.tweener methods that we don't re-export:
|
||||||
|
// pauseAllTweens, removeAllTweens, resumeAllTweens. (It would be hard
|
||||||
|
// to clean up properly after removeAllTweens, and also, any code that
|
||||||
|
// calls any of these is almost certainly wrong anyway, because they
|
||||||
|
// affect the entire application.)
|
||||||
|
|
||||||
|
|
||||||
|
// Called from Main.start
|
||||||
|
function init() {
|
||||||
|
Tweener.setFrameTicker(new ClutterFrameTicker());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addCaller(target, tweeningParameters) {
|
||||||
|
_wrapTweening(target, tweeningParameters);
|
||||||
|
Tweener.addCaller(target, tweeningParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addTween(target, tweeningParameters) {
|
||||||
|
_wrapTweening(target, tweeningParameters);
|
||||||
|
Tweener.addTween(target, tweeningParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _wrapTweening(target, tweeningParameters) {
|
||||||
|
let state = _getTweenState(target);
|
||||||
|
|
||||||
|
if (target instanceof Clutter.Actor && !state.destroyedId)
|
||||||
|
state.destroyedId = target.connect('destroy', _actorDestroyed);
|
||||||
|
|
||||||
|
_addHandler(target, tweeningParameters, 'onStart', _tweenStarted);
|
||||||
|
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getTweenState(target) {
|
||||||
|
// If we were paranoid, we could keep a plist mapping targets to
|
||||||
|
// states... but we're not that paranoid.
|
||||||
|
if (!target.__ShellTweenerState)
|
||||||
|
_resetTweenState(target);
|
||||||
|
return target.__ShellTweenerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _resetTweenState(target) {
|
||||||
|
let state = target.__ShellTweenerState;
|
||||||
|
|
||||||
|
if (state) {
|
||||||
|
if (state.destroyedId)
|
||||||
|
target.disconnect(state.destroyedId);
|
||||||
|
if (state.idleCompletedId)
|
||||||
|
Mainloop.source_remove(state.idleCompletedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
target.__ShellTweenerState = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function _addHandler(target, params, name, handler) {
|
||||||
|
if (params[name]) {
|
||||||
|
let oldHandler = params[name];
|
||||||
|
let oldScope = params[name + 'Scope'];
|
||||||
|
let oldParams = params[name + 'Params'];
|
||||||
|
let eventScope = oldScope ? oldScope : target;
|
||||||
|
|
||||||
|
params[name] = function () {
|
||||||
|
oldHandler.apply(eventScope, oldParams);
|
||||||
|
handler(target);
|
||||||
|
};
|
||||||
|
} else
|
||||||
|
params[name] = function () { handler(target); };
|
||||||
|
}
|
||||||
|
|
||||||
|
function _actorDestroyed(target) {
|
||||||
|
_resetTweenState(target);
|
||||||
|
Tweener.removeTweens(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tweenStarted(target) {
|
||||||
|
let state = _getTweenState(target);
|
||||||
|
let delegate = target._delegate;
|
||||||
|
|
||||||
|
if (!state.running && delegate && delegate.onAnimationStart)
|
||||||
|
delegate.onAnimationStart();
|
||||||
|
state.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _tweenCompleted(target) {
|
||||||
|
let state = _getTweenState(target);
|
||||||
|
|
||||||
|
if (!state.idleCompletedId)
|
||||||
|
state.idleCompletedId = Mainloop.idle_add(Lang.bind(null, _idleCompleted, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
function _idleCompleted(target) {
|
||||||
|
let state = _getTweenState(target);
|
||||||
|
let delegate = target._delegate;
|
||||||
|
|
||||||
|
if (!isTweening(target)) {
|
||||||
|
_resetTweenState(target);
|
||||||
|
if (delegate && delegate.onAnimationComplete)
|
||||||
|
delegate.onAnimationComplete();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTweenCount(scope) {
|
||||||
|
return Tweener.getTweenCount(scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
// imports.tweener.tweener doesn't provide this method (which exists
|
||||||
|
// in the ActionScript version) but it's easy to implement.
|
||||||
|
function isTweening(scope) {
|
||||||
|
return Tweener.getTweenCount(scope) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTweens(scope) {
|
||||||
|
if (Tweener.removeTweens.apply(null, arguments)) {
|
||||||
|
// If we just removed the last active tween, clean up
|
||||||
|
if (Tweener.getTweenCount(scope) == 0)
|
||||||
|
_tweenCompleted(scope);
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pauseTweens() {
|
||||||
|
return Tweener.pauseTweens.apply(null, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resumeTweens() {
|
||||||
|
return Tweener.resumeTweens.apply(null, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function registerSpecialProperty(name, getFunction, setFunction,
|
||||||
|
parameters, preProcessFunction) {
|
||||||
|
Tweener.registerSpecialProperty(name, getFunction, setFunction,
|
||||||
|
parameters, preProcessFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerSpecialPropertyModifier(name, modifyFunction, getFunction) {
|
||||||
|
Tweener.registerSpecialPropertyModifier(name, modifyFunction, getFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerSpecialPropertySplitter(name, splitFunction, parameters) {
|
||||||
|
Tweener.registerSpecialPropertySplitter(name, splitFunction, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 = {
|
||||||
|
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.FRAME_RATE,
|
||||||
|
duration: 1000*1000 });
|
||||||
|
this._currentTime = 0;
|
||||||
|
this._frame = 0;
|
||||||
|
|
||||||
|
let me = this;
|
||||||
|
this._timeline.connect('new-frame',
|
||||||
|
function(timeline, frame) {
|
||||||
|
me._onNewFrame(frame);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_onNewFrame : function(frame) {
|
||||||
|
// If there is a lot of setup to start the animation, then
|
||||||
|
// first frame number we get from clutter might be a long ways
|
||||||
|
// into the animation (or the animation might even be done).
|
||||||
|
// That looks bad, so we always start one frame into the
|
||||||
|
// animation then only do frame dropping from there.
|
||||||
|
let delta;
|
||||||
|
if (this._frame == 0)
|
||||||
|
delta = 1;
|
||||||
|
else
|
||||||
|
delta = frame - this._frame;
|
||||||
|
|
||||||
|
if (delta == 0) // protect against divide-by-0 if we get a frame twice
|
||||||
|
delta = 1;
|
||||||
|
|
||||||
|
// currentTime is in milliseconds
|
||||||
|
this._currentTime += (1000 * delta) / this.FRAME_RATE;
|
||||||
|
this._frame = frame;
|
||||||
|
this.emit('prepare-frame');
|
||||||
|
},
|
||||||
|
|
||||||
|
getTime : function() {
|
||||||
|
return this._currentTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
start : function() {
|
||||||
|
this._timeline.start();
|
||||||
|
},
|
||||||
|
|
||||||
|
stop : function() {
|
||||||
|
this._timeline.stop();
|
||||||
|
this._frame = 0;
|
||||||
|
this._currentTime = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Signals.addSignalMethods(ClutterFrameTicker.prototype);
|
@ -4,9 +4,9 @@ const Clutter = imports.gi.Clutter;
|
|||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Tweener = imports.tweener.tweener;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const WINDOW_ANIMATION_TIME = 0.25;
|
const WINDOW_ANIMATION_TIME = 0.25;
|
||||||
const SWITCH_ANIMATION_TIME = 0.5;
|
const SWITCH_ANIMATION_TIME = 0.5;
|
||||||
|
@ -10,11 +10,11 @@ const Meta = imports.gi.Meta;
|
|||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Tweener = imports.tweener.tweener;
|
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Overlay = imports.ui.overlay;
|
const Overlay = imports.ui.overlay;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
// Windows are slightly translucent in the overlay mode
|
// Windows are slightly translucent in the overlay mode
|
||||||
const WINDOW_OPACITY = 0.9 * 255;
|
const WINDOW_OPACITY = 0.9 * 255;
|
||||||
@ -58,6 +58,7 @@ WindowClone.prototype = {
|
|||||||
reactive: true,
|
reactive: true,
|
||||||
x: realWindow.x,
|
x: realWindow.x,
|
||||||
y: realWindow.y });
|
y: realWindow.y });
|
||||||
|
this.actor._delegate = this;
|
||||||
this.realWindow = realWindow;
|
this.realWindow = realWindow;
|
||||||
this.metaWindow = realWindow.meta_window;
|
this.metaWindow = realWindow.meta_window;
|
||||||
this.origX = realWindow.x;
|
this.origX = realWindow.x;
|
||||||
@ -77,12 +78,6 @@ WindowClone.prototype = {
|
|||||||
this._havePointer = false;
|
this._havePointer = false;
|
||||||
this._inDrag = false;
|
this._inDrag = false;
|
||||||
this._buttonDown = false;
|
this._buttonDown = false;
|
||||||
|
|
||||||
// We track the number of animations we are doing for the clone so we can
|
|
||||||
// hide the floating title while animating. It seems like it should be
|
|
||||||
// possible to use Tweener.getTweenCount(clone), but that annoyingly only
|
|
||||||
// updates after onComplete is called.
|
|
||||||
this._animationCount = 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
@ -91,27 +86,6 @@ WindowClone.prototype = {
|
|||||||
this._title.destroy();
|
this._title.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
addTween: function (params) {
|
|
||||||
this._animationCount++;
|
|
||||||
this._updateTitle();
|
|
||||||
|
|
||||||
if (params.onComplete) {
|
|
||||||
let oldOnComplete = params.onComplete;
|
|
||||||
let oldOnCompleteScope = params.onCompleteScope;
|
|
||||||
let oldOnCompleteParams = params.onCompleteParams;
|
|
||||||
let eventScope = oldOnCompleteScope ? oldOnCompleteScope : this.actor;
|
|
||||||
|
|
||||||
params.onComplete = function () {
|
|
||||||
oldOnComplete.apply(eventScope, oldOnCompleteParams);
|
|
||||||
this._onAnimationComplete();
|
|
||||||
};
|
|
||||||
} else
|
|
||||||
params.onComplete = this._onAnimationComplete;
|
|
||||||
params.onCompleteScope = this;
|
|
||||||
|
|
||||||
Tweener.addTween(this.actor, params);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onEnter: function (actor, event) {
|
_onEnter: function (actor, event) {
|
||||||
// If the user drags faster than we can follow, he'll end up
|
// If the user drags faster than we can follow, he'll end up
|
||||||
// leaving the window temporarily and then re-entering it
|
// leaving the window temporarily and then re-entering it
|
||||||
@ -132,7 +106,7 @@ WindowClone.prototype = {
|
|||||||
|
|
||||||
this._havePointer = false;
|
this._havePointer = false;
|
||||||
|
|
||||||
if (this._animationCount)
|
if (Tweener.isTweening(this.actor))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
actor.raise(this.stackAbove);
|
actor.raise(this.stackAbove);
|
||||||
@ -140,7 +114,7 @@ WindowClone.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onButtonPress : function (actor, event) {
|
_onButtonPress : function (actor, event) {
|
||||||
if (this._animationCount)
|
if (Tweener.isTweening(this.actor))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
actor.raise_top();
|
actor.raise_top();
|
||||||
@ -209,13 +183,14 @@ WindowClone.prototype = {
|
|||||||
this.emit('dragged', stageX, stageY, event.get_time());
|
this.emit('dragged', stageX, stageY, event.get_time());
|
||||||
if (this.realWindow.get_workspace() == origWorkspace) {
|
if (this.realWindow.get_workspace() == origWorkspace) {
|
||||||
// Didn't get moved elsewhere, restore position
|
// Didn't get moved elsewhere, restore position
|
||||||
this.addTween({ x: this._dragStartX + this._dragOffsetX,
|
Tweener.addTween(this.actor,
|
||||||
y: this._dragStartY + this._dragOffsetY,
|
{ x: this._dragStartX + this._dragOffsetX,
|
||||||
time: SNAP_BACK_ANIMATION_TIME,
|
y: this._dragStartY + this._dragOffsetY,
|
||||||
transition: "easeOutQuad",
|
time: SNAP_BACK_ANIMATION_TIME,
|
||||||
onComplete: this._onSnapBackComplete,
|
transition: "easeOutQuad",
|
||||||
onCompleteScope: this
|
onComplete: this._onSnapBackComplete,
|
||||||
});
|
onCompleteScope: this
|
||||||
|
});
|
||||||
// Most likely, the clone is going to move away from the
|
// Most likely, the clone is going to move away from the
|
||||||
// pointer now. But that won't cause a leave-event, so
|
// pointer now. But that won't cause a leave-event, so
|
||||||
// do this by hand. Of course, if the window only snaps
|
// do this by hand. Of course, if the window only snaps
|
||||||
@ -234,12 +209,15 @@ WindowClone.prototype = {
|
|||||||
this.actor.set_position(this._dragOrigX, this._dragOrigY);
|
this.actor.set_position(this._dragOrigX, this._dragOrigY);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onAnimationComplete : function () {
|
// Called by Tweener
|
||||||
this._animationCount--;
|
onAnimationStart : function () {
|
||||||
if (this._animationCount == 0) {
|
this._updateTitle();
|
||||||
this._updateTitle();
|
},
|
||||||
this.actor.raise(this.stackAbove);
|
|
||||||
}
|
// Called by Tweener
|
||||||
|
onAnimationComplete : function () {
|
||||||
|
this._updateTitle();
|
||||||
|
this.actor.raise(this.stackAbove);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createTitle : function () {
|
_createTitle : function () {
|
||||||
@ -313,7 +291,7 @@ WindowClone.prototype = {
|
|||||||
_updateTitle : function () {
|
_updateTitle : function () {
|
||||||
let shouldShow = (this._havePointer &&
|
let shouldShow = (this._havePointer &&
|
||||||
!this._buttonDown &&
|
!this._buttonDown &&
|
||||||
this._animationCount == 0);
|
!Tweener.isTweening(this.actor));
|
||||||
|
|
||||||
if (shouldShow)
|
if (shouldShow)
|
||||||
this._showTitle();
|
this._showTitle();
|
||||||
@ -528,21 +506,16 @@ Workspace.prototype = {
|
|||||||
let desiredSize = global.screen_width * fraction;
|
let desiredSize = global.screen_width * fraction;
|
||||||
let scale = Math.min(desiredSize / size, 1.0);
|
let scale = Math.min(desiredSize / size, 1.0);
|
||||||
|
|
||||||
let tweenProperties = {
|
Tweener.addTween(clone.actor,
|
||||||
x: xCenter - 0.5 * scale * clone.actor.width,
|
{ x: xCenter - 0.5 * scale * clone.actor.width,
|
||||||
y: yCenter - 0.5 * scale * clone.actor.height,
|
y: yCenter - 0.5 * scale * clone.actor.height,
|
||||||
scale_x: scale,
|
scale_x: scale,
|
||||||
scale_y: scale,
|
scale_y: scale,
|
||||||
time: Overlay.ANIMATION_TIME,
|
workspace_relative: workspaceZooming ? this : null,
|
||||||
opacity: WINDOW_OPACITY,
|
time: Overlay.ANIMATION_TIME,
|
||||||
transition: "easeOutQuad"
|
opacity: WINDOW_OPACITY,
|
||||||
};
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
// workspace_relative assumes that the workspace is zooming in or out
|
|
||||||
if (workspaceZooming)
|
|
||||||
tweenProperties['workspace_relative'] = this;
|
|
||||||
|
|
||||||
clone.addTween(tweenProperties);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -659,15 +632,16 @@ Workspace.prototype = {
|
|||||||
|
|
||||||
for (let i = 1; i < this._windows.length; i++) {
|
for (let i = 1; i < this._windows.length; i++) {
|
||||||
let clone = this._windows[i];
|
let clone = this._windows[i];
|
||||||
clone.addTween({ x: clone.origX,
|
Tweener.addTween(clone.actor,
|
||||||
y: clone.origY,
|
{ x: clone.origX,
|
||||||
scale_x: 1.0,
|
y: clone.origY,
|
||||||
scale_y: 1.0,
|
scale_x: 1.0,
|
||||||
workspace_relative: this,
|
scale_y: 1.0,
|
||||||
time: Overlay.ANIMATION_TIME,
|
workspace_relative: this,
|
||||||
opacity: 255,
|
time: Overlay.ANIMATION_TIME,
|
||||||
transition: "easeOutQuad"
|
opacity: 255,
|
||||||
});
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.leavingOverlay = false;
|
this.leavingOverlay = false;
|
||||||
@ -1207,6 +1181,9 @@ Tweener.registerSpecialPropertyModifier("workspace_relative", _workspace_relativ
|
|||||||
function _workspace_relative_modifier(workspace) {
|
function _workspace_relative_modifier(workspace) {
|
||||||
let endX, endY;
|
let endX, endY;
|
||||||
|
|
||||||
|
if (!workspace)
|
||||||
|
return [];
|
||||||
|
|
||||||
if (workspace.leavingOverlay) {
|
if (workspace.leavingOverlay) {
|
||||||
endX = workspace.fullSizeX;
|
endX = workspace.fullSizeX;
|
||||||
endY = workspace.fullSizeY;
|
endY = workspace.fullSizeY;
|
||||||
|
Loading…
Reference in New Issue
Block a user