michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict" michael@0: michael@0: const DEBUG = false; michael@0: function debug(s) { michael@0: if (DEBUG) dump("-*- SettingsChangeNotifier: " + s + "\n"); michael@0: } michael@0: michael@0: const Cu = Components.utils; michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: michael@0: this.EXPORTED_SYMBOLS = ["SettingsChangeNotifier"]; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: const kXpcomShutdownObserverTopic = "xpcom-shutdown"; michael@0: const kMozSettingsChangedObserverTopic = "mozsettings-changed"; michael@0: const kFromSettingsChangeNotifier = "fromSettingsChangeNotifier"; michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "ppmm", michael@0: "@mozilla.org/parentprocessmessagemanager;1", michael@0: "nsIMessageBroadcaster"); michael@0: michael@0: this.SettingsChangeNotifier = { michael@0: init: function() { michael@0: if (DEBUG) debug("init"); michael@0: this.children = []; michael@0: this._messages = ["Settings:Changed", "Settings:RegisterForMessages", "child-process-shutdown"]; michael@0: this._messages.forEach((function(msgName) { michael@0: ppmm.addMessageListener(msgName, this); michael@0: }).bind(this)); michael@0: michael@0: Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false); michael@0: Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false); michael@0: }, michael@0: michael@0: observe: function(aSubject, aTopic, aData) { michael@0: if (DEBUG) debug("observe"); michael@0: switch (aTopic) { michael@0: case kXpcomShutdownObserverTopic: michael@0: this._messages.forEach((function(msgName) { michael@0: ppmm.removeMessageListener(msgName, this); michael@0: }).bind(this)); michael@0: Services.obs.removeObserver(this, kXpcomShutdownObserverTopic); michael@0: Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic); michael@0: ppmm = null; michael@0: break; michael@0: case kMozSettingsChangedObserverTopic: michael@0: { michael@0: let setting = JSON.parse(aData); michael@0: // To avoid redundantly broadcasting settings-changed events that are michael@0: // just requested from content processes themselves, skip the observer michael@0: // messages that are notified from the internal SettingsChangeNotifier. michael@0: if (setting.message && setting.message === kFromSettingsChangeNotifier) michael@0: return; michael@0: this.broadcastMessage("Settings:Change:Return:OK", michael@0: { key: setting.key, value: setting.value }); michael@0: break; michael@0: } michael@0: default: michael@0: if (DEBUG) debug("Wrong observer topic: " + aTopic); michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: broadcastMessage: function broadcastMessage(aMsgName, aContent) { michael@0: if (DEBUG) debug("Broadast"); michael@0: this.children.forEach(function(msgMgr) { michael@0: msgMgr.sendAsyncMessage(aMsgName, aContent); michael@0: }); michael@0: }, michael@0: michael@0: receiveMessage: function(aMessage) { michael@0: if (DEBUG) debug("receiveMessage"); michael@0: let msg = aMessage.data; michael@0: let mm = aMessage.target; michael@0: switch (aMessage.name) { michael@0: case "Settings:Changed": michael@0: if (!aMessage.target.assertPermission("settings-write")) { michael@0: Cu.reportError("Settings message " + msg.name + michael@0: " from a content process with no 'settings-write' privileges."); michael@0: return null; michael@0: } michael@0: this.broadcastMessage("Settings:Change:Return:OK", michael@0: { key: msg.key, value: msg.value }); michael@0: Services.obs.notifyObservers(this, kMozSettingsChangedObserverTopic, michael@0: JSON.stringify({ michael@0: key: msg.key, michael@0: value: msg.value, michael@0: message: kFromSettingsChangeNotifier michael@0: })); michael@0: break; michael@0: case "Settings:RegisterForMessages": michael@0: if (!aMessage.target.assertPermission("settings-read")) { michael@0: Cu.reportError("Settings message " + msg.name + michael@0: " from a content process with no 'settings-read' privileges."); michael@0: return null; michael@0: } michael@0: if (DEBUG) debug("Register!"); michael@0: if (this.children.indexOf(mm) == -1) { michael@0: this.children.push(mm); michael@0: } michael@0: break; michael@0: case "child-process-shutdown": michael@0: if (DEBUG) debug("Unregister"); michael@0: let index; michael@0: if ((index = this.children.indexOf(mm)) != -1) { michael@0: if (DEBUG) debug("Unregister index: " + index); michael@0: this.children.splice(index, 1); michael@0: } michael@0: break; michael@0: default: michael@0: if (DEBUG) debug("Wrong message: " + aMessage.name); michael@0: } michael@0: } michael@0: } michael@0: michael@0: SettingsChangeNotifier.init();