background: fix cancellable issue

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.

Based on work from Jasper St. Pierre <jstpierre@macheye.net>

https://bugzilla.gnome.org/show_bug.cgi?id=722149
This commit is contained in:
Ray Strode 2014-02-26 15:45:14 -05:00 committed by Jasper St. Pierre
parent fdf264ff64
commit 55d1c7e2ab

View File

@ -134,6 +134,21 @@ const BackgroundCache = new Lang.Class({
_attachCallerToFileLoad: function(caller, fileLoad) { _attachCallerToFileLoad: function(caller, fileLoad) {
fileLoad.callers.push(caller); 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) { _loadImageContent: function(params) {
@ -146,6 +161,7 @@ const BackgroundCache = new Lang.Class({
let caller = { monitorIndex: params.monitorIndex, let caller = { monitorIndex: params.monitorIndex,
effects: params.effects, effects: params.effects,
cancellable: params.cancellable,
onFinished: params.onFinished }; onFinished: params.onFinished };
for (let i = 0; i < this._pendingFileLoads.length; i++) { for (let i = 0; i < this._pendingFileLoads.length; i++) {
@ -160,6 +176,7 @@ const BackgroundCache = new Lang.Class({
let fileLoad = { filename: params.filename, let fileLoad = { filename: params.filename,
style: params.style, style: params.style,
cancellable: new Gio.Cancellable(),
callers: [] }; callers: [] };
this._attachCallerToFileLoad(caller, fileLoad); this._attachCallerToFileLoad(caller, fileLoad);