[gnome-shell/wip/overview-transition: 73/79] background: Fix cancellable issues



commit a2e4153fa0d5f63f85a54c1aaee9ea89b70eba34
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Mon Jan 13 18:42:32 2014 -0500

    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 |  122 +++++++++++++++++++++++++++-----------------------
 1 files changed, 66 insertions(+), 56 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 });
-
         }
     },
 


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