diff -r 000000000000 -r 6474c204b198 dom/settings/SettingsChangeNotifier.jsm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/settings/SettingsChangeNotifier.jsm Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,123 @@ +/* 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" + +const DEBUG = false; +function debug(s) { + if (DEBUG) dump("-*- SettingsChangeNotifier: " + s + "\n"); +} + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; + +this.EXPORTED_SYMBOLS = ["SettingsChangeNotifier"]; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +const kXpcomShutdownObserverTopic = "xpcom-shutdown"; +const kMozSettingsChangedObserverTopic = "mozsettings-changed"; +const kFromSettingsChangeNotifier = "fromSettingsChangeNotifier"; + +XPCOMUtils.defineLazyServiceGetter(this, "ppmm", + "@mozilla.org/parentprocessmessagemanager;1", + "nsIMessageBroadcaster"); + +this.SettingsChangeNotifier = { + init: function() { + if (DEBUG) debug("init"); + this.children = []; + this._messages = ["Settings:Changed", "Settings:RegisterForMessages", "child-process-shutdown"]; + this._messages.forEach((function(msgName) { + ppmm.addMessageListener(msgName, this); + }).bind(this)); + + Services.obs.addObserver(this, kXpcomShutdownObserverTopic, false); + Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false); + }, + + observe: function(aSubject, aTopic, aData) { + if (DEBUG) debug("observe"); + switch (aTopic) { + case kXpcomShutdownObserverTopic: + this._messages.forEach((function(msgName) { + ppmm.removeMessageListener(msgName, this); + }).bind(this)); + Services.obs.removeObserver(this, kXpcomShutdownObserverTopic); + Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic); + ppmm = null; + break; + case kMozSettingsChangedObserverTopic: + { + let setting = JSON.parse(aData); + // To avoid redundantly broadcasting settings-changed events that are + // just requested from content processes themselves, skip the observer + // messages that are notified from the internal SettingsChangeNotifier. + if (setting.message && setting.message === kFromSettingsChangeNotifier) + return; + this.broadcastMessage("Settings:Change:Return:OK", + { key: setting.key, value: setting.value }); + break; + } + default: + if (DEBUG) debug("Wrong observer topic: " + aTopic); + break; + } + }, + + broadcastMessage: function broadcastMessage(aMsgName, aContent) { + if (DEBUG) debug("Broadast"); + this.children.forEach(function(msgMgr) { + msgMgr.sendAsyncMessage(aMsgName, aContent); + }); + }, + + receiveMessage: function(aMessage) { + if (DEBUG) debug("receiveMessage"); + let msg = aMessage.data; + let mm = aMessage.target; + switch (aMessage.name) { + case "Settings:Changed": + if (!aMessage.target.assertPermission("settings-write")) { + Cu.reportError("Settings message " + msg.name + + " from a content process with no 'settings-write' privileges."); + return null; + } + this.broadcastMessage("Settings:Change:Return:OK", + { key: msg.key, value: msg.value }); + Services.obs.notifyObservers(this, kMozSettingsChangedObserverTopic, + JSON.stringify({ + key: msg.key, + value: msg.value, + message: kFromSettingsChangeNotifier + })); + break; + case "Settings:RegisterForMessages": + if (!aMessage.target.assertPermission("settings-read")) { + Cu.reportError("Settings message " + msg.name + + " from a content process with no 'settings-read' privileges."); + return null; + } + if (DEBUG) debug("Register!"); + if (this.children.indexOf(mm) == -1) { + this.children.push(mm); + } + break; + case "child-process-shutdown": + if (DEBUG) debug("Unregister"); + let index; + if ((index = this.children.indexOf(mm)) != -1) { + if (DEBUG) debug("Unregister index: " + index); + this.children.splice(index, 1); + } + break; + default: + if (DEBUG) debug("Wrong message: " + aMessage.name); + } + } +} + +SettingsChangeNotifier.init();