d5e647a191
Previously, we would create one StBin per monitor, but each was positioned at 0,0 and sized as the screen, so they would overlap and draw the box shadows on top of the other backgrounds. Instead, we need to size appropriately the bin, and then we need to position the actual MetaBacgroundActor at 0,0, so add a flag to BackgroundManager for this. Also, get rid of MetaBackgroundGroup, they do nothing because the screenshield is not a descendant of the MetaWindowGroup and because the widget in between blocks the propagation of the visible region. At the same time, use a widget, not a bin, because StBin requires you to set .child, not call add_child(). https://bugzilla.gnome.org/show_bug.cgi?id=694394
723 lines
26 KiB
JavaScript
723 lines
26 KiB
JavaScript
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
const GDesktopEnums = imports.gi.GDesktopEnums;
|
|
const Gio = imports.gi.Gio;
|
|
const GLib = imports.gi.GLib;
|
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
|
const Lang = imports.lang;
|
|
const Meta = imports.gi.Meta;
|
|
const Signals = imports.signals;
|
|
|
|
const Main = imports.ui.main;
|
|
const Params = imports.misc.params;
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
const BACKGROUND_SCHEMA = 'org.gnome.desktop.background';
|
|
const PRIMARY_COLOR_KEY = 'primary-color';
|
|
const SECONDARY_COLOR_KEY = 'secondary-color';
|
|
const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
|
|
const BACKGROUND_STYLE_KEY = 'picture-options';
|
|
const PICTURE_OPACITY_KEY = 'picture-opacity';
|
|
const PICTURE_URI_KEY = 'picture-uri';
|
|
|
|
const FADE_ANIMATION_TIME = 1.0;
|
|
|
|
// These parameters affect how often we redraw.
|
|
// The first is how different (percent crossfaded) the slide show
|
|
// has to look before redrawing and the second is the minimum
|
|
// frequency (in seconds) we're willing to wake up
|
|
const ANIMATION_OPACITY_STEP_INCREMENT = 4.0;
|
|
const ANIMATION_MIN_WAKEUP_INTERVAL = 1.0;
|
|
|
|
let _backgroundCache = null;
|
|
|
|
const BackgroundCache = new Lang.Class({
|
|
Name: 'BackgroundCache',
|
|
|
|
_init: function() {
|
|
this._patterns = [];
|
|
this._images = [];
|
|
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])
|
|
continue;
|
|
|
|
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;
|
|
},
|
|
|
|
_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);
|
|
}));
|
|
|
|
this._fileMonitors[filename] = monitor;
|
|
},
|
|
|
|
_removeContent: function(contentList, content) {
|
|
let index = contentList.indexOf(content);
|
|
|
|
if (index >= 0)
|
|
contentList.splice(index, 1);
|
|
},
|
|
|
|
removePatternContent: function(content) {
|
|
this._removeContent(this._patterns, content);
|
|
},
|
|
|
|
removeImageContent: function(content) {
|
|
this._removeContent(this._images, content);
|
|
},
|
|
|
|
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])
|
|
continue;
|
|
|
|
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_index != this._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;
|
|
|
|
if (params.onFinished)
|
|
params.onFinished(content);
|
|
} else {
|
|
content = new Meta.Background({ meta_screen: global.screen,
|
|
monitor: params.monitorIndex,
|
|
effects: params.effects });
|
|
|
|
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);
|
|
this._images.push(content);
|
|
} catch(e) {
|
|
content = null;
|
|
}
|
|
|
|
if (params.onFinished)
|
|
params.onFinished(content);
|
|
}));
|
|
}
|
|
},
|
|
|
|
getAnimation: function(params) {
|
|
params = Params.parse(params, { filename: null,
|
|
onLoaded: null });
|
|
|
|
if (this._animationFilename == params.filename) {
|
|
if (params.onLoaded) {
|
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
|
params.onLoaded(this._animation);
|
|
}));
|
|
}
|
|
}
|
|
|
|
let animation = new Animation({ filename: params.filename });
|
|
|
|
animation.load(Lang.bind(this, function() {
|
|
this._monitorFile(params.filename);
|
|
this._animationFilename = params.filename;
|
|
this._animation = animation;
|
|
|
|
if (params.onLoaded) {
|
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
|
params.onLoaded(this._animation);
|
|
}));
|
|
}
|
|
}));
|
|
}
|
|
});
|
|
Signals.addSignalMethods(BackgroundCache.prototype);
|
|
|
|
function getBackgroundCache() {
|
|
if (!_backgroundCache)
|
|
_backgroundCache = new BackgroundCache();
|
|
return _backgroundCache;
|
|
}
|
|
|
|
const Background = new Lang.Class({
|
|
Name: 'Background',
|
|
|
|
_init: function(params) {
|
|
params = Params.parse(params, { monitorIndex: 0,
|
|
layoutManager: Main.layoutManager,
|
|
effects: Meta.BackgroundEffects.NONE });
|
|
this.actor = new Meta.BackgroundGroup();
|
|
this.actor._delegate = this;
|
|
|
|
this._destroySignalId = this.actor.connect('destroy',
|
|
Lang.bind(this, this._destroy));
|
|
|
|
this._settings = new Gio.Settings({ schema: BACKGROUND_SCHEMA });
|
|
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._saturation = 1.0;
|
|
this._cancellable = new Gio.Cancellable();
|
|
this.isLoaded = false;
|
|
|
|
this._settings.connect('changed', Lang.bind(this, function() {
|
|
this.emit('changed');
|
|
}));
|
|
|
|
this._load();
|
|
},
|
|
|
|
_destroy: function() {
|
|
this._cancellable.cancel();
|
|
|
|
if (this._animationUpdateTimeoutId) {
|
|
GLib.source_remove (this._animationUpdateTimeoutId);
|
|
this._animationUpdateTimeoutId = 0
|
|
}
|
|
|
|
let i;
|
|
let keys = Object.keys(this._fileWatches);
|
|
for (i = 0; i < keys.length; i++) {
|
|
this._cache.disconnect(this._fileWatches[keys[i]]);
|
|
}
|
|
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;
|
|
},
|
|
|
|
_setLoaded: function() {
|
|
if (this.isLoaded)
|
|
return;
|
|
|
|
this.isLoaded = true;
|
|
|
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
|
this.emit('loaded');
|
|
return false;
|
|
}));
|
|
},
|
|
|
|
_loadPattern: function() {
|
|
let colorString, res, color, secondColor;
|
|
|
|
colorString = this._settings.get_string(PRIMARY_COLOR_KEY);
|
|
[res, color] = Clutter.Color.from_string(colorString);
|
|
colorString = this._settings.get_string(SECONDARY_COLOR_KEY);
|
|
[res, secondColor] = Clutter.Color.from_string(colorString);
|
|
|
|
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;
|
|
},
|
|
|
|
_watchCacheFile: function(filename) {
|
|
if (this._fileWatches[filename])
|
|
return;
|
|
|
|
let signalId = this._cache.connect('file-changed',
|
|
Lang.bind(this, function(cache, changedFile) {
|
|
if (changedFile == filename) {
|
|
this.emit('changed');
|
|
}
|
|
}));
|
|
this._fileWatches[filename] = signalId;
|
|
},
|
|
|
|
_addImage: function(content, index, filename) {
|
|
content.saturation = this._saturation;
|
|
content.brightness = this._brightness;
|
|
content.vignette_sharpness = this._vignetteSharpness;
|
|
|
|
let actor = new Meta.BackgroundActor();
|
|
actor.content = content;
|
|
this.actor.add_child(actor);
|
|
|
|
this._images[index] = actor;
|
|
this._watchCacheFile(filename);
|
|
},
|
|
|
|
_updateImage: function(content, index, filename) {
|
|
content.saturation = this._saturation;
|
|
content.brightness = this._brightness;
|
|
content.vignette_sharpness = this._vignetteSharpness;
|
|
|
|
this._images[index].content = content;
|
|
this._watchCacheFile(filename);
|
|
},
|
|
|
|
_updateAnimationProgress: function() {
|
|
if (this._images[1]) {
|
|
this._images[1].raise_top();
|
|
this._images[1].opacity = this._animation.transitionProgress * 255;
|
|
}
|
|
|
|
this._queueAnimationUpdate();
|
|
},
|
|
|
|
_updateAnimation: function() {
|
|
this._animationUpdateTimeoutId = 0;
|
|
|
|
let files = this._animation.getKeyFrameFiles(this._layoutManager.monitors[this._monitorIndex]);
|
|
|
|
if (!files) {
|
|
this._setLoaded();
|
|
this._queueAnimationUpdate();
|
|
return;
|
|
}
|
|
|
|
let numPendingImages = files.length;
|
|
for (let i = 0; i < files.length; i++) {
|
|
if (this._images[i] && this._images[i].content &&
|
|
this._images[i].content.get_filename() == files[i]) {
|
|
|
|
numPendingImages--;
|
|
if (numPendingImages == 0)
|
|
this._updateAnimationProgress();
|
|
continue;
|
|
}
|
|
this._cache.getImageContent({ monitorIndex: this._monitorIndex,
|
|
effects: this._effects,
|
|
style: this._style,
|
|
filename: files[i],
|
|
cancellable: this._cancellable,
|
|
onFinished: Lang.bind(this, function(content) {
|
|
numPendingImages--;
|
|
|
|
if (!content) {
|
|
this._setLoaded();
|
|
if (numPendingImages == 0)
|
|
this._updateAnimationProgress();
|
|
return;
|
|
}
|
|
|
|
if (!this._images[i]) {
|
|
this._addImage(content, i, files[i]);
|
|
} else {
|
|
this._updateImage(content, i, files[i]);
|
|
}
|
|
|
|
if (numPendingImages == 0) {
|
|
this._setLoaded();
|
|
this._updateAnimationProgress();
|
|
}
|
|
})
|
|
});
|
|
}
|
|
},
|
|
|
|
_queueAnimationUpdate: function() {
|
|
if (this._animationUpdateTimeoutId != 0)
|
|
return;
|
|
|
|
if (!this._cancellable || this._cancellable.is_cancelled())
|
|
return;
|
|
|
|
if (!this._animation.duration)
|
|
return;
|
|
|
|
let interval = Math.max(ANIMATION_MIN_WAKEUP_INTERVAL * 1000,
|
|
ANIMATION_OPACITY_STEP_INCREMENT / this._animation.duration);
|
|
this._animationUpdateTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
|
interval,
|
|
Lang.bind(this, function() {
|
|
this._animationUpdateTimeoutId = 0;
|
|
this._updateAnimation();
|
|
return false;
|
|
}));
|
|
},
|
|
|
|
_loadAnimation: function(filename) {
|
|
this._cache.getAnimation({ filename: filename,
|
|
onLoaded: Lang.bind(this, function(animation) {
|
|
this._animation = animation;
|
|
|
|
if (!this._animation || this._cancellable.is_cancelled()) {
|
|
this._setLoaded();
|
|
return;
|
|
}
|
|
|
|
this._updateAnimation();
|
|
this._watchCacheFile(filename);
|
|
})
|
|
});
|
|
},
|
|
|
|
_loadFile: 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) {
|
|
if (!this._cancellable.is_cancelled())
|
|
this._loadAnimation(filename);
|
|
return;
|
|
}
|
|
|
|
this._addImage(content, 0, filename);
|
|
this._setLoaded();
|
|
})
|
|
});
|
|
|
|
},
|
|
|
|
_load: function () {
|
|
this._cache = getBackgroundCache();
|
|
|
|
this._loadPattern(this._cache);
|
|
|
|
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);
|
|
let filename = Gio.File.new_for_uri(uri).get_path();
|
|
|
|
this._loadFile(filename);
|
|
},
|
|
|
|
get saturation() {
|
|
return this._saturation;
|
|
},
|
|
|
|
set saturation(saturation) {
|
|
this._saturation = saturation;
|
|
|
|
if (this._pattern && this._pattern.content)
|
|
this._pattern.content.saturation = saturation;
|
|
|
|
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.saturation = saturation;
|
|
}
|
|
},
|
|
|
|
get brightness() {
|
|
return this._brightness;
|
|
},
|
|
|
|
set brightness(factor) {
|
|
this._brightness = factor;
|
|
if (this._pattern && this._pattern.content)
|
|
this._pattern.content.brightness = factor;
|
|
|
|
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;
|
|
}
|
|
},
|
|
|
|
get vignetteSharpness() {
|
|
return this._vignetteSharpness;
|
|
},
|
|
|
|
set vignetteSharpness(sharpness) {
|
|
this._vignetteSharpness = sharpness;
|
|
if (this._pattern && this._pattern.content)
|
|
this._pattern.content.vignette_sharpness = sharpness;
|
|
|
|
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;
|
|
}
|
|
}
|
|
});
|
|
Signals.addSignalMethods(Background.prototype);
|
|
|
|
const StillFrame = new Lang.Class({
|
|
Name: 'StillFrame',
|
|
|
|
_init: function(monitorIndex) {
|
|
this.actor = new Meta.BackgroundActor();
|
|
this.actor._delegate = this;
|
|
|
|
let content = new Meta.Background({ meta_screen: global.screen,
|
|
monitor: monitorIndex,
|
|
effects: Meta.BackgroundEffects.NONE });
|
|
content.load_still_frame();
|
|
|
|
this.actor.content = content;
|
|
}
|
|
});
|
|
Signals.addSignalMethods(StillFrame.prototype);
|
|
|
|
const Animation = new Lang.Class({
|
|
Name: 'Animation',
|
|
|
|
_init: function(params) {
|
|
params = Params.parse(params, { filename: null });
|
|
|
|
this.filename = params.filename;
|
|
this._keyFrames = [];
|
|
this.duration = 0.0;
|
|
this.transitionProgress = 0.0;
|
|
this.loaded = false;
|
|
},
|
|
|
|
load: function(callback) {
|
|
let file = Gio.File.new_for_path(this.filename);
|
|
|
|
this._show = new GnomeDesktop.BGSlideShow({ filename: this.filename });
|
|
|
|
this._show.load_async(null,
|
|
Lang.bind(this,
|
|
function(object, result) {
|
|
this.duration = this._show.get_total_duration();
|
|
this.loaded = true;
|
|
if (callback)
|
|
callback();
|
|
}));
|
|
},
|
|
|
|
getKeyFrameFiles: function(monitor) {
|
|
if (!this._show)
|
|
return null;
|
|
|
|
if (this._show.get_num_slides() < 1)
|
|
return null;
|
|
|
|
let [progress, duration, isFixed, file1, file2] = this._show.get_current_slide(monitor.width, monitor.height);
|
|
|
|
this.transitionProgress = progress;
|
|
|
|
let files = [];
|
|
|
|
if (file1)
|
|
files.push(file1);
|
|
|
|
if (file2)
|
|
files.push(file2);
|
|
|
|
return files;
|
|
},
|
|
});
|
|
Signals.addSignalMethods(Animation.prototype);
|
|
|
|
const BackgroundManager = new Lang.Class({
|
|
Name: 'BackgroundManager',
|
|
|
|
_init: function(params) {
|
|
params = Params.parse(params, { container: null,
|
|
layoutManager: Main.layoutManager,
|
|
monitorIndex: null,
|
|
effects: Meta.BackgroundEffects.NONE,
|
|
controlPosition: true });
|
|
|
|
this._container = params.container;
|
|
this._layoutManager = params.layoutManager;
|
|
this._effects = params.effects;
|
|
this._monitorIndex = params.monitorIndex;
|
|
this._controlPosition = params.controlPosition;
|
|
|
|
this.background = this._createBackground();
|
|
this._newBackground = null;
|
|
this._loadedSignalId = 0;
|
|
this._changedSignalId = 0;
|
|
},
|
|
|
|
destroy: function() {
|
|
if (this._loadedSignalId)
|
|
this._newBackground.disconnect(this._loadedSignalId);
|
|
|
|
if (this._changedSignalId)
|
|
this.background.disconnect(this._changedSignalId);
|
|
|
|
if (this._newBackground) {
|
|
this._newBackground.actor.destroy();
|
|
this._newBackground = null;
|
|
}
|
|
|
|
if (this.background) {
|
|
this.background.actor.destroy();
|
|
this.background = null;
|
|
}
|
|
},
|
|
|
|
_updateBackground: function(background, monitorIndex) {
|
|
let newBackground = this._createBackground(monitorIndex);
|
|
newBackground.vignetteSharpness = background.vignetteSharpness;
|
|
newBackground.brightness = background.brightness;
|
|
newBackground.saturation = background.saturation;
|
|
newBackground.visible = background.visible;
|
|
|
|
let signalId = newBackground.connect('loaded',
|
|
Lang.bind(this, function() {
|
|
newBackground.disconnect(signalId);
|
|
Tweener.addTween(background.actor,
|
|
{ opacity: 0,
|
|
time: FADE_ANIMATION_TIME,
|
|
transition: 'easeOutQuad',
|
|
onComplete: Lang.bind(this, function() {
|
|
this.background = newBackground;
|
|
this._newBackground = null;
|
|
background.actor.destroy();
|
|
this.emit('changed');
|
|
})
|
|
});
|
|
}));
|
|
this._loadedSignalId = signalId;
|
|
|
|
this._newBackground = newBackground;
|
|
},
|
|
|
|
_createBackground: function() {
|
|
let background = new Background({ monitorIndex: this._monitorIndex,
|
|
layoutManager: this._layoutManager,
|
|
effects: this._effects });
|
|
this._container.add_child(background.actor);
|
|
|
|
let monitor = this._layoutManager.monitors[this._monitorIndex];
|
|
|
|
background.actor.set_size(monitor.width, monitor.height);
|
|
if (this._controlPosition) {
|
|
background.actor.set_position(monitor.x, monitor.y);
|
|
background.actor.lower_bottom();
|
|
}
|
|
|
|
let signalId = background.connect('changed', Lang.bind(this, function() {
|
|
background.disconnect(signalId);
|
|
this._updateBackground(background, this._monitorIndex);
|
|
}));
|
|
|
|
this._changedSignalId = signalId;
|
|
|
|
return background;
|
|
},
|
|
});
|
|
Signals.addSignalMethods(BackgroundManager.prototype);
|