addon-sdk/source/lib/sdk/input/system.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     4 "use strict";
     6 const { Cc, Ci, Cr, Cu } = require("chrome");
     7 const { Input, start, stop, end, receive, outputs } = require("../event/utils");
     8 const { once, off } = require("../event/core");
     9 const { id: addonID } = require("../self");
    11 const unloadMessage = require("@loader/unload");
    12 const { addObserver, removeObserver } = Cc['@mozilla.org/observer-service;1'].
    13                                           getService(Ci.nsIObserverService);
    15 const addonUnloadTopic = "sdk:loader:destroy";
    17 const isXrayWrapper = Cu.isXrayWrapper;
    18 // In the past SDK used to double-wrap notifications dispatched, which
    19 // made them awkward to use outside of SDK. At present they no longer
    20 // do that, although we still supported for legacy reasons.
    21 const isLegacyWrapper = x =>
    22     x && x.wrappedJSObject &&
    23     "observersModuleSubjectWrapper" in x.wrappedJSObject;
    25 const unwrapLegacy = x => x.wrappedJSObject.object;
    27 // `InputPort` provides a way to create a signal out of the observer
    28 // notification subject's for the given `topic`. If `options.initial`
    29 // is provided it is used as initial value otherwise `null` is used.
    30 // Constructor can be given `options.id` that will be used to create
    31 // a `topic` which is namespaced to an add-on (this avoids conflicts
    32 // when multiple add-on are used, although in a future host probably
    33 // should just be shared across add-ons). It is also possible to
    34 // specify a specific `topic` via `options.topic` which is used as
    35 // without namespacing. Created signal ends whenever add-on is
    36 // unloaded.
    37 const InputPort = function InputPort({id, topic, initial}) {
    38   this.id = id || topic;
    39   this.topic = topic || "sdk:" + addonID + ":" + id;
    40   this.value = initial === void(0) ? null : initial;
    41   this.observing = false;
    42   this[outputs] = [];
    43 };
    45 // InputPort type implements `Input` signal interface.
    46 InputPort.prototype = new Input();
    47 InputPort.prototype.constructor = InputPort;
    49 // When port is started (which is when it's subgraph get's
    50 // first subscriber) actual observer is registered.
    51 InputPort.start = input => {
    52   input.addListener(input);
    53   // Also register add-on unload observer to end this signal
    54   // when that happens.
    55   addObserver(input, addonUnloadTopic, false);
    56 };
    57 InputPort.prototype[start] = InputPort.start;
    59 InputPort.addListener = input => addObserver(input, input.topic, false);
    60 InputPort.prototype.addListener = InputPort.addListener;
    62 // When port is stopped (which is when it's subgraph has no
    63 // no subcribers left) an actual observer unregistered.
    64 // Note that port stopped once it ends as well (which is when
    65 // add-on is unloaded).
    66 InputPort.stop = input => {
    67   input.removeListener(input);
    68   removeObserver(input, addonUnloadTopic);
    69 };
    70 InputPort.prototype[stop] = InputPort.stop;
    72 InputPort.removeListener = input => removeObserver(input, input.topic);
    73 InputPort.prototype.removeListener = InputPort.removeListener;
    75 // `InputPort` also implements `nsIObserver` interface and
    76 // `nsISupportsWeakReference` interfaces as it's going to be used as such.
    77 InputPort.prototype.QueryInterface = function(iid) {
    78   if (!iid.equals(Ci.nsIObserver) && !iid.equals(Ci.nsISupportsWeakReference))
    79     throw Cr.NS_ERROR_NO_INTERFACE;
    81   return this;
    82 };
    84 // `InputPort` instances implement `observe` method, which is invoked when
    85 // observer notifications are dispatched. The `subject` of that notification
    86 // are received on this signal.
    87 InputPort.prototype.observe = function(subject, topic, data) {
    88   // Unwrap message from the subject. SDK used to have it's own version of
    89   // wrappedJSObjects which take precedence, if subject has `wrappedJSObject`
    90   // and it's not an XrayWrapper use it as message. Otherwise use subject as
    91   // is.
    92   const message = subject === null ? null :
    93         isLegacyWrapper(subject) ? unwrapLegacy(subject) :
    94         isXrayWrapper(subject) ? subject :
    95         subject.wrappedJSObject ? subject.wrappedJSObject :
    96         subject;
    98   // If observer topic matches topic of the input port receive a message.
    99   if (topic === this.topic) {
   100     receive(this, message);
   101   }
   103   // If observe topic is add-on unload topic we create an end message.
   104   if (topic === addonUnloadTopic && message === unloadMessage) {
   105     end(this);
   106   }
   107 };
   109 exports.InputPort = InputPort;

mercurial