2013-06-18 11:35:41 +00:00
|
|
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
2019-01-31 14:07:06 +00:00
|
|
|
/* exported Animation, AnimatedIcon, Spinner */
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2018-07-20 19:46:19 +00:00
|
|
|
const { Clutter, GLib, Gio, St } = imports.gi;
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-07-18 17:47:27 +00:00
|
|
|
var ANIMATED_ICON_UPDATE_TIMEOUT = 16;
|
2019-08-01 23:13:10 +00:00
|
|
|
var SPINNER_ANIMATION_TIME = 300;
|
|
|
|
var SPINNER_ANIMATION_DELAY = 1000;
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-10-31 01:19:44 +00:00
|
|
|
var Animation = class {
|
|
|
|
constructor(file, width, height, speed) {
|
2013-06-18 11:35:41 +00:00
|
|
|
this.actor = new St.Bin();
|
2017-11-30 01:36:05 +00:00
|
|
|
this.actor.set_size(width, height);
|
2017-12-02 00:27:35 +00:00
|
|
|
this.actor.connect('destroy', this._onDestroy.bind(this));
|
2017-11-30 01:36:05 +00:00
|
|
|
this.actor.connect('resource-scale-changed',
|
|
|
|
this._loadFile.bind(this, file, width, height));
|
|
|
|
|
2019-02-27 01:08:26 +00:00
|
|
|
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
|
|
|
this._scaleChangedId = themeContext.connect('notify::scale-factor',
|
|
|
|
this._loadFile.bind(this, file, width, height));
|
|
|
|
|
2013-06-18 11:35:41 +00:00
|
|
|
this._speed = speed;
|
|
|
|
|
|
|
|
this._isLoaded = false;
|
|
|
|
this._isPlaying = false;
|
|
|
|
this._timeoutId = 0;
|
|
|
|
this._frame = 0;
|
2014-03-23 02:20:50 +00:00
|
|
|
|
2017-11-30 01:36:05 +00:00
|
|
|
this._loadFile(file, width, height);
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
play() {
|
2013-06-18 11:35:41 +00:00
|
|
|
if (this._isLoaded && this._timeoutId == 0) {
|
|
|
|
if (this._frame == 0)
|
|
|
|
this._showFrame(0);
|
|
|
|
|
2017-12-02 00:27:35 +00:00
|
|
|
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_LOW, this._speed, this._update.bind(this));
|
2014-04-10 17:26:52 +00:00
|
|
|
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._update');
|
2013-06-18 11:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this._isPlaying = true;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
stop() {
|
2013-06-18 11:35:41 +00:00
|
|
|
if (this._timeoutId > 0) {
|
2019-08-19 18:50:33 +00:00
|
|
|
GLib.source_remove(this._timeoutId);
|
2013-06-18 11:35:41 +00:00
|
|
|
this._timeoutId = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._isPlaying = false;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-11-30 01:36:05 +00:00
|
|
|
_loadFile(file, width, height) {
|
|
|
|
let [validResourceScale, resourceScale] = this.actor.get_resource_scale();
|
2019-06-14 14:48:16 +00:00
|
|
|
let wasPlaying = this._isPlaying;
|
|
|
|
|
|
|
|
if (this._isPlaying)
|
|
|
|
this.stop();
|
2017-11-30 01:36:05 +00:00
|
|
|
|
|
|
|
this._isLoaded = false;
|
|
|
|
this.actor.destroy_all_children();
|
|
|
|
|
2019-06-14 14:48:16 +00:00
|
|
|
if (!validResourceScale) {
|
|
|
|
if (wasPlaying)
|
|
|
|
this.play();
|
2017-11-30 01:36:05 +00:00
|
|
|
return;
|
2019-06-14 14:48:16 +00:00
|
|
|
}
|
2017-11-30 01:36:05 +00:00
|
|
|
|
2019-01-31 13:43:52 +00:00
|
|
|
let textureCache = St.TextureCache.get_default();
|
2017-11-30 01:36:05 +00:00
|
|
|
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
2019-01-31 13:43:52 +00:00
|
|
|
this._animations = textureCache.load_sliced_image(file, width, height,
|
|
|
|
scaleFactor, resourceScale,
|
|
|
|
this._animationsLoaded.bind(this));
|
2017-11-30 01:36:05 +00:00
|
|
|
this.actor.set_child(this._animations);
|
2019-06-14 14:48:16 +00:00
|
|
|
|
|
|
|
if (wasPlaying)
|
|
|
|
this.play();
|
2017-11-30 01:36:05 +00:00
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_showFrame(frame) {
|
2013-06-18 11:35:41 +00:00
|
|
|
let oldFrameActor = this._animations.get_child_at_index(this._frame);
|
|
|
|
if (oldFrameActor)
|
|
|
|
oldFrameActor.hide();
|
|
|
|
|
|
|
|
this._frame = (frame % this._animations.get_n_children());
|
|
|
|
|
|
|
|
let newFrameActor = this._animations.get_child_at_index(this._frame);
|
|
|
|
if (newFrameActor)
|
|
|
|
newFrameActor.show();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_update() {
|
2013-06-18 11:35:41 +00:00
|
|
|
this._showFrame(this._frame + 1);
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_CONTINUE;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-11-30 01:36:05 +00:00
|
|
|
_syncAnimationSize() {
|
|
|
|
if (!this._isLoaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let [width, height] = this.actor.get_size();
|
|
|
|
|
|
|
|
for (let i = 0; i < this._animations.get_n_children(); ++i)
|
|
|
|
this._animations.get_child_at_index(i).set_size(width, height);
|
|
|
|
}
|
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_animationsLoaded() {
|
2016-11-21 17:09:42 +00:00
|
|
|
this._isLoaded = this._animations.get_n_children() > 0;
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-11-30 01:36:05 +00:00
|
|
|
this._syncAnimationSize();
|
|
|
|
|
2013-06-18 11:35:41 +00:00
|
|
|
if (this._isPlaying)
|
|
|
|
this.play();
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-10-31 00:03:21 +00:00
|
|
|
_onDestroy() {
|
2013-06-18 11:35:41 +00:00
|
|
|
this.stop();
|
2019-02-27 01:08:26 +00:00
|
|
|
|
|
|
|
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
|
|
|
if (this._scaleChangedId)
|
|
|
|
themeContext.disconnect(this._scaleChangedId);
|
|
|
|
this._scaleChangedId = 0;
|
2013-06-18 11:35:41 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
};
|
2013-06-18 11:35:41 +00:00
|
|
|
|
2017-10-31 01:19:44 +00:00
|
|
|
var AnimatedIcon = class extends Animation {
|
|
|
|
constructor(file, size) {
|
|
|
|
super(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
|
2013-06-18 11:35:41 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
};
|
2018-11-28 15:41:09 +00:00
|
|
|
|
2017-10-31 01:19:44 +00:00
|
|
|
var Spinner = class extends AnimatedIcon {
|
2019-01-29 01:27:05 +00:00
|
|
|
constructor(size, animate = false) {
|
2018-11-28 15:41:09 +00:00
|
|
|
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
|
2017-10-31 01:19:44 +00:00
|
|
|
super(file, size);
|
2018-11-28 16:34:48 +00:00
|
|
|
|
|
|
|
this.actor.opacity = 0;
|
|
|
|
this._animate = animate;
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-11-28 16:34:48 +00:00
|
|
|
|
2019-01-23 22:40:18 +00:00
|
|
|
_onDestroy() {
|
|
|
|
this._animate = false;
|
2017-10-31 01:19:44 +00:00
|
|
|
super._onDestroy();
|
|
|
|
}
|
2019-01-23 22:40:18 +00:00
|
|
|
|
2018-11-28 16:34:48 +00:00
|
|
|
play() {
|
2018-07-20 19:46:19 +00:00
|
|
|
this.actor.remove_all_transitions();
|
2018-11-28 16:34:48 +00:00
|
|
|
|
|
|
|
if (this._animate) {
|
2017-10-31 01:19:44 +00:00
|
|
|
super.play();
|
2018-07-20 19:46:19 +00:00
|
|
|
this.actor.ease({
|
2018-11-28 16:34:48 +00:00
|
|
|
opacity: 255,
|
2018-07-20 19:46:19 +00:00
|
|
|
delay: SPINNER_ANIMATION_DELAY,
|
|
|
|
duration: SPINNER_ANIMATION_TIME,
|
|
|
|
mode: Clutter.AnimationMode.LINEAR
|
2018-11-28 16:34:48 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.actor.opacity = 255;
|
2017-10-31 01:19:44 +00:00
|
|
|
super.play();
|
2018-11-28 16:34:48 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
}
|
2018-11-28 16:34:48 +00:00
|
|
|
|
|
|
|
stop() {
|
2018-07-20 19:46:19 +00:00
|
|
|
this.actor.remove_all_transitions();
|
2018-11-28 16:34:48 +00:00
|
|
|
|
|
|
|
if (this._animate) {
|
2018-07-20 19:46:19 +00:00
|
|
|
this.actor.ease({
|
2018-11-28 16:34:48 +00:00
|
|
|
opacity: 0,
|
2019-10-09 03:14:15 +00:00
|
|
|
duration: SPINNER_ANIMATION_TIME,
|
|
|
|
mode: Clutter.AnimationMode.LINEAR,
|
2018-07-20 19:46:19 +00:00
|
|
|
onComplete: () => super.stop()
|
2018-11-28 16:34:48 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.actor.opacity = 0;
|
2017-10-31 01:19:44 +00:00
|
|
|
super.stop();
|
2018-11-28 16:34:48 +00:00
|
|
|
}
|
2018-11-28 15:41:09 +00:00
|
|
|
}
|
2017-10-31 01:19:44 +00:00
|
|
|
};
|