Bug 1342712 - Allow scoping a theme per-window. r=jaws draft
authorTim Nguyen <ntim.bugs@gmail.com>
Fri, 04 Aug 2017 20:08:57 +0000
changeset 621428 4f82c2bc8c1fabb5fac14f79bdc0e148ba8a6304
parent 621399 4cfb674227051e22bab651e5759f3de503a50560
child 724666 8ab0d9115ce51e8eca0e48439f9b1eafc7951941
push id72375
push userbmo:ntim.bugs@gmail.com
push dateFri, 04 Aug 2017 20:09:04 +0000
reviewersjaws
bugs1342712
milestone57.0a1
Bug 1342712 - Allow scoping a theme per-window. r=jaws MozReview-Commit-ID: FYsmgz5qAjx
toolkit/components/extensions/ext-theme.js
toolkit/components/extensions/schemas/theme.json
toolkit/modules/LightweightThemeConsumer.jsm
--- a/toolkit/components/extensions/ext-theme.js
+++ b/toolkit/components/extensions/ext-theme.js
@@ -1,10 +1,12 @@
 "use strict";
 
+/* global windowTracker */
+
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gThemesEnabled", () => {
   return Services.prefs.getBoolPref("extensions.webextensions.themes.enabled");
 });
@@ -31,18 +33,26 @@ class Theme {
   }
 
   /**
    * Loads a theme by reading the properties from the extension's manifest.
    * This method will override any currently applied theme.
    *
    * @param {Object} details Theme part of the manifest. Supported
    *   properties can be found in the schema under ThemeType.
+   * @param {Object} targetWindow The window to apply the theme to. Omitting
+   *   this parameter will apply the theme globally.
    */
-  load(details) {
+  load(details, targetWindow) {
+    if (targetWindow) {
+      this.lwtStyles.window = targetWindow
+        .QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+    }
+
     if (details.colors) {
       this.loadColors(details.colors);
     }
 
     if (details.images) {
       this.loadImages(details.images);
     }
 
@@ -268,30 +278,34 @@ this.theme = class extends ExtensionAPI 
     }
   }
 
   getAPI(context) {
     let {extension} = context;
 
     return {
       theme: {
-        update: (details) => {
+        update: (windowId, details) => {
           if (!gThemesEnabled) {
             // Return early if themes are disabled.
             return;
           }
 
           if (!this.theme) {
             // WebExtensions using the Theme API will not have a theme defined
             // in the manifest. Therefore, we need to initialize the theme the
             // first time browser.theme.update is called.
             this.theme = new Theme(extension.baseURI, extension.logger);
           }
 
-          this.theme.load(details);
+          let browserWindow;
+          if (windowId !== null) {
+            browserWindow = windowTracker.getWindow(windowId, context);
+          }
+          this.theme.load(details, browserWindow);
         },
         reset: () => {
           if (!gThemesEnabled) {
             // Return early if themes are disabled.
             return;
           }
 
           if (!this.theme) {
--- a/toolkit/components/extensions/schemas/theme.json
+++ b/toolkit/components/extensions/schemas/theme.json
@@ -452,16 +452,22 @@
     "functions": [
       {
         "name": "update",
         "type": "function",
         "async": true,
         "description": "Make complete or partial updates to the theme. Resolves when the update has completed.",
         "parameters": [
           {
+            "type": "integer",
+            "name": "windowId",
+            "optional": true,
+            "description": "The id of the window to update. No id updates all windows."
+          },
+          {
             "name": "details",
             "$ref": "manifest.ThemeType",
             "description": "The properties of the theme to update."
           }
         ]
       },
       {
         "name": "reset",
--- a/toolkit/modules/LightweightThemeConsumer.jsm
+++ b/toolkit/modules/LightweightThemeConsumer.jsm
@@ -1,15 +1,15 @@
 /* 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/. */
 
 this.EXPORTED_SYMBOLS = ["LightweightThemeConsumer"];
 
-const {utils: Cu} = Components;
+const {utils: Cu, interfaces: Ci, classes: Cc} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeImageOptimizer",
   "resource://gre/modules/addons/LightweightThemeImageOptimizer.jsm");
 
@@ -61,17 +61,26 @@ LightweightThemeConsumer.prototype = {
   getData() {
     return this._enabled ? Cu.cloneInto(this._lastData, this._win) : null;
   },
 
   observe(aSubject, aTopic, aData) {
     if (aTopic != "lightweight-theme-styling-update")
       return;
 
-    this._update(JSON.parse(aData));
+    const { outerWindowID } = this._win
+      .QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils);
+
+    const parsedData = JSON.parse(aData);
+    if (parsedData.window && parsedData.window !== outerWindowID) {
+      return;
+    }
+
+    this._update(parsedData);
   },
 
   handleEvent(aEvent) {
     let {width, height} = this._win.screen;
 
     if (this._lastScreenWidth != width || this._lastScreenHeight != height) {
       this._lastScreenWidth = width;
       this._lastScreenHeight = height;