From bed3bb45f7cb55ed6a2d88fd54f29d9ed502e901 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 25 Mar 2013 15:03:48 -0400 Subject: [PATCH] background: don't load the same image more than once concurrently If a background gets requested from the cache while it's still being loaded from an earlier call, then there will be two concurrent loads of the same file. That concurrency is mitigates the effectiveness of the cache and also causes leaks. This commit consolidates file loads so that concurrency doesn't happen. https://bugzilla.gnome.org/show_bug.cgi?id=696157 --- js/ui/background.js | 92 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/js/ui/background.js b/js/ui/background.js index cacdffb0d..262545222 100644 --- a/js/ui/background.js +++ b/js/ui/background.js @@ -38,6 +38,7 @@ const BackgroundCache = new Lang.Class({ _init: function() { this._patterns = []; this._images = []; + this._pendingFileLoads = []; this._fileMonitors = {}; }, @@ -128,6 +129,73 @@ const BackgroundCache = new Lang.Class({ this._removeContent(this._images, content); }, + _loadImageContent: function(params) { + params = Params.parse(params, { monitorIndex: 0, + style: null, + filename: null, + effects: Meta.BackgroundEffects.NONE, + cancellable: null, + onFinished: 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; + } + } + + 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; + } + + 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) { + if (content && pendingLoad.callers[j].shouldCopy) { + content = object.copy(pendingLoad.callers[j].monitorIndex, + pendingLoad.callers[j].effects); + + } + + pendingLoad.callers[j].onFinished(content); + } + } + + this._pendingFileLoads.splice(i, 1); + } + })); + }, + getImageContent: function(params) { params = Params.parse(params, { monitorIndex: 0, style: null, @@ -171,27 +239,11 @@ const BackgroundCache = new Lang.Class({ if (params.onFinished) params.onFinished(content); } else { - content = new Meta.Background({ meta_screen: global.screen, - monitor: params.monitorIndex, - effects: params.effects }); + this._loadImageContent({ filename: params.filename, + style: params.style, + cancellable: params.cancellable, + onFinished: params.onFinished }); - 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); - })); } },