Backout bug 899222 (forgot to apply review comments)
authorBill McCloskey <wmccloskey@mozilla.com>
Mon, 19 Aug 2013 15:26:39 -0700
changeset 143140 8a62bbd033a23aff392d5c4ed6cad3e5026aafe2
parent 143139 716d1f856bdf6e1a513e14ece2c4c5c70584cf05
child 143141 bbf749ee2af7c67e8e60efa38b0f04c71a78f608
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
bugs899222
milestone26.0a1
Backout bug 899222 (forgot to apply review comments)
browser/base/content/abouthome/aboutHome.js
browser/base/content/browser.js
browser/base/content/content.js
browser/base/content/test/browser_aboutHome.js
browser/components/nsBrowserGlue.js
browser/modules/AboutHome.jsm
browser/modules/AboutHomeUtils.jsm
browser/modules/moz.build
--- a/browser/base/content/abouthome/aboutHome.js
+++ b/browser/base/content/abouthome/aboutHome.js
@@ -165,20 +165,16 @@ let gObserver = new MutationObserver(fun
 });
 
 window.addEventListener("pageshow", function () {
   // Delay search engine setup, cause browser.js::BrowserOnAboutPageLoad runs
   // later and may use asynchronous getters.
   window.gObserver.observe(document.documentElement, { attributes: true });
   fitToWidth();
   window.addEventListener("resize", fitToWidth);
-
-  // Ask chrome to update snippets.
-  var event = new CustomEvent('AboutHomeLoad', {bubbles:true});
-  document.dispatchEvent(event);
 });
 
 window.addEventListener("pagehide", function() {
   window.gObserver.disconnect();
   window.removeEventListener("resize", fitToWidth);
 });
 
 // This object has the same interface as Map and is used to store and retrieve
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -79,16 +79,19 @@ this.__defineGetter__("PluralForm", func
 this.__defineSetter__("PluralForm", function (val) {
   delete this.PluralForm;
   return this.PluralForm = val;
 });
 
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch",
   "resource://gre/modules/TelemetryStopwatch.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils",
+  "resource:///modules/AboutHomeUtils.jsm");
+
 #ifdef MOZ_SERVICES_SYNC
 XPCOMUtils.defineLazyModuleGetter(this, "Weave",
   "resource://services-sync/main.js");
 #endif
 
 XPCOMUtils.defineLazyGetter(this, "PopupNotifications", function () {
   let tmp = {};
   Cu.import("resource://gre/modules/PopupNotifications.jsm", tmp);
@@ -2308,16 +2311,74 @@ function SetPageProxyState(aState)
 
 function PageProxyClickHandler(aEvent)
 {
   if (aEvent.button == 1 && gPrefService.getBoolPref("middlemouse.paste"))
     middleMousePaste(aEvent);
 }
 
 /**
+ *  Handle load of some pages (about:*) so that we can make modifications
+ *  to the DOM for unprivileged pages.
+ */
+function BrowserOnAboutPageLoad(doc) {
+  if (doc.documentURI.toLowerCase() == "about:home") {
+    // XXX bug 738646 - when Marketplace is launched, remove this statement and
+    // the hidden attribute set on the apps button in aboutHome.xhtml
+    if (getBoolPref("browser.aboutHome.apps", false))
+      doc.getElementById("apps").removeAttribute("hidden");
+
+    let ss = Components.classes["@mozilla.org/browser/sessionstore;1"].
+             getService(Components.interfaces.nsISessionStore);
+    if (ss.canRestoreLastSession &&
+        !PrivateBrowsingUtils.isWindowPrivate(window))
+      doc.getElementById("launcher").setAttribute("session", "true");
+
+    // Inject search engine and snippets URL.
+    let docElt = doc.documentElement;
+    // set the following attributes BEFORE searchEngineURL, which triggers to
+    // show the snippets when it's set.
+    docElt.setAttribute("snippetsURL", AboutHomeUtils.snippetsURL);
+    if (AboutHomeUtils.showKnowYourRights) {
+      docElt.setAttribute("showKnowYourRights", "true");
+      // Set pref to indicate we've shown the notification.
+      let currentVersion = Services.prefs.getIntPref("browser.rights.version");
+      Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
+    }
+    docElt.setAttribute("snippetsVersion", AboutHomeUtils.snippetsVersion);
+
+    let updateSearchEngine = function() {
+      let engine = AboutHomeUtils.defaultSearchEngine;
+      docElt.setAttribute("searchEngineName", engine.name);
+      docElt.setAttribute("searchEnginePostData", engine.postDataString || "");
+      // Again, keep the searchEngineURL as the last attribute, because the
+      // mutation observer in aboutHome.js is counting on that.
+      docElt.setAttribute("searchEngineURL", engine.searchURL);
+    };
+    updateSearchEngine();
+
+    // Listen for the event that's triggered when the user changes search engine.
+    // At this point we simply reload about:home to reflect the change.
+    Services.obs.addObserver(updateSearchEngine, "browser-search-engine-modified", false);
+
+    // Remove the observer when the page is reloaded or closed.
+    doc.defaultView.addEventListener("pagehide", function removeObserver() {
+      doc.defaultView.removeEventListener("pagehide", removeObserver);
+      Services.obs.removeObserver(updateSearchEngine, "browser-search-engine-modified");
+    }, false);
+
+#ifdef MOZ_SERVICES_HEALTHREPORT
+    doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
+      BrowserSearch.recordSearchInHealthReport(e.detail, "abouthome");
+    }, true, true);
+#endif
+  }
+}
+
+/**
  * Handle command events bubbling up from error page content
  */
 let BrowserOnClick = {
   handleEvent: function BrowserOnClick_handleEvent(aEvent) {
     if (!aEvent.isTrusted || // Don't trust synthetic events
         aEvent.button == 2 || aEvent.target.localName != "button") {
       return;
     }
@@ -2331,16 +2392,19 @@ let BrowserOnClick = {
       this.onAboutCertError(originalTarget, ownerDoc);
     }
     else if (ownerDoc.documentURI.startsWith("about:blocked")) {
       this.onAboutBlocked(originalTarget, ownerDoc);
     }
     else if (ownerDoc.documentURI.startsWith("about:neterror")) {
       this.onAboutNetError(originalTarget, ownerDoc);
     }
+    else if (ownerDoc.documentURI.toLowerCase() == "about:home") {
+      this.onAboutHome(originalTarget, ownerDoc);
+    }
   },
 
   onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
     let elmId = aTargetElm.getAttribute("id");
     let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
     let isTopFrame = (aOwnerDoc.defaultView.parent === aOwnerDoc.defaultView);
 
     switch (elmId) {
@@ -2507,16 +2571,59 @@ let BrowserOnClick = {
   },
 
   onAboutNetError: function BrowserOnClick_onAboutNetError(aTargetElm, aOwnerDoc) {
     let elmId = aTargetElm.getAttribute("id");
     if (elmId != "errorTryAgain" || !/e=netOffline/.test(aOwnerDoc.documentURI))
       return;
     Services.io.offline = false;
   },
+
+  onAboutHome: function BrowserOnClick_onAboutHome(aTargetElm, aOwnerDoc) {
+    let elmId = aTargetElm.getAttribute("id");
+
+    switch (elmId) {
+      case "restorePreviousSession":
+        let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+                 getService(Ci.nsISessionStore);
+        if (ss.canRestoreLastSession) {
+          ss.restoreLastSession();
+        }
+        aOwnerDoc.getElementById("launcher").removeAttribute("session");
+        break;
+
+      case "downloads":
+        BrowserDownloadsUI();
+        break;
+
+      case "bookmarks":
+        PlacesCommandHook.showPlacesOrganizer("AllBookmarks");
+        break;
+
+      case "history":
+        PlacesCommandHook.showPlacesOrganizer("History");
+        break;
+
+      case "apps":
+        openUILinkIn("https://marketplace.mozilla.org/", "tab");
+        break;
+
+      case "addons":
+        BrowserOpenAddonsMgr();
+        break;
+
+      case "sync":
+        openPreferences("paneSync");
+        break;
+
+      case "settings":
+        openPreferences();
+        break;
+    }
+  },
 };
 
 /**
  * Re-direct the browser to a known-safe page.  This function is
  * used when, for example, the user browses to a known malware page
  * and is presented with about:blocked.  The "Get me out of here!"
  * button should take the user to the default start page so that even
  * when their own homepage is infected, we can get them somewhere safe.
@@ -4186,30 +4293,32 @@ var TabsProgressListener = {
     // document URI is not yet the about:-uri of the error page.
 
     let doc = gMultiProcessBrowser ? null : aWebProgress.DOMWindow.document;
     if (!gMultiProcessBrowser &&
         aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
         Components.isSuccessCode(aStatus) &&
         doc.documentURI.startsWith("about:") &&
         !doc.documentURI.toLowerCase().startsWith("about:blank") &&
-        !doc.documentURI.toLowerCase().startsWith("about:home") &&
         !doc.documentElement.hasAttribute("hasBrowserHandlers")) {
       // STATE_STOP may be received twice for documents, thus store an
       // attribute to ensure handling it just once.
       doc.documentElement.setAttribute("hasBrowserHandlers", "true");
       aBrowser.addEventListener("click", BrowserOnClick, true);
       aBrowser.addEventListener("pagehide", function onPageHide(event) {
         if (event.target.defaultView.frameElement)
           return;
         aBrowser.removeEventListener("click", BrowserOnClick, true);
         aBrowser.removeEventListener("pagehide", onPageHide, true);
         if (event.target.documentElement)
           event.target.documentElement.removeAttribute("hasBrowserHandlers");
       }, true);
+
+      // We also want to make changes to page UI for unprivileged about pages.
+      BrowserOnAboutPageLoad(doc);
     }
   },
 
   onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI,
                               aFlags) {
     // Filter out location changes caused by anchor navigation
     // or history.push/pop/replaceState.
     if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -8,18 +8,16 @@ let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this,
   "LoginManagerContent", "resource://gre/modules/LoginManagerContent.jsm");
 XPCOMUtils.defineLazyModuleGetter(this,
   "InsecurePasswordUtils", "resource://gre/modules/InsecurePasswordUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
-  "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 // Bug 671101 - directly using webNavigation in this context
 // causes docshells to leak
 this.__defineGetter__("webNavigation", function () {
   return docShell.QueryInterface(Ci.nsIWebNavigation);
 });
 
 addMessageListener("WebNavigation:LoadURI", function (message) {
@@ -52,136 +50,16 @@ if (Services.prefs.getBoolPref("browser.
   addEventListener("DOMAutoComplete", function(event) {
     LoginManagerContent.onUsernameInput(event);
   });
   addEventListener("blur", function(event) {
     LoginManagerContent.onUsernameInput(event);
   });
 }
 
-let AboutHomeListener = {
-  init: function(chromeGlobal) {
-    addMessageListener("AboutHome:Update", this);
-
-    let self = this;
-    chromeGlobal.addEventListener('AboutHomeLoad', function(e) { self.onPageLoad(); }, false, true);
-  },
-
-  receiveMessage: function(aMessage) {
-    switch (aMessage.name) {
-    case "AboutHome:Update":
-      this.onUpdate(aMessage.data);
-      break;
-    }
-  },
-
-  onUpdate: function(aData) {
-    let doc = content.document;
-    if (doc.documentURI.toLowerCase() != "about:home")
-      return;
-
-    if (aData.showRestoreLastSession && !PrivateBrowsingUtils.isWindowPrivate(content))
-      doc.getElementById("launcher").setAttribute("session", "true");
-
-    // Inject search engine and snippets URL.
-    let docElt = doc.documentElement;
-    // set the following attributes BEFORE searchEngineURL, which triggers to
-    // show the snippets when it's set.
-    docElt.setAttribute("snippetsURL", aData.snippetsURL);
-    if (aData.showKnowYourRights)
-      docElt.setAttribute("showKnowYourRights", "true");
-    docElt.setAttribute("snippetsVersion", aData.snippetsVersion);
-
-    let engine = aData.defaultSearchEngine;
-    docElt.setAttribute("searchEngineName", engine.name);
-    docElt.setAttribute("searchEnginePostData", engine.postDataString || "");
-    // Again, keep the searchEngineURL as the last attribute, because the
-    // mutation observer in aboutHome.js is counting on that.
-    docElt.setAttribute("searchEngineURL", engine.searchURL);
-  },
-
-  onPageLoad: function() {
-    let doc = content.document;
-    if (doc.documentURI.toLowerCase() != "about:home" ||
-        doc.documentElement.hasAttribute("hasBrowserHandlers")) {
-      return;
-    }
-
-    doc.documentElement.setAttribute("hasBrowserHandlers", "true");
-    addEventListener("click", this.onClick, true);
-    addEventListener("pagehide", function onPageHide(event) {
-      if (event.target.defaultView.frameElement)
-        return;
-      removeEventListener("click", this.onClick, true);
-      removeEventListener("pagehide", onPageHide, true);
-      if (event.target.documentElement)
-        event.target.documentElement.removeAttribute("hasBrowserHandlers");
-    }, true);
-
-    // XXX bug 738646 - when Marketplace is launched, remove this statement and
-    // the hidden attribute set on the apps button in aboutHome.xhtml
-    if (Services.prefs.getPrefType("browser.aboutHome.apps") == Services.prefs.PREF_BOOL &&
-        Services.prefs.getBoolPref("browser.aboutHome.apps"))
-      doc.getElementById("apps").removeAttribute("hidden");
-
-    sendAsyncMessage("AboutHome:RequestUpdate");
-
-    doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
-      sendAsyncMessage("AboutHome:Search", { engineName: e.detail });
-    }, true, true);
-  },
-
-  onClick: function(aEvent) {
-    if (!aEvent.isTrusted || // Don't trust synthetic events
-        aEvent.button == 2 || aEvent.target.localName != "button") {
-      return;
-    }
-
-    let originalTarget = aEvent.originalTarget;
-    let ownerDoc = originalTarget.ownerDocument;
-    let elmId = originalTarget.getAttribute("id");
-
-    switch (elmId) {
-      case "restorePreviousSession":
-        sendAsyncMessage("AboutHome:RestorePreviousSession");
-        ownerDoc.getElementById("launcher").removeAttribute("session");
-        break;
-
-      case "downloads":
-        sendAsyncMessage("AboutHome:Downloads");
-        break;
-
-      case "bookmarks":
-        sendAsyncMessage("AboutHome:Bookmarks");
-        break;
-
-      case "history":
-        sendAsyncMessage("AboutHome:History");
-        break;
-
-      case "apps":
-        sendAsyncMessage("AboutHome:Apps");
-        break;
-
-      case "addons":
-        sendAsyncMessage("AboutHome:Addons");
-        break;
-
-      case "sync":
-        sendAsyncMessage("AboutHome:Sync");
-        break;
-
-      case "settings":
-        sendAsyncMessage("AboutHome:Settings");
-        break;
-    }
-  },
-};
-AboutHomeListener.init(this);
-
 
 var global = this;
 
 let ClickEventHandler = {
   init: function init() {
     Cc["@mozilla.org/eventlistenerservice;1"]
       .getService(Ci.nsIEventListenerService)
       .addSystemEventListener(global, "click", this, true);
--- a/browser/base/content/test/browser_aboutHome.js
+++ b/browser/base/content/test/browser_aboutHome.js
@@ -2,17 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/commonjs/sdk/core/promise.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AboutHomeUtils",
-  "resource:///modules/AboutHome.jsm");
+  "resource:///modules/AboutHomeUtils.jsm");
 
 let gRightsVersion = Services.prefs.getIntPref("browser.rights.version");
 
 registerCleanupFunction(function() {
   // Ensure we don't pollute prefs for next tests.
   Services.prefs.clearUserPref("network.cookies.cookieBehavior");
   Services.prefs.clearUserPref("network.cookie.lifetimePolicy");
   Services.prefs.clearUserPref("browser.rights.override");
@@ -101,27 +101,24 @@ let gTests = [
       return Promise.resolve();
     }
 
     let numSearchesBefore = 0;
     let deferred = Promise.defer();
     let doc = gBrowser.contentDocument;
     let engineName = doc.documentElement.getAttribute("searchEngineName");
 
+    // We rely on the listener in browser.js being installed and fired before
+    // this one. If this ever changes, we should add an executeSoon() or similar.
     doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
       is(e.detail, engineName, "Detail is search engine name");
 
-      // We use executeSoon() to ensure that this code runs after the
-      // count has been updated in browser.js, since it uses the same
-      // event.
-      executeSoon(function () {
-        getNumberOfSearches(engineName).then(num => {
-          is(num, numSearchesBefore + 1, "One more search recorded.");
-          deferred.resolve();
-        });
+      getNumberOfSearches(engineName).then(num => {
+        is(num, numSearchesBefore + 1, "One more search recorded.");
+        deferred.resolve();
       });
     }, true, true);
 
     // Get the current number of recorded searches.
     getNumberOfSearches(engineName).then(num => {
       numSearchesBefore = num;
 
       info("Perform a search.");
@@ -273,52 +270,40 @@ let gTests = [
       info("Observer: " + aData + " for " + engine.name);
 
       if (aData != "engine-added")
         return;
 
       if (engine.name != "POST Search")
         return;
 
+      Services.search.defaultEngine = engine;
+
+      registerCleanupFunction(function() {
+        Services.search.removeEngine(engine);
+        Services.search.defaultEngine = currEngine;
+      });
+
+
       // Ready to execute the tests!
       let needle = "Search for something awesome.";
       let document = gBrowser.selectedTab.linkedBrowser.contentDocument;
       let searchText = document.getElementById("searchText");
 
-      // We're about to change the search engine. Once the change has
-      // propagated to the about:home content, we want to perform a search.
-      let mutationObserver = new MutationObserver(function (mutations) {
-        for (let mutation of mutations) {
-          if (mutation.attributeName == "searchEngineURL") {
-            searchText.value = needle;
-            searchText.focus();
-            EventUtils.synthesizeKey("VK_RETURN", {});
-          }
-        }
-      });
-      mutationObserver.observe(document.documentElement, { attributes: true });
-
-      // Change the search engine, triggering the observer above.
-      Services.search.defaultEngine = engine;
-
-      registerCleanupFunction(function() {
-        mutationObserver.disconnect();
-        Services.search.removeEngine(engine);
-        Services.search.defaultEngine = currEngine;
-      });
-
-
-      // When the search results load, check them for correctness.
       waitForLoad(function() {
         let loadedText = gBrowser.contentDocument.body.textContent;
         ok(loadedText, "search page loaded");
         is(loadedText, "searchterms=" + escape(needle.replace(/\s/g, "+")),
            "Search text should arrive correctly");
         deferred.resolve();
       });
+
+      searchText.value = needle;
+      searchText.focus();
+      EventUtils.synthesizeKey("VK_RETURN", {});
     };
     Services.obs.addObserver(searchObserver, "browser-search-engine-modified", false);
     registerCleanupFunction(function () {
       Services.obs.removeObserver(searchObserver, "browser-search-engine-modified");
     });
     Services.search.addEngine("http://test:80/browser/browser/base/content/test/POSTSearchEngine.xml",
                               Ci.nsISearchEngine.DATA_XML, null, false);
     return deferred.promise;
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -9,19 +9,16 @@ const Cr = Components.results;
 const Cu = Components.utils;
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/SignInToWebsite.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
-                                  "resource:///modules/AboutHome.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ContentClick",
                                   "resource:///modules/ContentClick.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
@@ -463,17 +460,16 @@ BrowserGlue.prototype = {
 
     webappsUI.init();
     PageThumbs.init();
     NewTabUtils.init();
     BrowserNewTabPreloader.init();
     SignInToWebsiteUX.init();
     PdfJs.init();
     webrtcUI.init();
-    AboutHome.init();
 
     if (Services.prefs.getBoolPref("browser.tabs.remote"))
       ContentClick.init();
 
     Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
   },
 
   _checkForOldBuildUpdates: function () {
rename from browser/modules/AboutHome.jsm
rename to browser/modules/AboutHomeUtils.jsm
--- a/browser/modules/AboutHome.jsm
+++ b/browser/modules/AboutHomeUtils.jsm
@@ -1,43 +1,36 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-let Cc = Components.classes;
-let Ci = Components.interfaces;
-let Cu = Components.utils;
-
-this.EXPORTED_SYMBOLS = [ "AboutHomeUtils", "AboutHome" ];
+this.EXPORTED_SYMBOLS = [ "AboutHomeUtils" ];
 
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
-  "resource://gre/modules/PrivateBrowsingUtils.jsm");
-
 // Url to fetch snippets, in the urlFormatter service format.
 const SNIPPETS_URL_PREF = "browser.aboutHomeSnippets.updateUrl";
 
 // Should be bumped up if the snippets content format changes.
 const STARTPAGE_VERSION = 4;
 
 this.AboutHomeUtils = {
   get snippetsVersion() STARTPAGE_VERSION,
 
   /**
    * Returns an object containing the name and searchURL of the original default
    * search engine.
    */
   get defaultSearchEngine() {
     let defaultEngine = Services.search.defaultEngine;
     let submission = defaultEngine.getSubmission("_searchTerms_", null, "homepage");
-
+  
     return Object.freeze({
       name: defaultEngine.name,
       searchURL: submission.uri.spec,
       postDataString: submission.postDataString
     });
   },
 
   /*
@@ -85,125 +78,8 @@ this.AboutHomeUtils = {
  * Returns the URL to fetch snippets from, in the urlFormatter service format.
  */
 XPCOMUtils.defineLazyGetter(AboutHomeUtils, "snippetsURL", function() {
   let updateURL = Services.prefs
                           .getCharPref(SNIPPETS_URL_PREF)
                           .replace("%STARTPAGE_VERSION%", STARTPAGE_VERSION);
   return Services.urlFormatter.formatURL(updateURL);
 });
-
-/**
- * This code provides services to the about:home page. Whenever
- * about:home needs to do something chrome-privileged, it sends a
- * message that's handled here.
- */
-let AboutHome = {
-  MESSAGES: [
-    "AboutHome:RestorePreviousSession",
-    "AboutHome:Downloads",
-    "AboutHome:Bookmarks",
-    "AboutHome:History",
-    "AboutHome:Apps",
-    "AboutHome:Addons",
-    "AboutHome:Sync",
-    "AboutHome:Settings",
-    "AboutHome:RequestUpdate",
-    "AboutHome:Search",
-  ],
-
-  init: function() {
-    let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
-
-    for (let msg of this.MESSAGES) {
-      mm.addMessageListener(msg, this);
-    }
-
-    Services.obs.addObserver(this, "browser-search-engine-modified", false);
-  },
-
-  observe: function(aEngine, aTopic, aVerb) {
-    switch (aTopic) {
-      case "browser-search-engine-modified":
-        this.sendAboutHomeData(null);
-        break;
-    }
-  },
-
-  receiveMessage: function(aMessage) {
-    let window = aMessage.target.ownerDocument.defaultView;
-
-    switch (aMessage.name) {
-      case "AboutHome:RestorePreviousSession":
-        let ss = Cc["@mozilla.org/browser/sessionstore;1"].
-                 getService(Ci.nsISessionStore);
-        if (ss.canRestoreLastSession) {
-          ss.restoreLastSession();
-        }
-        break;
-
-      case "AboutHome:Downloads":
-        window.BrowserDownloadsUI();
-        break;
-
-      case "AboutHome:Bookmarks":
-        window.PlacesCommandHook.showPlacesOrganizer("AllBookmarks");
-        break;
-
-      case "AboutHome:History":
-        window.PlacesCommandHook.showPlacesOrganizer("History");
-        break;
-
-      case "AboutHome:Apps":
-        window.openUILinkIn("https://marketplace.mozilla.org/", "tab");
-        break;
-
-      case "AboutHome:Addons":
-        window.BrowserOpenAddonsMgr();
-        break;
-
-      case "AboutHome:Sync":
-        window.openPreferences("paneSync");
-        break;
-
-      case "AboutHome:Settings":
-        window.openPreferences();
-        break;
-
-      case "AboutHome:RequestUpdate":
-        this.sendAboutHomeData(aMessage.target);
-        break;
-
-      case "AboutHome:Search":
-#ifdef MOZ_SERVICES_HEALTHREPORT
-        window.BrowserSearch.recordSearchInHealthReport(aMessage.data.engineName, "abouthome");
-#endif
-        break;
-    }
-  },
-
-  // Send all the chrome-privileged data needed by about:home. This
-  // gets re-sent when the search engine changes.
-  sendAboutHomeData: function(target) {
-    let ss = Cc["@mozilla.org/browser/sessionstore;1"].
-               getService(Ci.nsISessionStore);
-    let data = {
-      showRestoreLastSession: ss.canRestoreLastSession,
-      snippetsURL: AboutHomeUtils.snippetsURL,
-      showKnowYourRights: AboutHomeUtils.showKnowYourRights,
-      snippetsVersion: AboutHomeUtils.snippetsVersion,
-      defaultSearchEngine: AboutHomeUtils.defaultSearchEngine
-    };
-
-    if (AboutHomeUtils.showKnowYourRights) {
-      // Set pref to indicate we've shown the notification.
-      let currentVersion = Services.prefs.getIntPref("browser.rights.version");
-      Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true);
-    }
-
-    if (target) {
-      target.messageManager.sendAsyncMessage("AboutHome:Update", data);
-    } else {
-      let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
-      mm.broadcastAsyncMessage("AboutHome:Update", data);
-    }
-  },
-};
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -22,12 +22,12 @@ EXTRA_JS_MODULES += [
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXTRA_JS_MODULES += [
         'WindowsJumpLists.jsm',
         'WindowsPreviewPerTab.jsm',
     ]
 
 EXTRA_PP_JS_MODULES += [
-    'AboutHome.jsm',
+    'AboutHomeUtils.jsm',
     'RecentWindow.jsm',
 ]