gnome-shell/gnome-shell-3.11.90-background.patch

184 lines
8.3 KiB
Diff

From b5d7bd02b514b9862203ff30435b6c98766143ef Mon Sep 17 00:00:00 2001
From: "Jasper St. Pierre" <jstpierre@mecheye.net>
Date: Mon, 13 Jan 2014 18:42:32 -0500
Subject: [PATCH] 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
---
js/ui/background.js | 120 ++++++++++++++++++++++++++++------------------------
1 file changed, 65 insertions(+), 55 deletions(-)
diff --git a/js/ui/background.js b/js/ui/background.js
index 3a7541c..a3224f5 100644
--- a/js/ui/background.js
+++ b/js/ui/background.js
@@ -132,6 +132,46 @@ const BackgroundCache = new Lang.Class({
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) {
params = Params.parse(params, { monitorIndex: 0,
style: null,
@@ -140,67 +180,38 @@ const BackgroundCache = new Lang.Class({
cancellable: null,
onFinished: null });
+ let caller = { monitorIndex: params.monitorIndex,
+ effects: params.effects,
+ cancellable: params.cancellable,
+ onFinished: params.onFinished };
+
+ let info = null;
for (let i = 0; i < this._pendingFileLoads.length; i++) {
- 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,
- onFinished: params.onFinished });
- return;
+ let pendingLoad = this._pendingFileLoads[i];
+ if (pendingLoad.filename == params.filename && pendingLoad.style == params.style) {
+ info = pendingLoad;
+ break;
}
}
- this._pendingFileLoads.push({ filename: params.filename,
- style: params.style,
- callers: [{ shouldCopy: false,
- monitorIndex: params.monitorIndex,
- effects: params.effects,
- onFinished: params.onFinished }] });
+ if (!info)
+ info = this._loadImageContentInternal(params.filename, params.style);
- let content = new Meta.Background({ meta_screen: global.screen,
- monitor: params.monitorIndex,
- effects: params.effects });
+ info.callers.push(caller);
- 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 (caller.cancellable) {
+ caller.cancellable.connect(Lang.bind(this, function() {
+ let idx = info.callers.indexOf(caller);
+ info.callers.splice(idx, 1);
- for (let i = 0; i < this._pendingFileLoads.length; i++) {
- let pendingLoad = this._pendingFileLoads[i];
- if (pendingLoad.filename != params.filename ||
- pendingLoad.style != params.style)
- continue;
-
- 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.callers.length == 0) {
+ info.cancellable.cancel();
+
+ let idx = this._pendingFileLoads.indexOf(info);
+ this._pendingFileLoads.splice(idx, 1);
+ }
+ }));
+ }
},
getImageContent: function(params) {
@@ -250,7 +261,6 @@ const BackgroundCache = new Lang.Class({
monitorIndex: params.monitorIndex,
cancellable: params.cancellable,
onFinished: params.onFinished });
-
}
},
--
1.8.5.3