+ no longer loading the frame at all until the user needs it
authorIan Gilman <ian@iangilman.com>
Mon, 09 Aug 2010 17:24:08 -0700
changeset 50285 99097a097e4f9bbe429a56bcf56ae51772f86594
parent 50284 9a7a4256f84260f5c9c231f433f75029b1b6f705
child 50286 ce0c948f1554186de653d6cdf6223cdef390e3c3
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
+ no longer loading the frame at all until the user needs it
browser/base/content/browser-tabview.js
browser/base/content/tabview/storage.js
browser/base/content/tabview/ui.js
--- a/browser/base/content/browser-tabview.js
+++ b/browser/base/content/browser-tabview.js
@@ -29,81 +29,186 @@
 # use your version of this file under the terms of the MPL, indicate your
 # decision by deleting the provisions above and replace them with the notice
 # and other provisions required by the GPL or the LGPL. If you do not delete
 # the provisions above, a recipient may use your version of this file under
 # the terms of any one of the MPL, the GPL or the LGPL.
 #
 # ***** END LICENSE BLOCK *****
 
-// New API methods can be added to here.
 let TabView = {
-  init: function TabView_init() {
+  _window: null,
+  _sessionstore: null,
+  _visibilityID: "tabview-visibility",
+  
+  // ----------
+  init: function TabView_init() {    
+    // ___ keys    
+    this._setBrowserKeyHandlers();
+
+    // ___ visibility
+    this._sessionstore =
+      Components.classes["@mozilla.org/browser/sessionstore;1"]
+        .getService(Components.interfaces.nsISessionStore);
+
+    let data = this._sessionstore.getWindowValue(window, this._visibilityID);
+    if (data) {
+      data = JSON.parse(data);
+      if (data && data.visible)
+        this.toggle();
+    }
+  },
+
+  // ----------
+  _initFrame: function TabView__initFrame() {
+    if (this._window)
+      return;
+      
+    // ___ create the frame
     var iframe = document.createElement("iframe");
     iframe.id = "tab-view";
     iframe.setAttribute("transparent", "true");
     iframe.flex = 1;
     iframe.setAttribute("src", "chrome://browser/content/tabview.html");
     document.getElementById("tab-view-deck").appendChild(iframe);
+    this._window = iframe.contentWindow;
+    
+    // ___ visibility storage handler
+    let self = this;
+    var observer = {
+      observe : function(subject, topic, data) {
+        if (topic == "quit-application-requested") {
+          let data = {
+            visible: self.isVisible()
+          };
+          
+          self._sessionstore.setWindowValue(window, self._visibilityID, JSON.stringify(data));
+        }
+      }
+    };
+    
+    Services.obs.addObserver(observer, "quit-application-requested", false);
   },
 
+  // ----------
   isVisible: function() {
     return (window.document.getElementById("tab-view-deck").selectedIndex == 1);
   },
 
+  // ----------
   toggle: function() {
+    let firstTime = false;
     let event = document.createEvent("Events");
 
     if (this.isVisible()) {
       event.initEvent("tabviewhide", false, false);
     } else {
+      if (!this._window) {
+        firstTime = true;
+        this._initFrame(); 
+      }        
+        
       event.initEvent("tabviewshow", false, false);
     }
-    dispatchEvent(event);
+    
+    if (firstTime) {
+      // TODO: need a better way to know when the frame is loaded
+      // I suppose we can just attach to its onload?
+      setTimeout(function() {
+        dispatchEvent(event);
+      }, 100);
+    } else {
+      dispatchEvent(event);
+    }
   },
 
+  // ----------
   getWindowTitle: function() {
     let brandBundle = document.getElementById("bundle_brand");
     let brandShortName = brandBundle.getString("brandShortName");
     return gNavigatorBundle.getFormattedString("tabView.title", [brandShortName]);
   },
 
+  // ----------
   updateContextMenu: function(tab, popup) {
-    let tabViewWindow = document.getElementById("tab-view").contentWindow;
     let isEmpty = true;
 
     while(popup.lastChild && popup.lastChild.id != "context_namedGroups")
       popup.removeChild(popup.lastChild);
 
-	  if (!tabViewWindow.UI.frameInitalized)
-	    tabViewWindow.UI.initFrame();
+	  if (!this._window)
+	    this._initFrame(); // TODO: wait for load	    
 
     let activeGroup = tab.tabItem.parent;
-    let groupItems = tabViewWindow.GroupItems.groupItems;
+    let groupItems = this._window.GroupItems.groupItems;
     let self = this;
 
     groupItems.forEach(function(groupItem) { 
       if (groupItem.getTitle().length > 0 && 
           (!activeGroup || activeGroup.id != groupItem.id)) {
         let menuItem = self._createGroupMenuItem(groupItem);
         popup.appendChild(menuItem);
         isEmpty = false;
       }
     });
     document.getElementById("context_namedGroups").hidden = isEmpty;
   },
 
+  // ----------
   _createGroupMenuItem : function(groupItem) {
     let menuItem = document.createElement("menuitem")
     menuItem.setAttribute("class", "group");
     menuItem.setAttribute("label", groupItem.getTitle());
     menuItem.setAttribute(
       "oncommand", 
       "TabView.moveTabTo(TabContextMenu.contextTab,'" + groupItem.id + "')");
 
     return menuItem;
   },
 
+  // ----------
   moveTabTo: function(tab, groupItemId) {
-    let tabViewWindow = document.getElementById("tab-view").contentWindow;
-    tabViewWindow.GroupItems.moveTabToGroupItem(tab, groupItemId);
+    if (this._window)
+      this._window.GroupItems.moveTabToGroupItem(tab, groupItemId);
+  },
+
+  // ----------
+  // Overrides the browser's keys for navigating between tab (outside of the
+  // TabView UI) so they do the right thing in respect to groupItems.
+  _setBrowserKeyHandlers : function() {
+    var self = this;
+
+    window.addEventListener("keypress", function(event) {
+      if (self.isVisible())
+        return;
+
+      var charCode = event.charCode;
+#ifdef XP_MACOSX
+      // if a text box in a webpage has the focus, the event.altKey would
+      // return false so we are depending on the charCode here.
+      if (!event.ctrlKey && !event.metaKey && !event.shiftKey &&
+          charCode == 160) { // alt + space
+#else
+      if (event.ctrlKey && !event.metaKey && !event.shiftKey &&
+          !event.altKey && charCode == 32) { // ctrl + space
+#endif
+        event.stopPropagation();
+        event.preventDefault();
+        self.toggle();
+        return;
+      }
+
+      // Control (+ Shift) + `
+      if (event.ctrlKey && !event.metaKey && !event.altKey &&
+          (charCode == 96 || charCode == 126)) {
+        event.stopPropagation();
+        event.preventDefault();
+
+        if (!self._window)
+          self._initFrame(); // TODO: wait for load
+
+        var tabItem = self._window.GroupItems.getNextGroupItemTab(event.shiftKey);
+        if (tabItem)
+          window.gBrowser.selectedTab = tabItem.tab;
+      }
+    }, true);
   }
 };
--- a/browser/base/content/tabview/storage.js
+++ b/browser/base/content/tabview/storage.js
@@ -44,50 +44,16 @@
 Storage = {
   GROUP_DATA_IDENTIFIER:  "tabview-group",
   GROUPS_DATA_IDENTIFIER: "tabview-groups",
   TAB_DATA_IDENTIFIER:    "tabview-tab",
   UI_DATA_IDENTIFIER:    "tabview-ui",
   VISIBILITY_DATA_IDENTIFIER:    "tabview-visibility",
 
   // ----------
-  // Function: onReady
-  // Calls callback when Storage is ready for business. Could be immediately if it's already ready
-  // or later if needed.
-  onReady: function(callback) {
-    try {
-      // ToDo: the session store doesn't expose any public methods/variables for
-      // us to check whether it's loaded or not so using a private one for
-      // now.
-      var alreadyReady = gWindow.__SSi;
-      if (alreadyReady) {
-        callback();
-      } else {
-        var observer = {
-          observe: function(subject, topic, data) {
-            try {
-              if (topic == "browser-delayed-startup-finished") {
-                if (subject == gWindow) {
-                  callback();
-                }
-              }
-            } catch(e) {
-              Utils.log(e);
-            }
-          }
-        };
-        Services.obs.addObserver(
-          observer, "browser-delayed-startup-finished", false);
-      }
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
   // Function: init
   // Sets up the object.
   init: function() {
     this._sessionStore =
       Components.classes["@mozilla.org/browser/sessionstore;1"]
         .getService(Components.interfaces.nsISessionStore);
   },
 
--- a/browser/base/content/tabview/ui.js
+++ b/browser/base/content/tabview/ui.js
@@ -79,77 +79,35 @@ var UIManager = {
   // TabView UI and re-orders the tabs when switcing back to main browser.
   _reorderTabsOnHide : [],
 
   // Variable: _currentTab
   // Keeps track of which xul:tab we are currently on.
   // Used to facilitate zooming down from a previous tab.
   _currentTab : null,
 
-  // Variable: frameInitalized
-  // The getter of _frameInitalized.
-  get frameInitalized() this._frameInitalized,
-
   // ----------
   // Function: init
   // Must be called after the object is created.
   init: function() {
-    var self = this;
-    Profile.checkpoint();
-    Storage.onReady(function() {
-      self._delayInit();
-    });
-  },
-
-  // ----------
-  // Function: _delayInit
-  // Called automatically by init once sessionstore is online.
-  _delayInit : function() {
     try {
-      Profile.checkpoint("delay until _delayInit");
       let self = this;
 
       // ___ storage
       Storage.init();
       let data = Storage.readUIData(gWindow);
       this._storageSanity(data);
       this._pageBounds = data.pageBounds;
 
       // ___ hook into the browser
-      this._setBrowserKeyHandlers();
-
       gWindow.addEventListener("tabviewshow", function() {
         self.showTabView(true);
       }, false);
-
-      // ___ show TabView at startup based on last session.
-      if (data.tabViewVisible) {
-        this._stopZoomPreparation = true;
-        this.showTabView();
-
-        // ensure the tabs in the tab strip are in the same order as the tab
-        // items in groupItems when switching back to main browser UI for the first
-        // time.
-        GroupItems.groupItems.forEach(function(groupItem) {
-          self._reorderTabsOnHide.push(groupItem);
-        });
-      }
-    } catch(e) {
-      Utils.log(e);
-    }
-  },
-
-  // ----------
-  // Function: initFrame
-  // Initializes the TabView UI
-  initFrame: function() {
-    try {
-      Utils.assert("must not be already initialized", !this._frameInitalized);
-
-      let self = this;
+      
+      // ___ currentTab
       this._currentTab = gBrowser.selectedTab;
 
       // ___ Dev Menu
       this._addDevMenu();
 
       // When you click on the background/empty part of TabView,
       // we create a new groupItem.
       iQ(gTabViewFrame.contentDocument).mousedown(function(e) {
@@ -315,19 +273,16 @@ var UIManager = {
   // Function: showTabView
   // Shows TabView and hides the main browser UI.
   // Parameters:
   //   zoomOut - true for zoom out animation, false for nothing.
   showTabView: function(zoomOut) {
     if (this._isTabViewVisible())
       return;
 
-    if (!this._frameInitalized)
-      this.initFrame();
-
     var self = this;
     var currentTab = this._currentTab;
     var item = null;
 
     this._reorderTabItemsOnShow.forEach(function(groupItem) {
       groupItem.reorderTabItemsBasedOnTabOrder();
     });
     this._reorderTabItemsOnShow = [];
@@ -586,59 +541,16 @@ var UIManager = {
     if (!this._isTabViewVisible()) {
       var index = this._reorderTabItemsOnShow.indexOf(groupItem);
       if (index == -1)
         this._reorderTabItemsOnShow.push(groupItem);
     }
   },
 
   // ----------
-  // Function: _setBrowserKeyHandlers
-  // Overrides the browser's keys for navigating between tab (outside of the
-  // TabView UI) so they do the right thing in respect to groupItems.
-  _setBrowserKeyHandlers : function() {
-    var self = this;
-
-    gWindow.addEventListener("keypress", function(event) {
-      if (self._isTabViewVisible())
-        return;
-
-      var charCode = event.charCode;
-#ifdef XP_MACOSX
-      // if a text box in a webpage has the focus, the event.altKey would
-      // return false so we are depending on the charCode here.
-      if (!event.ctrlKey && !event.metaKey && !event.shiftKey &&
-          charCode == 160) { // alt + space
-#else
-      if (event.ctrlKey && !event.metaKey && !event.shiftKey &&
-          !event.altKey && charCode == 32) { // ctrl + space
-#endif
-        event.stopPropagation();
-        event.preventDefault();
-        self.showTabView(true);
-        return;
-      }
-
-      // Control (+ Shift) + `
-      if (event.ctrlKey && !event.metaKey && !event.altKey &&
-          (charCode == 96 || charCode == 126)) {
-        event.stopPropagation();
-        event.preventDefault();
-
-        if (!self._frameInitalized)
-          self.initFrame();
-
-        var tabItem = GroupItems.getNextGroupItemTab(event.shiftKey);
-        if (tabItem)
-          gBrowser.selectedTab = tabItem.tab;
-      }
-    }, true);
-  },
-
-  // ----------
   // Function: _setTabViewFrameKeyHandlers
   // Sets up the key handlers for navigating between tabs within the TabView UI.
   _setTabViewFrameKeyHandlers: function() {
     var self = this;
 
     iQ(window).keyup(function(event) {
       if (!event.metaKey) window.Keys.meta = false;
     });
@@ -1058,17 +970,16 @@ var UIManager = {
   // ----------
   // Function: _save
   // Saves the data for this object to persistent storage
   _save: function() {
     if (!this._frameInitalized)
       return;
 
     var data = {
-      tabViewVisible: this._isTabViewVisible(),
       pageBounds: this._pageBounds
     };
 
     if (this._storageSanity(data))
       Storage.saveUIData(gWindow, data);
   },
 
   // ----------