summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen W. Taylor <otaylor@fishsoup.net>2014-08-11 18:15:45 +0200
committerOwen W. Taylor <otaylor@fishsoup.net>2014-09-03 13:45:01 -0400
commit650dea017b551b24f594f104366afb47fd73794c (patch)
tree91f234eb4b795bc6ca0d913b27358216cba534de
parent70099872ab2a2bb5e78080348c6df9444b3a87bb (diff)
downloadgnome-shell-650dea017b551b24f594f104366afb47fd73794c.tar.gz
Adapt to Mutter background changes
The rewrite of Mutter's background code (see bug 735637) requires corresponding changes here - we no longer need to layer multiple MetaBackgroundActors together. The general strategy is that a BackgroundSource object is created per GSettings schema, and keeps either one Background/MetaBackground pair, or, for animation, a Background/Metabackground pair for each monitor. https://bugzilla.gnome.org/show_bug.cgi?id=735638
-rw-r--r--js/ui/background.js832
-rw-r--r--js/ui/layout.js12
-rw-r--r--js/ui/overview.js14
-rw-r--r--js/ui/workspaceThumbnail.js6
4 files changed, 370 insertions, 494 deletions
diff --git a/js/ui/background.js b/js/ui/background.js
index 27ce1242a..ea5cae473 100644
--- a/js/ui/background.js
+++ b/js/ui/background.js
@@ -1,5 +1,98 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+// READ THIS FIRST
+// Background handling is a maze of objects, both objects in this file, and
+// also objects inside Mutter. They all have a role.
+//
+// BackgroundManager
+// The only object that other parts of GNOME Shell deal with; a
+// BackgroundManager creates background actors and adds them to
+// the specified container. When the background is changed by the
+// user it will fade out the old actor and fade in the new actor.
+// (This is separate from the fading for an animated background,
+// since using two actors is quite inefficient.)
+//
+// MetaBackgroundImage
+// An object represented an image file that will be used for drawing
+// the background. MetaBackgroundImage objects asynchronously load,
+// so they are first created in an unloaded state, then later emit
+// a ::loaded signal when the Cogl object becomes available.
+//
+// MetaBackgroundImageCache
+// A cache from filename to MetaBackgroundImage.
+//
+// BackgroundSource
+// An object that is created for each GSettings schema (separate
+// settings schemas are used for the lock screen and main background),
+// and holds a reference to shared Background objects.
+//
+// MetaBackground
+// Holds the specification of a background - a background color
+// or gradient and one or two images blended together.
+//
+// Background
+// JS delegate object that Connects a MetaBackground to the GSettings
+// schema for the background.
+//
+// Animation
+// A helper object that handles loading a XML-based animation; it is a
+// wrapper for GnomeDesktop.BGSlideShow
+//
+// MetaBackgroundActor
+// An actor that draws the background for a single monitor
+//
+// BackgroundCache
+// A cache of Settings schema => BackgroundSource and of a single Animation.
+// Also used to share file monitors.
+//
+// A static image, background color or gradient is relatively straightforward. The
+// calling code creates a separate BackgroundManager for each monitor. Since they
+// are created for the same GSettings schema, they will use the same BackgroundSource
+// object, which provides a single Background and correspondingly a single
+// MetaBackground object.
+//
+// BackgroundManager BackgroundManager
+// | \ / |
+// | BackgroundSource | looked up in BackgroundCache
+// | | |
+// | Background |
+// | | |
+// MetaBackgroundActor | MetaBackgroundActor
+// \ | /
+// `------- MetaBackground ------'
+// |
+// MetaBackgroundImage looked up in MetaBackgroundImageCache
+//
+// The animated case is tricker because the animation XML file can specify different
+// files for different monitor resolutions and aspect ratios. For this reason,
+// the BackgroundSource provides different Background share a single Animation object,
+// which tracks the animation, but use different MetaBackground objects. In the
+// common case, the different MetaBackground objects will be created for the
+// same filename and look up the *same* MetaBackgroundImage object, so there is
+// little wasted memory:
+//
+// BackgroundManager BackgroundManager
+// | \ / |
+// | BackgroundSource | looked up in BackgroundCache
+// | / \ |
+// | Background Background |
+// | | \ / | |
+// | | Animation | | looked up in BackgroundCache
+// MetaBackgroundA|tor Me|aBackgroundActor
+// \ | | /
+// MetaBackground MetaBackground
+// \ /
+// MetaBackgroundImage looked up in MetaBackgroundImageCache
+// MetaBackgroundImage
+//
+// But the case of different filenames and different background images
+// is possible as well:
+// ....
+// MetaBackground MetaBackground
+// | |
+// MetaBackgroundImage MetaBackgroundImage
+// MetaBackgroundImage MetaBackgroundImage
+
const Clutter = imports.gi.Clutter;
const GDesktopEnums = imports.gi.GDesktopEnums;
const Gio = imports.gi.Gio;
@@ -36,235 +129,25 @@ const BackgroundCache = new Lang.Class({
Name: 'BackgroundCache',
_init: function() {
- this._patterns = [];
- this._images = [];
- this._pendingFileLoads = [];
- this._fileMonitors = {};
- },
-
- getPatternContent: function(params) {
- params = Params.parse(params, { monitorIndex: 0,
- color: null,
- secondColor: null,
- shadingType: null,
- effects: Meta.BackgroundEffects.NONE });
-
- let content = null;
-
- let candidateContent = null;
- for (let i = 0; i < this._patterns.length; i++) {
- if (this._patterns[i].get_shading() != params.shadingType)
- continue;
-
- if (!params.color.equal(this._patterns[i].get_color()))
- continue;
-
- if (params.shadingType != GDesktopEnums.BackgroundShading.SOLID &&
- !params.secondColor.equal(this._patterns[i].get_second_color()))
- continue;
-
- candidateContent = this._patterns[i];
-
- if (params.effects != this._patterns[i].effects)
- continue;
-
- break;
- }
-
- if (candidateContent) {
- content = candidateContent.copy(params.monitorIndex, params.effects);
- } else {
- content = new Meta.Background({ meta_screen: global.screen,
- monitor: params.monitorIndex,
- effects: params.effects });
-
- if (params.shadingType == GDesktopEnums.BackgroundShading.SOLID) {
- content.load_color(params.color);
- } else {
- content.load_gradient(params.shadingType, params.color, params.secondColor);
- }
- }
-
- this._patterns.push(content);
- return content;
+ this._pendingFileLoads = [];
+ this._fileMonitors = {};
+ this._backgroundSources = {};
},
- _monitorFile: function(filename) {
+ monitorFile: function(filename) {
if (this._fileMonitors[filename])
return;
let file = Gio.File.new_for_path(filename);
let monitor = file.monitor(Gio.FileMonitorFlags.NONE, null);
-
- let signalId = monitor.connect('changed',
- Lang.bind(this, function() {
- for (let i = 0; i < this._images.length; i++) {
- if (this._images[i].get_filename() == filename)
- this._images.splice(i, 1);
- }
-
- monitor.disconnect(signalId);
-
- this.emit('file-changed', filename);
- }));
+ monitor.connect('changed',
+ Lang.bind(this, function() {
+ this.emit('file-changed', filename);
+ }));
this._fileMonitors[filename] = monitor;
},
- _removeContent: function(contentList, content) {
- let index = contentList.indexOf(content);
- if (index < 0)
- throw new Error("Trying to remove invalid content: " + content);
- contentList.splice(index, 1);
- },
-
- removePatternContent: function(content) {
- this._removeContent(this._patterns, content);
- },
-
- removeImageContent: function(content) {
- let filename = content.get_filename();
-
- let hasOtherUsers = this._images.some(function(content) { return filename == content.get_filename(); });
- if (!hasOtherUsers)
- delete this._fileMonitors[filename];
-
- this._removeContent(this._images, content);
- },
-
- _attachCallerToFileLoad: function(caller, fileLoad) {
- fileLoad.callers.push(caller);
-
- if (!caller.cancellable)
- return;
-
- caller.cancellable.connect(Lang.bind(this, function() {
- let idx = fileLoad.callers.indexOf(caller);
- fileLoad.callers.splice(idx, 1);
-
- if (fileLoad.callers.length == 0) {
- fileLoad.cancellable.cancel();
-
- let idx = this._pendingFileLoads.indexOf(fileLoad);
- this._pendingFileLoads.splice(idx, 1);
- }
- }));
- },
-
- _loadImageContent: function(params) {
- params = Params.parse(params, { monitorIndex: 0,
- style: null,
- filename: null,
- effects: Meta.BackgroundEffects.NONE,
- cancellable: null,
- onFinished: null });
-
- let caller = { monitorIndex: params.monitorIndex,
- effects: params.effects,
- cancellable: params.cancellable,
- onFinished: params.onFinished };
-
- for (let i = 0; i < this._pendingFileLoads.length; i++) {
- let fileLoad = this._pendingFileLoads[i];
-
- if (fileLoad.filename == params.filename &&
- fileLoad.style == params.style) {
- this._attachCallerToFileLoad(caller, fileLoad);
- return;
- }
- }
-
- let fileLoad = { filename: params.filename,
- style: params.style,
- cancellable: new Gio.Cancellable(),
- callers: [] };
- this._attachCallerToFileLoad(caller, fileLoad);
-
- let content = new Meta.Background({ meta_screen: global.screen });
-
- content.load_file_async(params.filename,
- params.style,
- params.cancellable,
- Lang.bind(this,
- function(object, result) {
- try {
- content.load_file_finish(result);
-
- this._monitorFile(params.filename);
- } catch(e) {
- content = null;
- }
-
- for (let i = 0; i < fileLoad.callers.length; i++) {
- let caller = fileLoad.callers[i];
- if (caller.onFinished) {
- let newContent;
-
- if (content) {
- newContent = content.copy(caller.monitorIndex, caller.effects);
- this._images.push(newContent);
- }
-
- caller.onFinished(newContent);
- }
- }
-
- let idx = this._pendingFileLoads.indexOf(fileLoad);
- this._pendingFileLoads.splice(idx, 1);
- }));
- },
-
- getImageContent: function(params) {
- params = Params.parse(params, { monitorIndex: 0,
- style: null,
- filename: null,
- effects: Meta.BackgroundEffects.NONE,
- cancellable: null,
- onFinished: null });
-
- let content = null;
-
- let candidateContent = null;
- for (let i = 0; i < this._images.length; i++) {
- if (this._images[i].get_style() != params.style)
- continue;
-
- if (this._images[i].get_filename() != params.filename)
- continue;
-
- if (params.style == GDesktopEnums.BackgroundStyle.SPANNED &&
- this._images[i].monitor != params.monitorIndex)
- continue;
-
- candidateContent = this._images[i];
-
- if (params.effects != this._images[i].effects)
- continue;
-
- break;
- }
-
- if (candidateContent) {
- content = candidateContent.copy(params.monitorIndex, params.effects);
-
- if (params.cancellable && params.cancellable.is_cancelled())
- content = null;
- else
- this._images.push(content);
-
- if (params.onFinished)
- params.onFinished(content);
- } else {
- this._loadImageContent({ filename: params.filename,
- style: params.style,
- effects: params.effects,
- monitorIndex: params.monitorIndex,
- cancellable: params.cancellable,
- onFinished: params.onFinished });
-
- }
- },
-
getAnimation: function(params) {
params = Params.parse(params, { filename: null,
onLoaded: null });
@@ -282,7 +165,6 @@ const BackgroundCache = new Lang.Class({
let animation = new Animation({ filename: params.filename });
animation.load(Lang.bind(this, function() {
- this._monitorFile(params.filename);
this._animationFilename = params.filename;
this._animation = animation;
@@ -294,6 +176,31 @@ const BackgroundCache = new Lang.Class({
GLib.Source.set_name_by_id(id, '[gnome-shell] params.onLoaded');
}
}));
+ },
+
+ getBackgroundSource: function(layoutManager, settingsSchema) {
+ // The layoutManager is always the same one; we pass in it since
+ // Main.layoutManager may not be set yet
+
+ if (!(settingsSchema in this._backgroundSources)) {
+ this._backgroundSources[settingsSchema] = new BackgroundSource(layoutManager, settingsSchema);
+ this._backgroundSources[settingsSchema]._useCount = 1;
+ } else {
+ this._backgroundSources[settingsSchema]._useCount++;
+ }
+
+ return this._backgroundSources[settingsSchema];
+ },
+
+ releaseBackgroundSource: function(settingsSchema) {
+ if (settingsSchema in this._backgroundSources) {
+ let source = this._backgroundSources[settingsSchema];
+ source._useCount--;
+ if (source._useCount == 0) {
+ delete this._backgroundSources[settingsSchema];
+ source.destroy();
+ }
+ }
}
});
Signals.addSignalMethods(BackgroundCache.prototype);
@@ -310,28 +217,19 @@ const Background = new Lang.Class({
_init: function(params) {
params = Params.parse(params, { monitorIndex: 0,
layoutManager: Main.layoutManager,
- effects: Meta.BackgroundEffects.NONE,
settings: null,
- overrideImage: null });
- this.actor = new Meta.BackgroundGroup();
- this.actor._delegate = this;
+ filename: null,
+ style: null });
- this._destroySignalId = this.actor.connect('destroy',
- Lang.bind(this, this._destroy));
+ this.background = new Meta.Background({ meta_screen: global.screen });
+ this.background._delegate = this;
this._settings = params.settings;
- this._overrideImage = params.overrideImage;
+ this._filename = params.filename;
+ this._style = params.style;
this._monitorIndex = params.monitorIndex;
this._layoutManager = params.layoutManager;
- this._effects = params.effects;
this._fileWatches = {};
- this._pattern = null;
- // contains a single image for static backgrounds and
- // two images (from and to) for slide shows
- this._images = {};
-
- this._brightness = 1.0;
- this._vignetteSharpness = 0.2;
this._cancellable = new Gio.Cancellable();
this.isLoaded = false;
@@ -342,7 +240,7 @@ const Background = new Lang.Class({
this._load();
},
- _destroy: function() {
+ destroy: function() {
this._cancellable.cancel();
if (this._updateAnimationTimeoutId) {
@@ -357,28 +255,6 @@ const Background = new Lang.Class({
}
this._fileWatches = null;
- if (this._pattern) {
- if (this._pattern.content)
- this._cache.removePatternContent(this._pattern.content);
-
- this._pattern.destroy();
- this._pattern = null;
- }
-
- keys = Object.keys(this._images);
- for (i = 0; i < keys.length; i++) {
- let actor = this._images[keys[i]];
-
- if (actor.content)
- this._cache.removeImageContent(actor.content);
-
- actor.destroy();
- this._images[keys[i]] = null;
- }
-
- this.actor.disconnect(this._destroySignalId);
- this._destroySignalId = 0;
-
if (this._settingsChangedSignalId != 0)
this._settings.disconnect(this._settingsChangedSignalId);
this._settingsChangedSignalId = 0;
@@ -407,22 +283,17 @@ const Background = new Lang.Class({
let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY);
- let content = this._cache.getPatternContent({ monitorIndex: this._monitorIndex,
- effects: this._effects,
- color: color,
- secondColor: secondColor,
- shadingType: shadingType });
-
- this._pattern = new Meta.BackgroundActor();
- this.actor.add_child(this._pattern);
-
- this._pattern.content = content;
+ if (shadingType == GDesktopEnums.BackgroundShading.SOLID)
+ this.background.set_color(color);
+ else
+ this.background.set_gradient(shadingType, color, secondColor);
},
- _watchCacheFile: function(filename) {
+ _watchFile: function(filename) {
if (this._fileWatches[filename])
return;
+ this._cache.monitorFile(filename);
let signalId = this._cache.connect('file-changed',
Lang.bind(this, function(cache, changedFile) {
if (changedFile == filename) {
@@ -432,82 +303,46 @@ const Background = new Lang.Class({
this._fileWatches[filename] = signalId;
},
- _ensureImage: function(index) {
- if (this._images[index])
- return;
-
- let actor = new Meta.BackgroundActor();
-
- // The background pattern is the first actor in
- // the group, and all images should be above that.
- this.actor.insert_child_at_index(actor, index + 1);
- this._images[index] = actor;
- },
-
- _updateImage: function(index, content, filename) {
- content.brightness = this._brightness;
- content.vignette_sharpness = this._vignetteSharpness;
-
- let image = this._images[index];
- if (image.content)
- this._cache.removeImageContent(image.content);
- image.content = content;
- this._watchCacheFile(filename);
- },
-
- _updateAnimationProgress: function() {
- if (this._images[1])
- this._images[1].opacity = this._animation.transitionProgress * 255;
-
- this._queueUpdateAnimation();
- },
-
_updateAnimation: function() {
this._updateAnimationTimeoutId = 0;
this._animation.update(this._layoutManager.monitors[this._monitorIndex]);
let files = this._animation.keyFrameFiles;
- if (files.length == 0) {
+ let finish = Lang.bind(this, function() {
this._setLoaded();
+ if (files.length > 1) {
+ this.background.set_blend(files[0], files[1],
+ this._animation.transitionProgress,
+ this._style);
+ } else if (files.length > 0) {
+ this.background.set_filename(files[0], this._style);
+ } else {
+ this.background.set_filename(null, this._style);
+ }
this._queueUpdateAnimation();
- return;
- }
+ });
+ let cache = Meta.BackgroundImageCache.get_default();
let numPendingImages = files.length;
+ let images = [];
for (let i = 0; i < files.length; i++) {
- if (this._images[i] && this._images[i].content &&
- this._images[i].content.get_filename() == files[i]) {
-
+ this._watchFile(files[i]);
+ let image = cache.load(files[i]);
+ images.push(image);
+ if (image.is_loaded()) {
numPendingImages--;
if (numPendingImages == 0)
- this._updateAnimationProgress();
- continue;
+ finish();
+ } else {
+ let id = image.connect('loaded',
+ Lang.bind(this, function() {
+ image.disconnect(id);
+ numPendingImages--;
+ if (numPendingImages == 0)
+ finish();
+ }));
}
- this._cache.getImageContent({ monitorIndex: this._monitorIndex,
- effects: this._effects,
- style: this._style,
- filename: files[i],
- cancellable: this._cancellable,
- onFinished: Lang.bind(this, function(content, i) {
- numPendingImages--;
-
- if (!content) {
- this._setLoaded();
- if (numPendingImages == 0)
- this._updateAnimationProgress();
- return;
- }
-
- this._ensureImage(i);
- this._updateImage(i, content, files[i]);
-
- if (numPendingImages == 0) {
- this._setLoaded();
- this._updateAnimationProgress();
- }
- }, i)
- });
}
},
@@ -551,25 +386,26 @@ const Background = new Lang.Class({
}
this._updateAnimation();
- this._watchCacheFile(filename);
+ this._watchFile(filename);
})
});
},
_loadImage: function(filename) {
- this._cache.getImageContent({ monitorIndex: this._monitorIndex,
- effects: this._effects,
- style: this._style,
- filename: filename,
- cancellable: this._cancellable,
- onFinished: Lang.bind(this, function(content) {
- if (content) {
- this._ensureImage(0);
- this._updateImage(0, content, filename);
- }
- this._setLoaded();
- })
- });
+ this.background.set_filename(filename, this._style);
+ this._watchFile(filename);
+
+ let cache = Meta.BackgroundImageCache.get_default();
+ let image = cache.load(filename);
+ if (image.is_loaded())
+ this._setLoaded();
+ else {
+ let id = image.connect('loaded',
+ Lang.bind(this, function() {
+ this._setLoaded();
+ image.disconnect(id);
+ }));
+ }
},
_loadFile: function(filename) {
@@ -584,95 +420,118 @@ const Background = new Lang.Class({
this._loadPattern();
- let filename;
- if (this._overrideImage != null) {
- filename = this._overrideImage;
- this._style = GDesktopEnums.BackgroundStyle.ZOOM; // Hardcode
- } else {
- this._style = this._settings.get_enum(BACKGROUND_STYLE_KEY);
- if (this._style == GDesktopEnums.BackgroundStyle.NONE) {
- this._setLoaded();
- return;
- }
-
- let uri = this._settings.get_string(PICTURE_URI_KEY);
- if (GLib.uri_parse_scheme(uri) != null)
- filename = Gio.File.new_for_uri(uri).get_path();
- else
- filename = uri;
- }
-
- if (!filename) {
+ if (!this._filename) {
this._setLoaded();
return;
}
- this._loadFile(filename);
+ this._loadFile(this._filename);
},
+});
+Signals.addSignalMethods(Background.prototype);
- get brightness() {
- return this._brightness;
- },
+let _systemBackground;
- set brightness(factor) {
- this._brightness = factor;
- if (this._pattern && this._pattern.content)
- this._pattern.content.brightness = factor;
+const SystemBackground = new Lang.Class({
+ Name: 'SystemBackground',
- let keys = Object.keys(this._images);
- for (let i = 0; i < keys.length; i++) {
- let image = this._images[keys[i]];
- if (image && image.content)
- image.content.brightness = factor;
+ _init: function() {
+ let filename = global.datadir + '/theme/noise-texture.png';
+
+ if (_systemBackground == null) {
+ _systemBackground = new Meta.Background({ meta_screen: global.screen });
+ _systemBackground.set_filename(filename, GDesktopEnums.BackgroundStyle.WALLPAPER);
+ }
+
+ this.actor = new Meta.BackgroundActor({ meta_screen: global.screen,
+ monitor: 0,
+ background: _systemBackground });
+
+ let cache = Meta.BackgroundImageCache.get_default();
+ let image = cache.load(filename);
+ if (image.is_loaded()) {
+ image = null;
+ let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
+ this.emit('loaded');
+ return GLib.SOURCE_REMOVE;
+ }));
+ GLib.Source.set_name_by_id(id, '[gnome-shell] SystemBackground.loaded');
+ } else {
+ let id = image.connect('loaded',
+ Lang.bind(this, function() {
+ this.emit('loaded');
+ image.disconnect(id);
+ image = null;
+ }));
}
},
+});
+Signals.addSignalMethods(SystemBackground.prototype);
+
+const BackgroundSource = new Lang.Class({
+ Name: 'BackgroundSource',
- get vignetteSharpness() {
- return this._vignetteSharpness;
+ _init: function(layoutManager, settingsSchema) {
+ // Allow override the background image setting for performance testing
+ this._layoutManager = layoutManager;
+ this._overrideImage = GLib.getenv('SHELL_BACKGROUND_IMAGE');
+ this._settings = new Gio.Settings({ schema_id: settingsSchema });
+ this._backgrounds = [];
},
- set vignetteSharpness(sharpness) {
- this._vignetteSharpness = sharpness;
- if (this._pattern && this._pattern.content)
- this._pattern.content.vignette_sharpness = sharpness;
+ getBackground: function(monitorIndex) {
+ let filename = null;
+ let style;
- let keys = Object.keys(this._images);
- for (let i = 0; i < keys.length; i++) {
- let image = this._images[keys[i]];
- if (image && image.content)
- image.content.vignette_sharpness = sharpness;
+ if (this._overrideImage != null) {
+ filename = this._overrideImage;
+ style = GDesktopEnums.BackgroundStyle.ZOOM; // Hardcode
+ } else {
+ style = this._settings.get_enum(BACKGROUND_STYLE_KEY);
+ if (style != GDesktopEnums.BackgroundStyle.NONE) {
+ let uri = this._settings.get_string(PICTURE_URI_KEY);
+ if (GLib.uri_parse_scheme(uri) != null)
+ filename = Gio.File.new_for_uri(uri).get_path();
+ else
+ filename = uri;
+ }
}
- }
-});
-Signals.addSignalMethods(Background.prototype);
-const SystemBackground = new Lang.Class({
- Name: 'SystemBackground',
+ // Animated backgrounds are (potentially) per-monitor, since
+ // they can have variants that depend on the aspect ratio and
+ // size of the monitor; for other backgrounds we can use the
+ // same background object for all monitors.
+ if (filename == null || !filename.endsWith('.xml'))
+ monitorIndex = 0;
+
+ if (!(monitorIndex in this._backgrounds)) {
+ let background = new Background({
+ monitorIndex: monitorIndex,
+ layoutManager: this._layoutManager,
+ settings: this._settings,
+ filename: filename,
+ style: style
+ });
+
+ let changedId = background.connect('changed', Lang.bind(this, function() {
+ background.disconnect(changedId);
+ background.destroy();
+ delete this._backgrounds[monitorIndex];
+ }));
+
+ this._backgrounds[monitorIndex] = background;
+ }
- _init: function() {
- this._cache = getBackgroundCache();
- this.actor = new Meta.BackgroundActor();
-
- this._cache.getImageContent({ style: GDesktopEnums.BackgroundStyle.WALLPAPER,
- filename: global.datadir + '/theme/noise-texture.png',
- effects: Meta.BackgroundEffects.NONE,
- onFinished: Lang.bind(this, function(content) {
- this.actor.content = content;
- this.emit('loaded');
- })
- });
-
- this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+ return this._backgrounds[monitorIndex];
},
- _onDestroy: function() {
- let content = this.actor.content;
+ destroy: function() {
+ for (let monitorIndex in this._backgrounds)
+ this._backgrounds[monitorIndex].destroy();
- if (content)
- this._cache.removeImageContent(content);
- },
+ this._backgrounds = null;
+ }
});
-Signals.addSignalMethods(SystemBackground.prototype);
const Animation = new Lang.Class({
Name: 'Animation',
@@ -731,100 +590,121 @@ const BackgroundManager = new Lang.Class({
params = Params.parse(params, { container: null,
layoutManager: Main.layoutManager,
monitorIndex: null,
- effects: Meta.BackgroundEffects.NONE,
+ vignette: false,
controlPosition: true,
settingsSchema: BACKGROUND_SCHEMA });
- // Allow override the background image setting for performance testing
- this._overrideImage = GLib.getenv('SHELL_BACKGROUND_IMAGE');
- this._settings = new Gio.Settings({ schema_id: params.settingsSchema });
+ let cache = getBackgroundCache();
+ this._settingsSchema = params.settingsSchema;
+ this._backgroundSource = cache.getBackgroundSource(params.layoutManager, params.settingsSchema);
+
this._container = params.container;
this._layoutManager = params.layoutManager;
- this._effects = params.effects;
+ this._vignette = params.vignette;
this._monitorIndex = params.monitorIndex;
this._controlPosition = params.controlPosition;
- this.background = this._createBackground();
- this._newBackground = null;
+ this.backgroundActor = this._createBackgroundActor();
+ this._newBackgroundActor = null;
},
destroy: function() {
- if (this._newBackground) {
- this._newBackground.actor.destroy();
- this._newBackground = null;
+ let cache = getBackgroundCache();
+ cache.releaseBackgroundSource(this._settingsSchema);
+ this._backgroundSource = null;
+
+ if (this._newBackgroundActor) {
+ this._newBackgroundActor.destroy();
+ this._newBackgroundActor = null;
}
- if (this.background) {
- this.background.actor.destroy();
- this.background = null;
+ if (this.backgroundActor) {
+ this.backgroundActor.destroy();
+ this.backgroundActor = null;
}
},
- _updateBackground: function() {
- let newBackground = this._createBackground();
- newBackground.vignetteSharpness = this.background.vignetteSharpness;
- newBackground.brightness = this.background.brightness;
- newBackground.visible = this.background.visible;
-
- newBackground.loadedSignalId = newBackground.connect('loaded',
- Lang.bind(this, function() {
- newBackground.disconnect(newBackground.loadedSignalId);
- newBackground.loadedSignalId = 0;
-
- if (this._newBackground != newBackground) {
- /* Not interesting, we queued another load */
- newBackground.actor.destroy();
- return;
- }
-
- Tweener.addTween(this.background.actor,
- { opacity: 0,
- time: FADE_ANIMATION_TIME,
- transition: 'easeOutQuad',
- onComplete: Lang.bind(this, function() {
- this.background.actor.destroy();
- this.background = newBackground;
- this._newBackground = null;
-
- this.emit('changed');
- })
- });
- }));
+ _swapBackgroundActor: function() {
+ let oldBackgroundActor = this.backgroundActor;
+ this.backgroundActor = this._newBackgroundActor;
+ this._newBackgroundActor = null;
+ this.emit('changed');
- this._newBackground = newBackground;
+ Tweener.addTween(oldBackgroundActor,
+ { opacity: 0,
+ time: FADE_ANIMATION_TIME,
+ transition: 'easeOutQuad',
+ onComplete: function() {
+ oldBackgroundActor.destroy();
+ }
+ });
},
- _createBackground: function() {
- let background = new Background({ monitorIndex: this._monitorIndex,
- layoutManager: this._layoutManager,
- effects: this._effects,
- settings: this._settings,
- overrideImage: this._overrideImage });
- this._container.add_child(background.actor);
+ _updateBackgroundActor: function() {
+ if (this._newBackgroundActor) {
+ /* Skip displaying existing background queued for load */
+ this._newBackgroundActor.destroy();
+ this._newBackgroundActor = null;
+ }
+
+ let newBackgroundActor = this._createBackgroundActor();
+ newBackgroundActor.vignette_sharpness = this.backgroundActor.vignette_sharpness;
+ newBackgroundActor.brightness = this.backgroundActor.brightness;
+ newBackgroundActor.visible = this.backgroundActor.visible;
+
+ this._newBackgroundActor = newBackgroundActor;
+
+ let background = newBackgroundActor.background._delegate;
+
+ if (background.isLoaded) {
+ this._swapBackgroundActor();
+ } else {
+ newBackgroundActor.loadedSignalId = background.connect('loaded',
+ Lang.bind(this, function() {
+ background.disconnect(newBackgroundActor.loadedSignalId);
+ newBackgroundActor.loadedSignalId = 0;
+
+ this._swapBackgroundActor();
+
+ }));
+ }
+ },
+
+ _createBackgroundActor: function() {
+ let background = this._backgroundSource.getBackground(this._monitorIndex);
+ let backgroundActor = new Meta.BackgroundActor({ meta_screen: global.screen,
+ monitor: this._monitorIndex,
+ background: background.background,
+ vignette: this._vignette,
+ vignette_sharpness: 0.5,
+ brightness: 0.5,
+ });
+
+ this._container.add_child(backgroundActor);
let monitor = this._layoutManager.monitors[this._monitorIndex];
- background.actor.set_size(monitor.width, monitor.height);
+ backgroundActor.set_size(monitor.width, monitor.height);
if (this._controlPosition) {
- background.actor.set_position(monitor.x, monitor.y);
- background.actor.lower_bottom();
+ backgroundActor.set_position(monitor.x, monitor.y);
+ backgroundActor.lower_bottom();
}
- background.changeSignalId = background.connect('changed', Lang.bind(this, function() {
- background.disconnect(background.changeSignalId);
- background.changeSignalId = 0;
- this._updateBackground();
+ let changeSignalId = background.connect('changed', Lang.bind(this, function() {
+ background.disconnect(changeSignalId);
+ changeSignalId = null;
+ this._updateBackgroundActor();
}));
- background.actor.connect('destroy', Lang.bind(this, function() {
- if (background.changeSignalId)
- background.disconnect(background.changeSignalId);
+ backgroundActor.connect('destroy', Lang.bind(this, function() {
+ if (changeSignalId)
+ background.disconnect(changeSignalId);
- if (background.loadedSignalId)
- background.disconnect(background.loadedSignalId);
+ if (backgroundActor.loadedSignalId)
+ backgroundActor.background._delegate.disconnect(backgroundActor.loadedSignalId);
}));
- return background;
+ return backgroundActor;
},
});
Signals.addSignalMethods(BackgroundManager.prototype);
diff --git a/js/ui/layout.js b/js/ui/layout.js
index 8096c04bb..5019036df 100644
--- a/js/ui/layout.js
+++ b/js/ui/layout.js
@@ -361,7 +361,7 @@ const LayoutManager = new Lang.Class({
},
_addBackgroundMenu: function(bgManager) {
- BackgroundMenu.addBackgroundMenu(bgManager.background.actor, this);
+ BackgroundMenu.addBackgroundMenu(bgManager.backgroundActor, this);
},
_createBackgroundManager: function(monitorIndex) {
@@ -378,10 +378,10 @@ const LayoutManager = new Lang.Class({
_showSecondaryBackgrounds: function() {
for (let i = 0; i < this.monitors.length; i++) {
if (i != this.primaryIndex) {
- let background = this._bgManagers[i].background;
- background.actor.show();
- background.actor.opacity = 0;
- Tweener.addTween(background.actor,
+ let backgroundActor = this._bgManagers[i].backgroundActor;
+ backgroundActor.show();
+ backgroundActor.opacity = 0;
+ Tweener.addTween(backgroundActor,
{ opacity: 255,
time: BACKGROUND_FADE_ANIMATION_TIME,
transition: 'easeOutQuad' });
@@ -404,7 +404,7 @@ const LayoutManager = new Lang.Class({
this._bgManagers.push(bgManager);
if (i != this.primaryIndex && this._startingUp)
- bgManager.background.actor.hide();
+ bgManager.backgroundActor.hide();
}
},
diff --git a/js/ui/overview.js b/js/ui/overview.js
index 84c070c60..3be62bdef 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -185,7 +185,7 @@ const Overview = new Lang.Class({
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
monitorIndex: i,
- effects: Meta.BackgroundEffects.VIGNETTE });
+ vignette: true });
this._bgManagers.push(bgManager);
}
},
@@ -193,11 +193,9 @@ const Overview = new Lang.Class({
_unshadeBackgrounds: function() {
let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) {
- let background = backgrounds[i]._delegate;
-
- Tweener.addTween(background,
+ Tweener.addTween(backgrounds[i],
{ brightness: 1.0,
- vignetteSharpness: 0.0,
+ vignette_sharpness: 0.0,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
@@ -207,11 +205,9 @@ const Overview = new Lang.Class({
_shadeBackgrounds: function() {
let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) {
- let background = backgrounds[i]._delegate;
-
- Tweener.addTween(background,
+ Tweener.addTween(backgrounds[i],
{ brightness: Lightbox.VIGNETTE_BRIGHTNESS,
- vignetteSharpness: Lightbox.VIGNETTE_SHARPNESS,
+ vignette_sharpness: Lightbox.VIGNETTE_SHARPNESS,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
index 0455a9dd6..8cd8affc4 100644
--- a/js/ui/workspaceThumbnail.js
+++ b/js/ui/workspaceThumbnail.js
@@ -306,7 +306,7 @@ const WorkspaceThumbnail = new Lang.Class({
_createBackground: function() {
this._bgManager = new Background.BackgroundManager({ monitorIndex: Main.layoutManager.primaryIndex,
container: this._contents,
- effects: Meta.BackgroundEffects.NONE });
+ vignette: false });
},
setPorthole: function(x, y, width, height) {
@@ -332,7 +332,7 @@ const WorkspaceThumbnail = new Lang.Class({
let clone = this._windows[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
- clone.setStackAbove(this._bgManager.background.actor);
+ clone.setStackAbove(this._bgManager.backgroundActor);
} else {
let previousClone = this._windows[i - 1];
clone.setStackAbove(previousClone.actor);
@@ -531,7 +531,7 @@ const WorkspaceThumbnail = new Lang.Class({
this._contents.add_actor(clone.actor);
if (this._windows.length == 0)
- clone.setStackAbove(this._bgManager.background.actor);
+ clone.setStackAbove(this._bgManager.backgroundActor);
else
clone.setStackAbove(this._windows[this._windows.length - 1].actor);