2012-12-24 14:20:39 +00:00
|
|
|
// -*- 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;
|
2013-02-04 21:50:36 +00:00
|
|
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
2012-12-24 14:20:39 +00:00
|
|
|
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;
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
// 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;
|
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
let _backgroundCache = null;
|
|
|
|
|
|
|
|
const BackgroundCache = new Lang.Class({
|
|
|
|
Name: 'BackgroundCache',
|
|
|
|
|
|
|
|
_init: function() {
|
|
|
|
this._patterns = [];
|
|
|
|
this._images = [];
|
2013-03-25 19:03:48 +00:00
|
|
|
this._pendingFileLoads = [];
|
2012-12-24 14:20:39 +00:00
|
|
|
this._fileMonitors = {};
|
|
|
|
},
|
|
|
|
|
|
|
|
getPatternContent: function(params) {
|
|
|
|
params = Params.parse(params, { monitorIndex: 0,
|
|
|
|
color: null,
|
|
|
|
secondColor: null,
|
|
|
|
shadingType: null,
|
|
|
|
effects: Meta.BackgroundEffects.NONE });
|
|
|
|
|
|
|
|
let content = null;
|
2013-12-03 20:45:53 +00:00
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-22 19:01:29 +00:00
|
|
|
this._patterns.push(content);
|
2012-12-24 14:20:39 +00:00
|
|
|
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);
|
2013-12-03 22:54:02 +00:00
|
|
|
if (index < 0)
|
|
|
|
throw new Error("Trying to remove invalid content: " + content);
|
|
|
|
contentList.splice(index, 1);
|
2012-12-24 14:20:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
removePatternContent: function(content) {
|
|
|
|
this._removeContent(this._patterns, content);
|
|
|
|
},
|
|
|
|
|
|
|
|
removeImageContent: function(content) {
|
2013-04-04 20:36:56 +00:00
|
|
|
let filename = content.get_filename();
|
|
|
|
|
2013-12-12 19:42:41 +00:00
|
|
|
let hasOtherUsers = this._images.some(function(content) { return filename == content.get_filename(); });
|
|
|
|
if (!hasOtherUsers)
|
2013-04-04 20:36:56 +00:00
|
|
|
delete this._fileMonitors[filename];
|
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
this._removeContent(this._images, content);
|
|
|
|
},
|
|
|
|
|
background: Fix cancellable issues
If we have the following sequence:
cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
cancellable1.cancel();
Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.
To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.
Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.
https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-13 23:42:32 +00:00
|
|
|
_loadImageContentInternal: function(filename, style) {
|
|
|
|
let cancellable = new Gio.Cancellable();
|
|
|
|
let content = new Meta.Background({ meta_screen: global.screen });
|
|
|
|
|
|
|
|
let info = { filename: filename,
|
|
|
|
style: style,
|
|
|
|
cancellable: cancellable,
|
|
|
|
callers: [] };
|
|
|
|
|
|
|
|
content.load_file_async(filename, style, cancellable, Lang.bind(this, function(object, result) {
|
|
|
|
if (cancellable.is_cancelled())
|
|
|
|
return;
|
|
|
|
|
|
|
|
try {
|
|
|
|
content.load_file_finish(result);
|
|
|
|
} catch(e) {
|
|
|
|
content = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (content) {
|
|
|
|
this._monitorFile(filename);
|
|
|
|
info.callers.forEach(Lang.bind(this, function(caller) {
|
|
|
|
let newContent = content.copy(caller.monitorIndex, caller.effects);
|
|
|
|
this._images.push(newContent);
|
|
|
|
caller.onFinished(newContent);
|
|
|
|
}));
|
|
|
|
} else {
|
|
|
|
info.callers.forEach(Lang.bind(this, function(caller) {
|
|
|
|
caller.onFinished(null);
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
let idx = this._pendingFileLoads.indexOf(info);
|
|
|
|
this._pendingFileLoads.splice(idx, 1);
|
|
|
|
}));
|
|
|
|
|
|
|
|
this._pendingFileLoads.push(info);
|
|
|
|
return info;
|
|
|
|
},
|
|
|
|
|
2013-03-25 19:03:48 +00:00
|
|
|
_loadImageContent: function(params) {
|
|
|
|
params = Params.parse(params, { monitorIndex: 0,
|
|
|
|
style: null,
|
|
|
|
filename: null,
|
|
|
|
effects: Meta.BackgroundEffects.NONE,
|
|
|
|
cancellable: null,
|
|
|
|
onFinished: null });
|
|
|
|
|
background: Fix cancellable issues
If we have the following sequence:
cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
cancellable1.cancel();
Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.
To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.
Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.
https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-13 23:42:32 +00:00
|
|
|
let caller = { monitorIndex: params.monitorIndex,
|
|
|
|
effects: params.effects,
|
|
|
|
cancellable: params.cancellable,
|
|
|
|
onFinished: params.onFinished };
|
|
|
|
|
|
|
|
let info = null;
|
2013-08-15 19:51:46 +00:00
|
|
|
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
background: Fix cancellable issues
If we have the following sequence:
cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
cancellable1.cancel();
Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.
To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.
Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.
https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-13 23:42:32 +00:00
|
|
|
let pendingLoad = this._pendingFileLoads[i];
|
|
|
|
if (pendingLoad.filename == params.filename && pendingLoad.style == params.style) {
|
|
|
|
info = pendingLoad;
|
|
|
|
break;
|
2013-08-15 19:51:46 +00:00
|
|
|
}
|
2013-03-25 19:03:48 +00:00
|
|
|
}
|
|
|
|
|
background: Fix cancellable issues
If we have the following sequence:
cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
cancellable1.cancel();
Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.
To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.
Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.
https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-13 23:42:32 +00:00
|
|
|
if (!info)
|
|
|
|
info = this._loadImageContentInternal(params.filename, params.style);
|
2013-08-15 19:51:46 +00:00
|
|
|
|
background: Fix cancellable issues
If we have the following sequence:
cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
cancellable1.cancel();
Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.
To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.
Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.
https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-13 23:42:32 +00:00
|
|
|
info.callers.push(caller);
|
|
|
|
|
|
|
|
if (caller.cancellable) {
|
|
|
|
caller.cancellable.connect(Lang.bind(this, function() {
|
|
|
|
let idx = info.callers.indexOf(caller);
|
|
|
|
info.callers.splice(idx, 1);
|
|
|
|
|
|
|
|
if (info.callers.length == 0) {
|
|
|
|
info.cancellable.cancel();
|
2013-03-25 19:03:48 +00:00
|
|
|
|
background: Fix cancellable issues
If we have the following sequence:
cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
cancellable1.cancel();
Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.
To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.
Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.
https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-13 23:42:32 +00:00
|
|
|
let idx = this._pendingFileLoads.indexOf(info);
|
|
|
|
this._pendingFileLoads.splice(idx, 1);
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
2013-03-25 19:03:48 +00:00
|
|
|
},
|
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
getImageContent: function(params) {
|
|
|
|
params = Params.parse(params, { monitorIndex: 0,
|
|
|
|
style: null,
|
|
|
|
filename: null,
|
|
|
|
effects: Meta.BackgroundEffects.NONE,
|
|
|
|
cancellable: null,
|
|
|
|
onFinished: null });
|
|
|
|
|
|
|
|
let content = null;
|
2013-12-03 20:45:53 +00:00
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
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 &&
|
2013-12-03 20:41:42 +00:00
|
|
|
this._images[i].monitor != params.monitorIndex)
|
2012-12-24 14:20:39 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
candidateContent = this._images[i];
|
|
|
|
|
|
|
|
if (params.effects != this._images[i].effects)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (candidateContent) {
|
|
|
|
content = candidateContent.copy(params.monitorIndex, params.effects);
|
|
|
|
|
2013-02-20 00:55:56 +00:00
|
|
|
if (params.cancellable && params.cancellable.is_cancelled())
|
2013-02-20 02:07:44 +00:00
|
|
|
content = null;
|
2013-03-22 19:01:29 +00:00
|
|
|
else
|
|
|
|
this._images.push(content);
|
2013-02-20 00:55:56 +00:00
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
if (params.onFinished)
|
|
|
|
params.onFinished(content);
|
|
|
|
} else {
|
2013-03-25 19:03:48 +00:00
|
|
|
this._loadImageContent({ filename: params.filename,
|
|
|
|
style: params.style,
|
2013-03-27 16:00:47 +00:00
|
|
|
effects: params.effects,
|
2013-03-27 16:12:48 +00:00
|
|
|
monitorIndex: params.monitorIndex,
|
2013-03-25 19:03:48 +00:00
|
|
|
cancellable: params.cancellable,
|
|
|
|
onFinished: params.onFinished });
|
2012-12-24 14:20:39 +00:00
|
|
|
}
|
2013-02-04 21:50:36 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
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);
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2013-02-04 21:50:36 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2013-02-04 21:50:36 +00:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
}));
|
2012-12-24 14:20:39 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
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,
|
2013-02-04 21:50:36 +00:00
|
|
|
layoutManager: Main.layoutManager,
|
2013-08-19 22:48:56 +00:00
|
|
|
effects: Meta.BackgroundEffects.NONE,
|
|
|
|
settings: null });
|
2012-12-24 14:20:39 +00:00
|
|
|
this.actor = new Meta.BackgroundGroup();
|
|
|
|
this.actor._delegate = this;
|
|
|
|
|
|
|
|
this._destroySignalId = this.actor.connect('destroy',
|
|
|
|
Lang.bind(this, this._destroy));
|
|
|
|
|
2013-08-19 22:48:56 +00:00
|
|
|
this._settings = params.settings;
|
2012-12-24 14:20:39 +00:00
|
|
|
this._monitorIndex = params.monitorIndex;
|
2013-02-04 21:50:36 +00:00
|
|
|
this._layoutManager = params.layoutManager;
|
2012-12-24 14:20:39 +00:00
|
|
|
this._effects = params.effects;
|
|
|
|
this._fileWatches = {};
|
|
|
|
this._pattern = null;
|
2013-02-04 21:50:36 +00:00
|
|
|
// contains a single image for static backgrounds and
|
|
|
|
// two images (from and to) for slide shows
|
|
|
|
this._images = {};
|
2012-12-24 14:20:39 +00:00
|
|
|
|
|
|
|
this._brightness = 1.0;
|
|
|
|
this._vignetteSharpness = 0.2;
|
|
|
|
this._cancellable = new Gio.Cancellable();
|
|
|
|
this.isLoaded = false;
|
|
|
|
|
2013-10-02 13:29:30 +00:00
|
|
|
this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() {
|
|
|
|
this.emit('changed');
|
|
|
|
}));
|
2012-12-24 14:20:39 +00:00
|
|
|
|
|
|
|
this._load();
|
|
|
|
},
|
|
|
|
|
|
|
|
_destroy: function() {
|
|
|
|
this._cancellable.cancel();
|
|
|
|
|
2013-03-14 21:00:57 +00:00
|
|
|
if (this._updateAnimationTimeoutId) {
|
|
|
|
GLib.source_remove (this._updateAnimationTimeoutId);
|
|
|
|
this._updateAnimationTimeoutId = 0;
|
2013-02-04 21:50:36 +00:00
|
|
|
}
|
2012-12-24 14:20:39 +00:00
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
let i;
|
2012-12-24 14:20:39 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
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);
|
2012-12-24 14:20:39 +00:00
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
actor.destroy();
|
|
|
|
this._images[keys[i]] = null;
|
2012-12-24 14:20:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.actor.disconnect(this._destroySignalId);
|
|
|
|
this._destroySignalId = 0;
|
2013-10-02 13:29:30 +00:00
|
|
|
|
|
|
|
if (this._settingsChangedSignalId != 0)
|
|
|
|
this._settings.disconnect(this._settingsChangedSignalId);
|
|
|
|
this._settingsChangedSignalId = 0;
|
2012-12-24 14:20:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_setLoaded: function() {
|
|
|
|
if (this.isLoaded)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.isLoaded = true;
|
|
|
|
|
|
|
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
|
|
|
this.emit('loaded');
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2012-12-24 14:20:39 +00:00
|
|
|
}));
|
|
|
|
},
|
|
|
|
|
|
|
|
_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;
|
|
|
|
},
|
|
|
|
|
2013-12-03 22:25:57 +00:00
|
|
|
_ensureImage: function(index) {
|
|
|
|
if (this._images[index])
|
|
|
|
return;
|
2013-02-04 21:50:36 +00:00
|
|
|
|
|
|
|
let actor = new Meta.BackgroundActor();
|
2013-03-14 20:45:29 +00:00
|
|
|
|
|
|
|
// 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);
|
2013-02-04 21:50:36 +00:00
|
|
|
this._images[index] = actor;
|
|
|
|
},
|
|
|
|
|
2013-12-03 22:25:57 +00:00
|
|
|
_updateImage: function(index, content, filename) {
|
2012-12-24 14:20:39 +00:00
|
|
|
content.brightness = this._brightness;
|
|
|
|
content.vignette_sharpness = this._vignetteSharpness;
|
|
|
|
|
2013-12-03 22:25:57 +00:00
|
|
|
let image = this._images[index];
|
|
|
|
if (image.content)
|
|
|
|
this._cache.removeImageContent(content);
|
|
|
|
image.content = content;
|
2012-12-24 14:20:39 +00:00
|
|
|
this._watchCacheFile(filename);
|
|
|
|
},
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
_updateAnimationProgress: function() {
|
2013-03-05 20:39:29 +00:00
|
|
|
if (this._images[1])
|
2013-02-04 21:50:36 +00:00
|
|
|
this._images[1].opacity = this._animation.transitionProgress * 255;
|
|
|
|
|
2013-03-14 21:00:57 +00:00
|
|
|
this._queueUpdateAnimation();
|
2013-02-04 21:50:36 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_updateAnimation: function() {
|
2013-03-14 21:00:57 +00:00
|
|
|
this._updateAnimationTimeoutId = 0;
|
2013-02-04 21:50:36 +00:00
|
|
|
|
2013-03-14 21:03:25 +00:00
|
|
|
this._animation.update(this._layoutManager.monitors[this._monitorIndex]);
|
|
|
|
let files = this._animation.keyFrameFiles;
|
2013-02-04 21:50:36 +00:00
|
|
|
|
2013-03-14 21:06:17 +00:00
|
|
|
if (files.length == 0) {
|
2013-02-04 21:50:36 +00:00
|
|
|
this._setLoaded();
|
2013-03-14 21:00:57 +00:00
|
|
|
this._queueUpdateAnimation();
|
2013-02-04 21:50:36 +00:00
|
|
|
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,
|
2013-03-14 17:59:30 +00:00
|
|
|
onFinished: Lang.bind(this, function(content, i) {
|
2013-02-04 21:50:36 +00:00
|
|
|
numPendingImages--;
|
|
|
|
|
|
|
|
if (!content) {
|
|
|
|
this._setLoaded();
|
|
|
|
if (numPendingImages == 0)
|
|
|
|
this._updateAnimationProgress();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-12-03 22:25:57 +00:00
|
|
|
this._ensureImage(i);
|
|
|
|
this._updateImage(i, content, files[i]);
|
2013-02-04 21:50:36 +00:00
|
|
|
|
|
|
|
if (numPendingImages == 0) {
|
|
|
|
this._setLoaded();
|
|
|
|
this._updateAnimationProgress();
|
|
|
|
}
|
2013-03-14 17:59:30 +00:00
|
|
|
}, i)
|
2013-02-04 21:50:36 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2013-03-14 21:00:57 +00:00
|
|
|
_queueUpdateAnimation: function() {
|
|
|
|
if (this._updateAnimationTimeoutId != 0)
|
2013-02-04 21:50:36 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (!this._cancellable || this._cancellable.is_cancelled())
|
|
|
|
return;
|
|
|
|
|
2013-03-14 20:58:52 +00:00
|
|
|
if (!this._animation.transitionDuration)
|
2013-02-04 21:50:36 +00:00
|
|
|
return;
|
|
|
|
|
2013-03-14 20:58:20 +00:00
|
|
|
let nSteps = 255 / ANIMATION_OPACITY_STEP_INCREMENT;
|
2013-03-14 20:58:52 +00:00
|
|
|
let timePerStep = (this._animation.transitionDuration * 1000) / nSteps;
|
2013-03-14 20:58:20 +00:00
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
let interval = Math.max(ANIMATION_MIN_WAKEUP_INTERVAL * 1000,
|
2013-03-14 20:58:20 +00:00
|
|
|
timePerStep);
|
2013-03-25 14:42:21 +00:00
|
|
|
|
|
|
|
if (interval > GLib.MAXUINT32)
|
|
|
|
return;
|
|
|
|
|
2013-03-14 21:00:57 +00:00
|
|
|
this._updateAnimationTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
2013-02-04 21:50:36 +00:00
|
|
|
interval,
|
|
|
|
Lang.bind(this, function() {
|
2013-03-14 21:00:57 +00:00
|
|
|
this._updateAnimationTimeoutId = 0;
|
2013-02-04 21:50:36 +00:00
|
|
|
this._updateAnimation();
|
2013-11-29 00:45:39 +00:00
|
|
|
return GLib.SOURCE_REMOVE;
|
2013-02-04 21:50:36 +00:00
|
|
|
}));
|
|
|
|
},
|
|
|
|
|
|
|
|
_loadAnimation: function(filename) {
|
|
|
|
this._cache.getAnimation({ filename: filename,
|
|
|
|
onLoaded: Lang.bind(this, function(animation) {
|
|
|
|
this._animation = animation;
|
|
|
|
|
2013-02-20 00:55:56 +00:00
|
|
|
if (!this._animation || this._cancellable.is_cancelled()) {
|
2013-02-04 21:50:36 +00:00
|
|
|
this._setLoaded();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._updateAnimation();
|
|
|
|
this._watchCacheFile(filename);
|
|
|
|
})
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2013-12-03 20:56:12 +00:00
|
|
|
_loadImage: function(filename) {
|
2012-12-24 14:20:39 +00:00
|
|
|
this._cache.getImageContent({ monitorIndex: this._monitorIndex,
|
|
|
|
effects: this._effects,
|
|
|
|
style: this._style,
|
|
|
|
filename: filename,
|
|
|
|
cancellable: this._cancellable,
|
|
|
|
onFinished: Lang.bind(this, function(content) {
|
2013-12-03 22:25:57 +00:00
|
|
|
if (content) {
|
|
|
|
this._ensureImage(0);
|
|
|
|
this._updateImage(0, content, filename);
|
|
|
|
}
|
2012-12-24 14:20:39 +00:00
|
|
|
this._setLoaded();
|
|
|
|
})
|
|
|
|
});
|
2013-12-03 20:56:12 +00:00
|
|
|
},
|
2012-12-24 14:20:39 +00:00
|
|
|
|
2013-12-03 20:56:12 +00:00
|
|
|
_loadFile: function(filename) {
|
|
|
|
if (filename.endsWith('.xml'))
|
|
|
|
this._loadAnimation(filename);
|
|
|
|
else
|
|
|
|
this._loadImage(filename);
|
2012-12-24 14:20:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
_load: function () {
|
|
|
|
this._cache = getBackgroundCache();
|
|
|
|
|
2014-01-13 23:21:03 +00:00
|
|
|
this._loadPattern();
|
2012-12-24 14:20:39 +00:00
|
|
|
|
|
|
|
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);
|
2013-06-13 19:48:32 +00:00
|
|
|
let filename;
|
|
|
|
if (GLib.uri_parse_scheme(uri) != null)
|
|
|
|
filename = Gio.File.new_for_uri(uri).get_path();
|
|
|
|
else
|
|
|
|
filename = uri;
|
|
|
|
|
|
|
|
if (!filename) {
|
|
|
|
this._setLoaded();
|
|
|
|
return;
|
|
|
|
}
|
2012-12-24 14:20:39 +00:00
|
|
|
|
|
|
|
this._loadFile(filename);
|
|
|
|
},
|
|
|
|
|
|
|
|
get brightness() {
|
|
|
|
return this._brightness;
|
|
|
|
},
|
|
|
|
|
|
|
|
set brightness(factor) {
|
|
|
|
this._brightness = factor;
|
|
|
|
if (this._pattern && this._pattern.content)
|
|
|
|
this._pattern.content.brightness = factor;
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-12-24 14:20:39 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
get vignetteSharpness() {
|
|
|
|
return this._vignetteSharpness;
|
|
|
|
},
|
|
|
|
|
|
|
|
set vignetteSharpness(sharpness) {
|
|
|
|
this._vignetteSharpness = sharpness;
|
|
|
|
if (this._pattern && this._pattern.content)
|
|
|
|
this._pattern.content.vignette_sharpness = sharpness;
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-12-24 14:20:39 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
Signals.addSignalMethods(Background.prototype);
|
|
|
|
|
2013-02-21 19:32:23 +00:00
|
|
|
const SystemBackground = new Lang.Class({
|
|
|
|
Name: 'SystemBackground',
|
|
|
|
|
|
|
|
_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');
|
|
|
|
})
|
|
|
|
});
|
2013-12-03 22:05:06 +00:00
|
|
|
|
|
|
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
|
|
|
},
|
|
|
|
|
|
|
|
_onDestroy: function() {
|
|
|
|
this._cache.removeImageContent(this.actor.content);
|
|
|
|
},
|
2013-02-21 19:32:23 +00:00
|
|
|
});
|
|
|
|
Signals.addSignalMethods(SystemBackground.prototype);
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
const Animation = new Lang.Class({
|
|
|
|
Name: 'Animation',
|
|
|
|
|
|
|
|
_init: function(params) {
|
|
|
|
params = Params.parse(params, { filename: null });
|
|
|
|
|
|
|
|
this.filename = params.filename;
|
2013-03-14 21:03:25 +00:00
|
|
|
this.keyFrameFiles = [];
|
2013-02-04 21:50:36 +00:00
|
|
|
this.transitionProgress = 0.0;
|
2013-03-14 20:58:52 +00:00
|
|
|
this.transitionDuration = 0.0;
|
2013-02-04 21:50:36 +00:00
|
|
|
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.loaded = true;
|
|
|
|
if (callback)
|
|
|
|
callback();
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
|
2013-03-14 21:03:25 +00:00
|
|
|
update: function(monitor) {
|
|
|
|
this.keyFrameFiles = [];
|
|
|
|
|
2013-02-04 21:50:36 +00:00
|
|
|
if (!this._show)
|
2013-03-14 21:03:25 +00:00
|
|
|
return;
|
2013-02-04 21:50:36 +00:00
|
|
|
|
|
|
|
if (this._show.get_num_slides() < 1)
|
2013-03-14 21:03:25 +00:00
|
|
|
return;
|
2013-02-04 21:50:36 +00:00
|
|
|
|
|
|
|
let [progress, duration, isFixed, file1, file2] = this._show.get_current_slide(monitor.width, monitor.height);
|
|
|
|
|
2013-03-14 20:58:52 +00:00
|
|
|
this.transitionDuration = duration;
|
2013-02-04 21:50:36 +00:00
|
|
|
this.transitionProgress = progress;
|
|
|
|
|
|
|
|
if (file1)
|
2013-03-14 21:03:25 +00:00
|
|
|
this.keyFrameFiles.push(file1);
|
2013-02-04 21:50:36 +00:00
|
|
|
|
|
|
|
if (file2)
|
2013-03-14 21:03:25 +00:00
|
|
|
this.keyFrameFiles.push(file2);
|
2013-02-04 21:50:36 +00:00
|
|
|
},
|
|
|
|
});
|
|
|
|
Signals.addSignalMethods(Animation.prototype);
|
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
const BackgroundManager = new Lang.Class({
|
|
|
|
Name: 'BackgroundManager',
|
|
|
|
|
|
|
|
_init: function(params) {
|
|
|
|
params = Params.parse(params, { container: null,
|
|
|
|
layoutManager: Main.layoutManager,
|
|
|
|
monitorIndex: null,
|
ScreenShield: fix positioning of background with multimonitor
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
2013-02-21 22:32:25 +00:00
|
|
|
effects: Meta.BackgroundEffects.NONE,
|
2013-08-19 22:48:56 +00:00
|
|
|
controlPosition: true,
|
|
|
|
settingsSchema: BACKGROUND_SCHEMA });
|
2012-12-24 14:20:39 +00:00
|
|
|
|
2013-08-19 22:48:56 +00:00
|
|
|
this._settings = new Gio.Settings({ schema: params.settingsSchema });
|
2012-12-24 14:20:39 +00:00
|
|
|
this._container = params.container;
|
|
|
|
this._layoutManager = params.layoutManager;
|
|
|
|
this._effects = params.effects;
|
|
|
|
this._monitorIndex = params.monitorIndex;
|
ScreenShield: fix positioning of background with multimonitor
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
2013-02-21 22:32:25 +00:00
|
|
|
this._controlPosition = params.controlPosition;
|
2012-12-24 14:20:39 +00:00
|
|
|
|
|
|
|
this.background = this._createBackground();
|
|
|
|
this._newBackground = null;
|
|
|
|
},
|
|
|
|
|
|
|
|
destroy: function() {
|
|
|
|
if (this._newBackground) {
|
2013-02-20 02:50:40 +00:00
|
|
|
this._newBackground.actor.destroy();
|
2012-12-24 14:20:39 +00:00
|
|
|
this._newBackground = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.background) {
|
2013-02-20 02:50:40 +00:00
|
|
|
this.background.actor.destroy();
|
2012-12-24 14:20:39 +00:00
|
|
|
this.background = null;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-01-13 22:12:16 +00:00
|
|
|
_updateBackground: function() {
|
2013-12-03 22:27:28 +00:00
|
|
|
let newBackground = this._createBackground();
|
2014-01-13 22:12:16 +00:00
|
|
|
newBackground.vignetteSharpness = this.background.vignetteSharpness;
|
|
|
|
newBackground.brightness = this.background.brightness;
|
|
|
|
newBackground.visible = this.background.visible;
|
2012-12-24 14:20:39 +00:00
|
|
|
|
2013-03-19 19:26:05 +00:00
|
|
|
newBackground.loadedSignalId = newBackground.connect('loaded',
|
2012-12-24 14:20:39 +00:00
|
|
|
Lang.bind(this, function() {
|
2013-03-19 19:26:05 +00:00
|
|
|
newBackground.disconnect(newBackground.loadedSignalId);
|
|
|
|
newBackground.loadedSignalId = 0;
|
2014-01-13 22:12:16 +00:00
|
|
|
Tweener.addTween(this.background.actor,
|
2012-12-24 14:20:39 +00:00
|
|
|
{ opacity: 0,
|
|
|
|
time: FADE_ANIMATION_TIME,
|
|
|
|
transition: 'easeOutQuad',
|
|
|
|
onComplete: Lang.bind(this, function() {
|
2014-01-22 19:17:15 +00:00
|
|
|
if (this._newBackground != newBackground) {
|
|
|
|
/* Not interesting, we queued another load */
|
2013-04-04 20:12:31 +00:00
|
|
|
newBackground.actor.destroy();
|
2014-01-22 19:17:15 +00:00
|
|
|
return;
|
2013-03-19 19:26:05 +00:00
|
|
|
}
|
2013-04-04 20:12:31 +00:00
|
|
|
|
2014-01-13 22:12:16 +00:00
|
|
|
this.background.actor.destroy();
|
2014-01-22 19:17:15 +00:00
|
|
|
this.background = newBackground;
|
|
|
|
this._newBackground = null;
|
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
this.emit('changed');
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
this._newBackground = newBackground;
|
|
|
|
},
|
|
|
|
|
|
|
|
_createBackground: function() {
|
|
|
|
let background = new Background({ monitorIndex: this._monitorIndex,
|
|
|
|
layoutManager: this._layoutManager,
|
2013-08-19 22:48:56 +00:00
|
|
|
effects: this._effects,
|
|
|
|
settings: this._settings });
|
2012-12-24 14:20:39 +00:00
|
|
|
this._container.add_child(background.actor);
|
|
|
|
|
|
|
|
let monitor = this._layoutManager.monitors[this._monitorIndex];
|
ScreenShield: fix positioning of background with multimonitor
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
2013-02-21 22:32:25 +00:00
|
|
|
|
2012-12-24 14:20:39 +00:00
|
|
|
background.actor.set_size(monitor.width, monitor.height);
|
ScreenShield: fix positioning of background with multimonitor
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
2013-02-21 22:32:25 +00:00
|
|
|
if (this._controlPosition) {
|
|
|
|
background.actor.set_position(monitor.x, monitor.y);
|
|
|
|
background.actor.lower_bottom();
|
|
|
|
}
|
2012-12-24 14:20:39 +00:00
|
|
|
|
2013-03-19 19:26:05 +00:00
|
|
|
background.changeSignalId = background.connect('changed', Lang.bind(this, function() {
|
|
|
|
background.disconnect(background.changeSignalId);
|
|
|
|
background.changeSignalId = 0;
|
2014-01-13 22:12:16 +00:00
|
|
|
this._updateBackground();
|
2012-12-24 14:20:39 +00:00
|
|
|
}));
|
|
|
|
|
2013-03-19 19:26:05 +00:00
|
|
|
background.actor.connect('destroy', Lang.bind(this, function() {
|
|
|
|
if (background.changeSignalId)
|
|
|
|
background.disconnect(background.changeSignalId);
|
|
|
|
|
|
|
|
if (background.loadedSignalId)
|
|
|
|
background.disconnect(background.loadedSignalId);
|
|
|
|
}));
|
2012-12-24 14:20:39 +00:00
|
|
|
|
|
|
|
return background;
|
|
|
|
},
|
|
|
|
});
|
|
|
|
Signals.addSignalMethods(BackgroundManager.prototype);
|