diff options
Diffstat (limited to 'toolkit/components/contentprefs/ContentPrefServiceParent.jsm')
-rw-r--r-- | toolkit/components/contentprefs/ContentPrefServiceParent.jsm | 137 |
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); + } +}; |