b2g/components/SystemAppProxy.jsm
author Mike Hommey <mh+mozilla@glandium.org>
Thu, 30 Oct 2014 13:06:12 +0900
changeset 213063 55d15b285436576e1c5979f753e433c50fd9db3a
parent 210303 7d7d64553c684fb913c0d53d7e49813da15d0c0b
child 217730 dcdd75b0017f82909c02f76b72812106ed3f9535
permissions -rw-r--r--
Bug 1077148 part 4 - Add and use new moz.build templates for Gecko programs and libraries. r=gps There are, sadly, many combinations of linkage in use throughout the tree. The main differentiator, though, is between program/libraries related to Gecko or not. Kind of. Some need mozglue, some don't. Some need dependent linkage, some standalone. Anyways, these new templates remove the need to manually define the right dependencies against xpcomglue, nspr, mozalloc and mozglue in most cases. Places that build programs and were resetting MOZ_GLUE_PROGRAM_LDFLAGS or that build libraries and were resetting MOZ_GLUE_LDFLAGS can now just not use those Gecko-specific templates.

/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;

Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.import('resource://gre/modules/Services.jsm');

this.EXPORTED_SYMBOLS = ['SystemAppProxy'];

let SystemAppProxy = {
  _frame: null,
  _isReady: false,
  _pendingEvents: [],
  _pendingListeners: [],

  // To call when a new system app iframe is created
  registerFrame: function (frame) {
    this._isReady = false;
    this._frame = frame;

    // Register all DOM event listeners added before we got a ref to the app iframe
    this._pendingListeners
        .forEach((args) =>
                 this.addEventListener.apply(this, args));
    this._pendingListeners = [];
  },

  // To call when it is ready to receive events
  setIsReady: function () {
    if (this._isReady) {
      Cu.reportError('SystemApp has already been declared as being ready.');
    }
    this._isReady = true;

    // Dispatch all events being queued while the system app was still loading
    this._pendingEvents
        .forEach(([type, details]) =>
                 this._sendCustomEvent(type, details));
    this._pendingEvents = [];
  },

  /*
   * Common way to send an event to the system app.
   *
   * // In gecko code:
   *   SystemAppProxy.sendCustomEvent('foo', { data: 'bar' });
   * // In system app:
   *   window.addEventListener('foo', function (event) {
   *     event.details == 'bar'
   *   });
   *
   *   @param type      The custom event type.
   *   @param details   The event details.
   *   @param noPending Set to true to emit this event even before the system
   *                    app is ready.
   */
  _sendCustomEvent: function systemApp_sendCustomEvent(type,
                                                       details,
                                                       noPending,
                                                       target) {
    let content = this._frame ? this._frame.contentWindow : null;

    // If the system app isn't ready yet,
    // queue events until someone calls setIsReady
    if (!content || (!this._isReady && !noPending)) {
      this._pendingEvents.push([type, details]);
      return null;
    }

    let event = content.document.createEvent('CustomEvent');

    let payload;
    // If the root object already has __exposedProps__,
    // we consider the caller already wrapped (correctly) the object.
    if ('__exposedProps__' in details) {
      payload = details;
    } else {
      payload = details ? Cu.cloneInto(details, content) : {};
    }

    event.initCustomEvent(type, true, false, payload);
    (target || content).dispatchEvent(event);

    return event;
  },

  // Now deprecated, use sendCustomEvent with a custom event name
  dispatchEvent: function systemApp_sendChromeEvent(details, target) {
    return this._sendCustomEvent('mozChromeEvent', details, false, target);
  },

  // Listen for dom events on the system app
  addEventListener: function systemApp_addEventListener() {
    let content = this._frame ? this._frame.contentWindow : null;
    if (!content) {
      this._pendingListeners.push(arguments);
      return false;
    }

    content.addEventListener.apply(content, arguments);
    return true;
  },

  removeEventListener: function systemApp_removeEventListener(name, listener) {
    let content = this._frame ? this._frame.contentWindow : null;
    if (content) {
      content.removeEventListener.apply(content, arguments);
    } else {
      this._pendingListeners = this._pendingListeners.filter(
        args => {
          return args[0] != name || args[1] != listener;
        });
    }
  },

  getFrames: function systemApp_getFrames() {
    let systemAppFrame = this._frame;
    if (!systemAppFrame) {
      return [];
    }
    let list = [systemAppFrame];
    let frames = systemAppFrame.contentDocument.querySelectorAll('iframe');
    for (let i = 0; i < frames.length; i++) {
      list.push(frames[i]);
    }
    return list;
  }
};
this.SystemAppProxy = SystemAppProxy;