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
This commit is contained in:
parent
2fba8e29e0
commit
a2e4153fa0
@ -132,6 +132,46 @@ const BackgroundCache = new Lang.Class({
|
|||||||
this._removeContent(this._images, content);
|
this._removeContent(this._images, content);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_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;
|
||||||
|
},
|
||||||
|
|
||||||
_loadImageContent: function(params) {
|
_loadImageContent: function(params) {
|
||||||
params = Params.parse(params, { monitorIndex: 0,
|
params = Params.parse(params, { monitorIndex: 0,
|
||||||
style: null,
|
style: null,
|
||||||
@ -140,67 +180,38 @@ const BackgroundCache = new Lang.Class({
|
|||||||
cancellable: null,
|
cancellable: null,
|
||||||
onFinished: null });
|
onFinished: null });
|
||||||
|
|
||||||
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
let caller = { monitorIndex: params.monitorIndex,
|
||||||
if (this._pendingFileLoads[i].filename == params.filename &&
|
|
||||||
this._pendingFileLoads[i].style == params.style) {
|
|
||||||
this._pendingFileLoads[i].callers.push({ shouldCopy: true,
|
|
||||||
monitorIndex: params.monitorIndex,
|
|
||||||
effects: params.effects,
|
effects: params.effects,
|
||||||
onFinished: params.onFinished });
|
cancellable: params.cancellable,
|
||||||
return;
|
onFinished: params.onFinished };
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._pendingFileLoads.push({ filename: params.filename,
|
|
||||||
style: params.style,
|
|
||||||
callers: [{ shouldCopy: false,
|
|
||||||
monitorIndex: params.monitorIndex,
|
|
||||||
effects: params.effects,
|
|
||||||
onFinished: params.onFinished }] });
|
|
||||||
|
|
||||||
let 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
let info = null;
|
||||||
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
||||||
let pendingLoad = this._pendingFileLoads[i];
|
let pendingLoad = this._pendingFileLoads[i];
|
||||||
if (pendingLoad.filename != params.filename ||
|
if (pendingLoad.filename == params.filename && pendingLoad.style == params.style) {
|
||||||
pendingLoad.style != params.style)
|
info = pendingLoad;
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
for (let j = 0; j < pendingLoad.callers.length; j++) {
|
|
||||||
if (pendingLoad.callers[j].onFinished) {
|
|
||||||
let newContent;
|
|
||||||
|
|
||||||
if (content && pendingLoad.callers[j].shouldCopy) {
|
|
||||||
newContent = content.copy(pendingLoad.callers[j].monitorIndex,
|
|
||||||
pendingLoad.callers[j].effects);
|
|
||||||
this._images.push(newContent);
|
|
||||||
} else {
|
|
||||||
newContent = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingLoad.callers[j].onFinished(newContent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._pendingFileLoads.splice(i, 1);
|
if (!info)
|
||||||
|
info = this._loadImageContentInternal(params.filename, params.style);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
let idx = this._pendingFileLoads.indexOf(info);
|
||||||
|
this._pendingFileLoads.splice(idx, 1);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getImageContent: function(params) {
|
getImageContent: function(params) {
|
||||||
@ -250,7 +261,6 @@ const BackgroundCache = new Lang.Class({
|
|||||||
monitorIndex: params.monitorIndex,
|
monitorIndex: params.monitorIndex,
|
||||||
cancellable: params.cancellable,
|
cancellable: params.cancellable,
|
||||||
onFinished: params.onFinished });
|
onFinished: params.onFinished });
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user