[gnome-shell/gnome-3-8] background: fix asynchronous management of background loading operations



commit 1020d8a0f8523a04d8336b1348388b8b242e414f
Author: Lionel Landwerlin <llandwerlin gmail com>
Date:   Mon Jun 24 19:13:05 2013 +0100

    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

 js/ui/background.js |   69 ++++++++++++++++++++++++++++++++------------------
 1 files changed, 44 insertions(+), 25 deletions(-)
---
diff --git a/js/ui/background.js b/js/ui/background.js
index 0e9c3aa..f2ffce8 100644
--- a/js/ui/background.js
+++ b/js/ui/background.js
@@ -142,33 +142,40 @@ const BackgroundCache = new Lang.Class({
                                         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;
-            }
+        let fileLoad = { filename: params.filename,
+                         style: params.style,
+                         shouldCopy: false,
+                         monitorIndex: params.monitorIndex,
+                         effects: params.effects,
+                         onFinished: params.onFinished,
+                         cancellable: new Gio.Cancellable(), };
+        this._pendingFileLoads.push(fileLoad);
+
+        if (params.cancellable) {
+            params.cancellable.connect(Lang.bind(this, function(c) {
+               fileLoad.cancellable.cancel();
+            }));
         }
 
-        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,
+                                fileLoad.cancellable,
                                 Lang.bind(this,
                                           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 {
                                                   content.load_file_finish(result);
 
@@ -178,22 +185,25 @@ const BackgroundCache = new Lang.Class({
                                                   content = null;
                                               }
 
+                                              let needsCopy = false;
                                               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);
-
-                                                          }
+                                                  if (pendingLoad.cancellable.is_cancelled())
+                                                      continue;
 
-                                                          pendingLoad.callers[j].onFinished(content);
+                                                  pendingLoad.cancellable.cancel();
+                                                  if (pendingLoad.onFinished) {
+                                                      if (content && needsCopy) {
+                                                          content = object.copy(pendingLoad.monitorIndex,
+                                                                                pendingLoad.effects);
                                                       }
+
+                                                      needsCopy = true;
+                                                      pendingLoad.onFinished(content);
                                                   }
 
                                                   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) {
         params = Params.parse(params, { monitorIndex: 0,
                                         style: null,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]