Bug 1285196 - make WindowsPreviewPerTab.jsm do nothing if disabled, r?mak draft
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 07 Jul 2016 18:38:43 +0100
changeset 385084 1f7a13978a765249558f838f675f3587a095cc4a
parent 385042 ec92630e4c635ef1fbaac6115c6a123de1fd5d28
child 524847 faf983280ba6b0739257198358851a1fdc42a144
push id22423
push usergijskruitbosch@gmail.com
push dateThu, 07 Jul 2016 17:39:14 +0000
reviewersmak
bugs1285196
milestone50.0a1
Bug 1285196 - make WindowsPreviewPerTab.jsm do nothing if disabled, r?mak MozReview-Commit-ID: IipisU8fnUW
browser/modules/WindowsPreviewPerTab.jsm
--- a/browser/modules/WindowsPreviewPerTab.jsm
+++ b/browser/modules/WindowsPreviewPerTab.jsm
@@ -445,26 +445,18 @@ TabWindow.prototype = {
   createTabPreview: function (controller) {
     let docShell = this.win
                   .QueryInterface(Ci.nsIInterfaceRequestor)
                   .getInterface(Ci.nsIWebNavigation)
                   .QueryInterface(Ci.nsIDocShell);
     let preview = AeroPeek.taskbar.createTaskbarTabPreview(docShell, controller);
     preview.visible = AeroPeek.enabled;
     preview.active = this.tabbrowser.selectedTab == controller.tab;
-    // Grab the default favicon
-    getFaviconAsImage(
-      null,
-      PrivateBrowsingUtils.isWindowPrivate(this.win),
-      function (img) {
-        // It is possible that we've already gotten the real favicon, so make sure
-        // we have not set one before setting this default one.
-        if (!preview.icon)
-          preview.icon = img;
-      });
+    this.onLinkIconAvailable(controller.tab.linkedBrowser,
+                             controller.tab.getAttribute("image"));
     return preview;
   },
 
   // Invoked when the given tab is closed
   removeTab: function (tab) {
     let preview = this.previewFromTab(tab);
     preview.active = false;
     preview.visible = false;
@@ -605,43 +597,43 @@ TabWindow.prototype = {
       this.invalidateTabPreview(aBrowser);
     }
   },
 
   directRequestProtocols: new Set([
     "file", "chrome", "resource", "about"
   ]),
   onLinkIconAvailable: function (aBrowser, aIconURL) {
-    if (!aIconURL) {
-      return;
+    let requestURL = null;
+    if (aIconURL) {
+      let shouldRequestFaviconURL = true;
+      try {
+        urlObject = NetUtil.newURI(aIconURL);
+        shouldRequestFaviconURL =
+          !this.directRequestProtocols.has(urlObject.scheme);
+      } catch (ex) {}
+
+      requestURL = shouldRequestFaviconURL ?
+        "moz-anno:favicon:" + aIconURL :
+        aIconURL;
     }
-    let tab = this.tabbrowser.getTabForBrowser(aBrowser);
-    let shouldRequestFaviconURL = true;
-    try {
-      urlObject = NetUtil.newURI(aIconURL);
-      shouldRequestFaviconURL =
-        !this.directRequestProtocols.has(urlObject.scheme);
-    } catch (ex) {}
-
-    let requestURL = shouldRequestFaviconURL ?
-      "moz-anno:favicon:" + aIconURL :
-      aIconURL;
-
     getFaviconAsImage(
       requestURL,
       PrivateBrowsingUtils.isWindowPrivate(this.win),
       img => {
         let index = this.tabbrowser.browsers.indexOf(aBrowser);
         // Only add it if we've found the index and the URI is still the same.
         // The tab could have closed, and there's no guarantee the icons
         // will have finished fetching 'in order'.
         if (index != -1) {
           let tab = this.tabbrowser.tabs[index];
-          if (tab.getAttribute("image") == aIconURL) {
-            this.previews.get(tab).icon = img;
+          let preview = this.previews.get(tab);
+          if (tab.getAttribute("image") == aIconURL ||
+              (!preview.icon && !requestURL)) {
+            preview.icon = img;
           }
         }
       }
     );
   }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -649,20 +641,22 @@ TabWindow.prototype = {
 
 /*
  * This object acts as global storage and external interface for this feature.
  * It maintains the values of the prefs.
  */
 this.AeroPeek = {
   available: false,
   // Does the pref say we're enabled?
-  _prefenabled: true,
+  __prefenabled: false,
 
   _enabled: true,
 
+  initialized: false,
+
   // nsITaskbarTabPreview array
   previews: [],
 
   // TabWindow array
   windows: [],
 
   // nsIWinTaskbar service
   taskbar: null,
@@ -676,35 +670,24 @@ this.AeroPeek = {
   initialize: function () {
     if (!(WINTASKBAR_CONTRACTID in Cc))
       return;
     this.taskbar = Cc[WINTASKBAR_CONTRACTID].getService(Ci.nsIWinTaskbar);
     this.available = this.taskbar.available;
     if (!this.available)
       return;
 
-    this.prefs.addObserver(TOGGLE_PREF_NAME, this, false);
-    this.prefs.addObserver(DISABLE_THRESHOLD_PREF_NAME, this, false);
-    this.prefs.addObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this, false);
-    PlacesUtils.history.addObserver(this, true);
-
-    this.cacheLifespan = this.prefs.getIntPref(CACHE_EXPIRATION_TIME_PREF_NAME);
-
-    this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
-
+    this.prefs.addObserver(TOGGLE_PREF_NAME, this, true);
     this.enabled = this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
+    this.initialized = true;
   },
 
   destroy: function destroy() {
     this._enabled = false;
 
-    this.prefs.removeObserver(TOGGLE_PREF_NAME, this);
-    this.prefs.removeObserver(DISABLE_THRESHOLD_PREF_NAME, this);
-    this.prefs.removeObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this);
-
     if (this.cacheTimer)
       this.cacheTimer.cancel();
   },
 
   get enabled() {
     return this._enabled;
   },
 
@@ -714,69 +697,125 @@ this.AeroPeek = {
 
     this._enabled = enable;
 
     this.windows.forEach(function (win) {
       win.enabled = enable;
     });
   },
 
+  get _prefenabled() {
+    return this.__prefenabled;
+  },
+
+  set _prefenabled(enable) {
+    if (enable == this.__prefenabled) {
+      return;
+    }
+    this.__prefenabled = enable;
+
+    if (enable) {
+      this.enable();
+    } else {
+      this.disable();
+    }
+  },
+
+  _observersAdded: false,
+
+  enable() {
+    if (!this._observersAdded) {
+      this.prefs.addObserver(DISABLE_THRESHOLD_PREF_NAME, this, true);
+      this.prefs.addObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this, true);
+      PlacesUtils.history.addObserver(this, true);
+      this._observersAdded = true;
+    }
+
+    this.cacheLifespan = this.prefs.getIntPref(CACHE_EXPIRATION_TIME_PREF_NAME);
+
+    this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
+
+    // If the user toggled us on/off while the browser was already up
+    // (rather than this code running on startup because the pref was
+    // already set to true), we must initialize previews for open windows:
+    if (this.initialized) {
+      let browserWindows = Services.wm.getEnumerator("navigator:browser");
+      while (browserWindows.hasMoreElements()) {
+        let win = browserWindows.getNext();
+        this.onOpenWindow(win);
+      }
+    }
+  },
+
+  disable() {
+    while (this.windows.length) {
+      this.windows[0].destroy(); // This will remove us from the array.
+    }
+  },
+
   addPreview: function (preview) {
     this.previews.push(preview);
     this.checkPreviewCount();
   },
 
   removePreview: function (preview) {
     let idx = this.previews.indexOf(preview);
     this.previews.splice(idx, 1);
     this.checkPreviewCount();
   },
 
   checkPreviewCount: function () {
+    if (!this._prefenabled) {
+      return;
+    }
     if (this.previews.length > this.maxpreviews)
       this.enabled = false;
     else
       this.enabled = this._prefenabled;
   },
 
   onOpenWindow: function (win) {
     // This occurs when the taskbar service is not available (xp, vista)
-    if (!this.available)
+    if (!this.available || !this._prefenabled)
       return;
 
     win.gTaskbarTabGroup = new TabWindow(win);
   },
 
   onCloseWindow: function (win) {
     // This occurs when the taskbar service is not available (xp, vista)
-    if (!this.available)
+    if (!this.available || !this._prefenabled)
       return;
 
     win.gTaskbarTabGroup.destroy();
     delete win.gTaskbarTabGroup;
 
     if (this.windows.length == 0)
       this.destroy();
   },
 
   resetCacheTimer: function () {
     this.cacheTimer.cancel();
     this.cacheTimer.init(this, 1000*this.cacheLifespan, Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
   //// nsIObserver
   observe: function (aSubject, aTopic, aData) {
+    if (aTopic == "nsPref:changed" && aData == TOGGLE_PREF_NAME) {
+      this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
+    }
+    if (!this._prefenabled) {
+      return;
+    }
     switch (aTopic) {
       case "nsPref:changed":
         if (aData == CACHE_EXPIRATION_TIME_PREF_NAME)
           break;
 
-        if (aData == TOGGLE_PREF_NAME)
-          this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
-        else if (aData == DISABLE_THRESHOLD_PREF_NAME)
+        if (aData == DISABLE_THRESHOLD_PREF_NAME)
           this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
         // Might need to enable/disable ourselves
         this.checkPreviewCount();
         break;
       case "timer-callback":
         this.previews.forEach(function (preview) {
           let controller = preview.controller.wrappedJSObject;
           controller.resetCanvasPreview();
@@ -791,28 +830,32 @@ this.AeroPeek = {
   onVisit() {},
   onTitleChanged() {},
   onFrecencyChanged() {},
   onManyFrecenciesChanged() {},
   onDeleteURI() {},
   onClearHistory() {},
   onDeleteVisits() {},
   onPageChanged(uri, changedConst, newValue) {
-    if (this._enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
+    if (this.enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
       for (let win of this.windows) {
         for (let [tab, preview] of win.previews) {
           if (tab.getAttribute("image") == newValue) {
             win.onLinkIconAvailable(tab.linkedBrowser, newValue);
           }
         }
       }
     }
   },
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsINavHistoryObserver]),
+  QueryInterface: XPCOMUtils.generateQI([
+    Ci.nsISupportsWeakReference,
+    Ci.nsINavHistoryObserver,
+    Ci.nsIObserver
+  ]),
 };
 
 XPCOMUtils.defineLazyGetter(AeroPeek, "cacheTimer", () =>
   Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer)
 );
 
 XPCOMUtils.defineLazyServiceGetter(AeroPeek, "prefs",
                                    "@mozilla.org/preferences-service;1",