Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View file

@ -0,0 +1,260 @@
/* global ActionMenu, BaseModule, LazyLoader, BroadcastChannel */
'use strict';
(function() {
var MultiScreenController = function() {};
MultiScreenController.SERVICES = [
'chooseDisplay'
];
MultiScreenController.EVENTS = [
'mozChromeEvent'
];
MultiScreenController.SETTINGS = [
'multiscreen.enabled'
];
MultiScreenController.STATES = [
'enabled'
];
BaseModule.create(MultiScreenController, {
name: 'MultiScreenController',
EVENT_PREFIX: 'remote-',
DEBUG: false,
enabled: function() {
return this._enabled;
},
chooseDisplay: function(config) {
this.debug('chooseDisplay is invoked');
if (!this._enabled) {
this.debug('multi-screen is disabled');
return Promise.reject();
}
if (config.isSystemMessage || config.stayBackground) {
this.debug('unsupported config: ' + JSON.stringify(config));
return Promise.reject();
}
return this.queryExternalDisplays()
.then(this.showMenu.bind(this))
.then((displayId) => {
this.debug('chosen display id: ' + displayId);
if (!displayId) {
return Promise.reject();
}
this.postMessage(displayId, 'launch-app', config);
return Promise.resolve(displayId);
});
},
choosePresentationDevice: function() {
this.debug('chooseDisplay for presentation device selection');
var deviceList = [];
return this.queryPresentationDevices()
.then((list) => {
deviceList = list.map((device, idx) => {
return {
name: device.name,
deviceId: device.id,
id: idx,
};
});
return Promise.resolve(deviceList);
})
.then(this.showMenu.bind(this))
.then((displayId) => {
this.debug('chosen display id: ' + displayId);
if (isNaN(displayId)) {
return Promise.reject();
}
return Promise.resolve(deviceList.find((device) => {
return device.id == displayId;
}).deviceId);
});
},
showMenu: function(displays) {
this.debug('showMenu is invoked');
if (this.actionMenu) {
this.debug('actionMenu is busy');
return Promise.reject();
}
if (!displays.length) {
this.debug('no external display so cancel the menu directly');
return Promise.resolve();
}
return new Promise((resolve, reject) => {
LazyLoader.load('js/action_menu.js', () => {
this.actionMenu = new ActionMenu({
successCb: (choice) => {
this.actionMenu = null;
resolve(choice);
},
cancelCb: () => {
this.actionMenu = null;
resolve();
}
});
this.actionMenu.show(displays.map(function(display) {
return {
label: display.name,
value: display.id
};
}), 'multiscreen-pick');
});
});
},
queryExternalDisplays: function() {
this.debug('queryExternalDisplays is invoked');
if (this.queryPromiseCallback) {
this.debug('there\'s a pending query');
return Promise.reject();
}
return new Promise((resolve, reject) => {
this.debug('sending mozContentEvent');
this.queryPromiseCallback = {
resolve: resolve,
reject: reject
};
window.dispatchEvent(new CustomEvent('mozContentEvent', {
detail: {
type: 'get-display-list'
}
}));
});
},
queryPresentationDevices: function() {
this.debug('queryPresentationDevices is invoked');
return navigator.mozPresentationDeviceInfo.getAll();
},
postMessage: function(target, type, detail) {
this.debug('broadcast message to #' + target + ': ' +
type + ', ' + JSON.stringify(detail));
this.broadcastChannel.postMessage({
target: target,
type: type,
detail: detail
});
},
_start: function() {
this._enabled = false;
this.actionMenu = null;
this.queryPromiseCallback = null;
this.broadcastChannel = new BroadcastChannel('multiscreen');
this.broadcastChannel.addEventListener('message', this);
},
_stop: function() {
this._enabled = false;
this.broadcastChannel.close();
this.broadcastChannel = null;
if (this.queryPromiseCallback) {
this.queryPromiseCallback.reject('module has been stoped');
this.queryPromiseCallback = null;
}
if (this.actionMenu) {
this.actionMenu.hide();
if (this.actionMenu.oncancel) {
this.actionMenu.oncancel();
}
this.actionMenu = null;
}
},
_handle_mozChromeEvent: function(evt) {
var detail = evt.detail;
switch (detail.type) {
case 'presentation-select-device':
this._presentationDeviceSelectionHandler(detail);
break;
case 'get-display-list-success':
case 'get-display-list-error':
this._displayListResultHandler(detail);
break;
}
},
_presentationDeviceSelectionHandler: function(detail) {
this.debug('handle presentation-select-device event');
this.choosePresentationDevice(null)
.then((deviceId) => {
window.dispatchEvent(new CustomEvent('mozContentEvent', {
detail: {
'type': 'presentation-select-result',
'deviceId': deviceId,
'id': detail.id,
}
}));
}).catch(() => {
window.dispatchEvent(new CustomEvent('mozContentEvent', {
detail: {
'type': 'presentation-select-deny',
'id': detail.id
}
}));
});
},
_displayListResultHandler: function(detail) {
if (!this.queryPromiseCallback) {
return;
}
switch (detail.type) {
case 'get-display-list-success':
this.queryPromiseCallback.resolve(detail.display);
break;
case 'get-display-list-error':
this.queryPromiseCallback.reject(detail.error);
break;
default:
return;
}
this.queryPromiseCallback = null;
this.debug('got mozChromeEvent: ' + JSON.stringify(detail));
},
_handle_message: function(evt) {
var data = evt.data;
if (data.target !== undefined) {
return;
}
this.debug('got message from #' + data.source + ': ' +
data.type + ', ' + JSON.stringify(data.detail));
switch(data.type) {
case 'launch-app-success':
case 'launch-app-error':
this.publish(data.type, {
displayId: data.source,
config: data.detail.config,
reason: data.detail.reason
});
break;
}
},
'_observe_multiscreen.enabled': function(value) {
if (value == this._enabled) {
return;
}
this._enabled = value;
}
});
}());