summaryrefslogtreecommitdiffstats
path: root/toolkit/components/contentprefs/ContentPrefServiceParent.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/contentprefs/ContentPrefServiceParent.jsm')
-rw-r--r--toolkit/components/contentprefs/ContentPrefServiceParent.jsm137
1 files changed, 137 insertions, 0 deletions
diff --git a/toolkit/components/contentprefs/ContentPrefServiceParent.jsm b/toolkit/components/contentprefs/ContentPrefServiceParent.jsm
new file mode 100644
index 000000000..32e31a789
--- /dev/null
+++ b/toolkit/components/contentprefs/ContentPrefServiceParent.jsm
@@ -0,0 +1,137 @@
+/* vim: set ts=2 sw=2 sts=2 et tw=80: */
+/* 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";
+
+this.EXPORTED_SYMBOLS = [ "ContentPrefServiceParent" ];
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/ContentPrefUtils.jsm");
+
+var ContentPrefServiceParent = {
+ _cps2: null,
+
+ init: function() {
+ let globalMM = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+ .getService(Ci.nsIMessageListenerManager);
+
+ this._cps2 = Cc["@mozilla.org/content-pref/service;1"]
+ .getService(Ci.nsIContentPrefService2);
+
+ globalMM.addMessageListener("ContentPrefs:FunctionCall", this);
+
+ let observerChangeHandler = this.handleObserverChange.bind(this);
+ globalMM.addMessageListener("ContentPrefs:AddObserverForName", observerChangeHandler);
+ globalMM.addMessageListener("ContentPrefs:RemoveObserverForName", observerChangeHandler);
+ globalMM.addMessageListener("child-process-shutdown", observerChangeHandler);
+ },
+
+ // Map from message manager -> content pref observer.
+ _observers: new Map(),
+
+ handleObserverChange: function(msg) {
+ let observer = this._observers.get(msg.target);
+ if (msg.name === "child-process-shutdown") {
+ // If we didn't have any observers for this child process, don't do
+ // anything.
+ if (!observer)
+ return;
+
+ for (let i of observer._names) {
+ this._cps2.removeObserverForName(i, observer);
+ }
+
+ this._observers.delete(msg.target);
+ return;
+ }
+
+ let prefName = msg.data.name;
+ if (msg.name === "ContentPrefs:AddObserverForName") {
+ // The child process is responsible for not adding multiple parent
+ // observers for the same name.
+ if (!observer) {
+ observer = {
+ onContentPrefSet: function(group, name, value, isPrivate) {
+ msg.target.sendAsyncMessage("ContentPrefs:NotifyObservers",
+ { name: name, callback: "onContentPrefSet",
+ args: [ group, name, value, isPrivate ] });
+ },
+
+ onContentPrefRemoved: function(group, name, isPrivate) {
+ msg.target.sendAsyncMessage("ContentPrefs:NotifyObservers",
+ { name: name, callback: "onContentPrefRemoved",
+ args: [ group, name, isPrivate ] });
+ },
+
+ // The names we're using this observer object for, used to keep track
+ // of the number of names we care about as well as for removing this
+ // observer if its associated process goes away.
+ _names: new Set()
+ };
+
+ this._observers.set(msg.target, observer);
+ }
+
+ observer._names.add(prefName);
+
+ this._cps2.addObserverForName(prefName, observer);
+ } else {
+ // RemoveObserverForName
+
+ // We must have an observer.
+ this._cps2.removeObserverForName(prefName, observer);
+
+ observer._names.delete(prefName);
+ if (observer._names.size === 0) {
+ // This was the last use for this observer.
+ this._observers.delete(msg.target);
+ }
+ }
+ },
+
+ receiveMessage: function(msg) {
+ let data = msg.data;
+
+ if (!_methodsCallableFromChild.some(([method, args]) => method == data.call)) {
+ throw new Error(`Can't call ${data.call} from child!`);
+ }
+
+ let args = data.args;
+ let requestId = data.requestId;
+
+ let listener = {
+ handleResult: function(pref) {
+ msg.target.sendAsyncMessage("ContentPrefs:HandleResult",
+ { requestId: requestId,
+ contentPref: {
+ domain: pref.domain,
+ name: pref.name,
+ value: pref.value
+ }
+ });
+ },
+
+ handleError: function(error) {
+ msg.target.sendAsyncMessage("ContentPrefs:HandleError",
+ { requestId: requestId,
+ error: error });
+ },
+ handleCompletion: function(reason) {
+ msg.target.sendAsyncMessage("ContentPrefs:HandleCompletion",
+ { requestId: requestId,
+ reason: reason });
+ }
+ };
+
+ // Push our special listener.
+ args.push(listener);
+
+ // And call the function.
+ this._cps2[data.call](...args);
+ }
+};