gecko-dev/dom/settings/SettingsChangeNotifier.jsm

124 lines
4.3 KiB
JavaScript

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