background: fix asynchronous management of background loading operations
This fixes a blue background being drawn when switching the monitors configuration using hardware keys (clone/multimonitor/external/internal). The problem is that the shell gather all background loading requests under the same meta_background_load_file_async call using one GCancellable (the first one to come). So when the shell receives a batch of 12 or so XRandr events, it creates 12 new background managers which end up trying to load 12 times the same background picture. All of these requests are batched into the same meta_background_load_file_async using the first GCancellable received on the first request. Unfortunately, when the first request is cancelled by the following event indicating a new monitor setup, all of the background picture requests are dropped on the floor, and nothing gets loaded (hence the blue screen background). https://bugzilla.gnome.org/show_bug.cgi?id=703001
This commit is contained in:
parent
1f6811ca06
commit
1020d8a0f8
@ -142,23 +142,20 @@ const BackgroundCache = new Lang.Class({
|
|||||||
cancellable: null,
|
cancellable: null,
|
||||||
onFinished: null });
|
onFinished: null });
|
||||||
|
|
||||||
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
let fileLoad = { filename: params.filename,
|
||||||
if (this._pendingFileLoads[i].filename == params.filename &&
|
style: params.style,
|
||||||
this._pendingFileLoads[i].style == params.style) {
|
shouldCopy: false,
|
||||||
this._pendingFileLoads[i].callers.push({ shouldCopy: true,
|
monitorIndex: params.monitorIndex,
|
||||||
monitorIndex: params.monitorIndex,
|
effects: params.effects,
|
||||||
effects: params.effects,
|
onFinished: params.onFinished,
|
||||||
onFinished: params.onFinished });
|
cancellable: new Gio.Cancellable(), };
|
||||||
return;
|
this._pendingFileLoads.push(fileLoad);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._pendingFileLoads.push({ filename: params.filename,
|
if (params.cancellable) {
|
||||||
style: params.style,
|
params.cancellable.connect(Lang.bind(this, function(c) {
|
||||||
callers: [{ shouldCopy: false,
|
fileLoad.cancellable.cancel();
|
||||||
monitorIndex: params.monitorIndex,
|
}));
|
||||||
effects: params.effects,
|
}
|
||||||
onFinished: params.onFinished }] });
|
|
||||||
|
|
||||||
let content = new Meta.Background({ meta_screen: global.screen,
|
let content = new Meta.Background({ meta_screen: global.screen,
|
||||||
monitor: params.monitorIndex,
|
monitor: params.monitorIndex,
|
||||||
@ -166,9 +163,19 @@ const BackgroundCache = new Lang.Class({
|
|||||||
|
|
||||||
content.load_file_async(params.filename,
|
content.load_file_async(params.filename,
|
||||||
params.style,
|
params.style,
|
||||||
params.cancellable,
|
fileLoad.cancellable,
|
||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
function(object, result) {
|
function(object, result) {
|
||||||
|
if (fileLoad.cancellable.is_cancelled()) {
|
||||||
|
if (params.cancellable && params.cancellable.is_cancelled()) {
|
||||||
|
if (params.onFinished)
|
||||||
|
params.onFinished(null);
|
||||||
|
this._removePendingFileLoad(fileLoad);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
content.load_file_finish(result);
|
content.load_file_finish(result);
|
||||||
|
|
||||||
@ -178,22 +185,25 @@ const BackgroundCache = new Lang.Class({
|
|||||||
content = null;
|
content = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let needsCopy = false;
|
||||||
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)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (let j = 0; j < pendingLoad.callers.length; j++) {
|
if (pendingLoad.cancellable.is_cancelled())
|
||||||
if (pendingLoad.callers[j].onFinished) {
|
continue;
|
||||||
if (content && pendingLoad.callers[j].shouldCopy) {
|
|
||||||
content = object.copy(pendingLoad.callers[j].monitorIndex,
|
|
||||||
pendingLoad.callers[j].effects);
|
|
||||||
|
|
||||||
}
|
pendingLoad.cancellable.cancel();
|
||||||
|
if (pendingLoad.onFinished) {
|
||||||
pendingLoad.callers[j].onFinished(content);
|
if (content && needsCopy) {
|
||||||
|
content = object.copy(pendingLoad.monitorIndex,
|
||||||
|
pendingLoad.effects);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
needsCopy = true;
|
||||||
|
pendingLoad.onFinished(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._pendingFileLoads.splice(i, 1);
|
this._pendingFileLoads.splice(i, 1);
|
||||||
@ -201,6 +211,15 @@ const BackgroundCache = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_removePendingFileLoad: function(fileLoad) {
|
||||||
|
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
||||||
|
if (this._pendingFileLoads[i].cancellable == fileLoad.cancellable) {
|
||||||
|
this._pendingFileLoads.splice(i, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getImageContent: function(params) {
|
getImageContent: function(params) {
|
||||||
params = Params.parse(params, { monitorIndex: 0,
|
params = Params.parse(params, { monitorIndex: 0,
|
||||||
style: null,
|
style: null,
|
||||||
|
Loading…
Reference in New Issue
Block a user