2014-06-30 14:16:00 +04:00
|
|
|
/* 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';
|
|
|
|
|
2014-10-13 10:43:00 +04:00
|
|
|
this.EXPORTED_SYMBOLS = ['Frames'];
|
2014-06-30 14:16:00 +04:00
|
|
|
|
|
|
|
const Cu = Components.utils;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
|
|
|
|
Cu.import('resource://gre/modules/Services.jsm');
|
|
|
|
Cu.import('resource://gre/modules/SystemAppProxy.jsm');
|
|
|
|
|
|
|
|
const listeners = [];
|
|
|
|
|
|
|
|
const Observer = {
|
|
|
|
// Save a map of (MessageManager => Frame) to be able to dispatch
|
|
|
|
// the FrameDestroyed event with a frame reference.
|
|
|
|
_frames: new Map(),
|
|
|
|
|
|
|
|
// Also save current number of iframes opened by app
|
|
|
|
_apps: new Map(),
|
|
|
|
|
|
|
|
start: function () {
|
|
|
|
Services.obs.addObserver(this, 'remote-browser-shown', false);
|
|
|
|
Services.obs.addObserver(this, 'inprocess-browser-shown', false);
|
2015-03-19 07:51:34 +03:00
|
|
|
Services.obs.addObserver(this, 'message-manager-disconnect', false);
|
2014-06-30 14:16:00 +04:00
|
|
|
|
2014-10-13 10:43:00 +04:00
|
|
|
SystemAppProxy.getFrames().forEach(frame => {
|
2014-06-30 14:16:00 +04:00
|
|
|
let mm = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
|
|
|
|
this._frames.set(mm, frame);
|
|
|
|
let mozapp = frame.getAttribute('mozapp');
|
2014-10-13 10:43:00 +04:00
|
|
|
if (mozapp) {
|
|
|
|
this._apps.set(mozapp, (this._apps.get(mozapp) || 0) + 1);
|
|
|
|
}
|
2014-06-30 14:16:00 +04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
stop: function () {
|
|
|
|
Services.obs.removeObserver(this, 'remote-browser-shown');
|
|
|
|
Services.obs.removeObserver(this, 'inprocess-browser-shown');
|
2015-03-19 07:51:34 +03:00
|
|
|
Services.obs.removeObserver(this, 'message-manager-disconnect');
|
2014-06-30 14:16:00 +04:00
|
|
|
this._frames.clear();
|
|
|
|
this._apps.clear();
|
|
|
|
},
|
|
|
|
|
|
|
|
observe: function (subject, topic, data) {
|
|
|
|
switch(topic) {
|
|
|
|
|
|
|
|
// Listen for frame creation in OOP (device) as well as in parent process (b2g desktop)
|
|
|
|
case 'remote-browser-shown':
|
|
|
|
case 'inprocess-browser-shown':
|
|
|
|
let frameLoader = subject;
|
|
|
|
|
|
|
|
// get a ref to the app <iframe>
|
|
|
|
frameLoader.QueryInterface(Ci.nsIFrameLoader);
|
|
|
|
let frame = frameLoader.ownerElement;
|
|
|
|
let mm = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
|
|
|
|
this.onMessageManagerCreated(mm, frame);
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Every time an iframe is destroyed, its message manager also is
|
2015-03-19 07:51:34 +03:00
|
|
|
case 'message-manager-disconnect':
|
2014-06-30 14:16:00 +04:00
|
|
|
this.onMessageManagerDestroyed(subject);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
onMessageManagerCreated: function (mm, frame) {
|
|
|
|
this._frames.set(mm, frame);
|
|
|
|
|
2014-10-13 10:43:00 +04:00
|
|
|
let isFirstAppFrame = null;
|
2014-06-30 14:16:00 +04:00
|
|
|
let mozapp = frame.getAttribute('mozapp');
|
2014-10-13 10:43:00 +04:00
|
|
|
if (mozapp) {
|
|
|
|
let count = (this._apps.get(mozapp) || 0) + 1;
|
|
|
|
this._apps.set(mozapp, count);
|
|
|
|
isFirstAppFrame = (count === 1);
|
|
|
|
}
|
2014-06-30 14:16:00 +04:00
|
|
|
|
|
|
|
listeners.forEach(function (listener) {
|
|
|
|
try {
|
2014-10-13 10:43:00 +04:00
|
|
|
listener.onFrameCreated(frame, isFirstAppFrame);
|
2014-06-30 14:16:00 +04:00
|
|
|
} catch(e) {
|
2014-10-13 10:43:00 +04:00
|
|
|
dump('Exception while calling Frames.jsm listener:' + e + '\n' +
|
|
|
|
e.stack + '\n');
|
2014-06-30 14:16:00 +04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
onMessageManagerDestroyed: function (mm) {
|
|
|
|
let frame = this._frames.get(mm);
|
|
|
|
if (!frame) {
|
2014-10-13 10:43:00 +04:00
|
|
|
// We received an event for an unknown message manager
|
2014-06-30 14:16:00 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this._frames.delete(mm);
|
|
|
|
|
2014-10-13 10:43:00 +04:00
|
|
|
let isLastAppFrame = null;
|
2014-06-30 14:16:00 +04:00
|
|
|
let mozapp = frame.getAttribute('mozapp');
|
2014-10-13 10:43:00 +04:00
|
|
|
if (mozapp) {
|
|
|
|
let count = (this._apps.get(mozapp) || 0) - 1;
|
|
|
|
this._apps.set(mozapp, count);
|
|
|
|
isLastAppFrame = (count === 0);
|
|
|
|
}
|
2014-06-30 14:16:00 +04:00
|
|
|
|
|
|
|
listeners.forEach(function (listener) {
|
|
|
|
try {
|
2014-10-13 10:43:00 +04:00
|
|
|
listener.onFrameDestroyed(frame, isLastAppFrame);
|
2014-06-30 14:16:00 +04:00
|
|
|
} catch(e) {
|
2014-10-13 10:43:00 +04:00
|
|
|
dump('Exception while calling Frames.jsm listener:' + e + '\n' +
|
|
|
|
e.stack + '\n');
|
2014-06-30 14:16:00 +04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2014-10-13 10:43:00 +04:00
|
|
|
let Frames = this.Frames = {
|
2014-06-30 14:16:00 +04:00
|
|
|
|
2014-10-13 10:43:00 +04:00
|
|
|
list: () => SystemAppProxy.getFrames(),
|
2014-06-30 14:16:00 +04:00
|
|
|
|
|
|
|
addObserver: function (listener) {
|
|
|
|
if (listeners.indexOf(listener) !== -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
listeners.push(listener);
|
|
|
|
if (listeners.length == 1) {
|
|
|
|
Observer.start();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
removeObserver: function (listener) {
|
|
|
|
let idx = listeners.indexOf(listener);
|
|
|
|
if (idx !== -1) {
|
|
|
|
listeners.splice(idx, 1);
|
|
|
|
}
|
|
|
|
if (listeners.length === 0) {
|
|
|
|
Observer.stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|