/* 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();