207 lines
4.9 KiB
JavaScript
207 lines
4.9 KiB
JavaScript
|
/*jshint node:true, nomen:true */
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
var app = require('app');
|
||
|
var BrowserWindow = require('browser-window');
|
||
|
var ipc = require('ipc');
|
||
|
var net = require('net');
|
||
|
var util = require('util');
|
||
|
var events = require('events');
|
||
|
|
||
|
/**
|
||
|
* App
|
||
|
*
|
||
|
* Controls the app flow
|
||
|
*/
|
||
|
function App() {
|
||
|
this.windows = [];
|
||
|
this.ready = false;
|
||
|
this.visible = true;
|
||
|
|
||
|
app.on('ready', function () {
|
||
|
this.ready = true;
|
||
|
}.bind(this));
|
||
|
|
||
|
app.on('window-all-closed', function () {
|
||
|
app.quit();
|
||
|
});
|
||
|
|
||
|
events.EventEmitter.call(this);
|
||
|
}
|
||
|
|
||
|
util.inherits(App, events.EventEmitter);
|
||
|
module.exports = App;
|
||
|
App.socket = '\\\\.\\pipe\\piano-sock';
|
||
|
|
||
|
/**
|
||
|
* Add a new window
|
||
|
*
|
||
|
* Open a window and add it to the
|
||
|
* window stack. Returns window instance.
|
||
|
*
|
||
|
* @param {options: Object} Window options (see atom-shell docs)
|
||
|
*/
|
||
|
App.prototype.addWindow = function (options) {
|
||
|
var window = new BrowserWindow(options),
|
||
|
index = this.windows.length;
|
||
|
|
||
|
window.on('closed', function () {
|
||
|
this.windows.splice(index, 1);
|
||
|
}.bind(this));
|
||
|
|
||
|
this.windows.push(window);
|
||
|
return window;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Fetch options
|
||
|
*
|
||
|
* Gather options in a litteral from
|
||
|
* argv parameters.
|
||
|
*/
|
||
|
App.prototype.fetchOptions = function () {
|
||
|
var argv, i, arg, options = {};
|
||
|
argv = process.argv.slice(1);
|
||
|
|
||
|
for (i in argv) {
|
||
|
if (argv.hasOwnProperty(i)) {
|
||
|
arg = argv[i];
|
||
|
|
||
|
if (arg[0] !== '-') {
|
||
|
options.file = arg;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.emit('options', options);
|
||
|
return options;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Chain options
|
||
|
*
|
||
|
* Pass current options to the instance that
|
||
|
* is already opened, if there is one.
|
||
|
* Otherwise, code in callback is executed,
|
||
|
* and server is launched.
|
||
|
*
|
||
|
* @param {callback: function} Function to call if this is the first instance
|
||
|
*/
|
||
|
App.prototype.chainOptions = function (callback) {
|
||
|
var client;
|
||
|
|
||
|
client = net.connect({
|
||
|
path: App.socket
|
||
|
}, function () {
|
||
|
// if the connection is established,
|
||
|
// an instance is already running.
|
||
|
// Pass on parameters and close app.
|
||
|
client.write(
|
||
|
JSON.stringify(this.fetchOptions()),
|
||
|
function () {
|
||
|
client.end();
|
||
|
app.terminate();
|
||
|
}
|
||
|
);
|
||
|
}.bind(this));
|
||
|
|
||
|
client.on('error', function (err) {
|
||
|
// if an error occurred, that means no
|
||
|
// server was created yet: this is the
|
||
|
// first instance
|
||
|
this.startServer();
|
||
|
|
||
|
if (this.ready) {
|
||
|
callback();
|
||
|
} else {
|
||
|
app.on('ready', callback);
|
||
|
}
|
||
|
}.bind(this));
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Start app server
|
||
|
*
|
||
|
* Start a server on App.socket path, waiting
|
||
|
* for new instances to pass their options.
|
||
|
*/
|
||
|
App.prototype.startServer = function () {
|
||
|
var server;
|
||
|
|
||
|
server = net.createServer(function (connection) {
|
||
|
connection.on('data', function (data) {
|
||
|
this.windows[0].focus();
|
||
|
this.emit('options', JSON.parse(data));
|
||
|
}.bind(this));
|
||
|
}.bind(this));
|
||
|
|
||
|
server.listen(App.socket);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Add a switch
|
||
|
*
|
||
|
* @param {switch: string} Switch name
|
||
|
* @param {value: mixed} Switch value
|
||
|
*/
|
||
|
App.prototype.addSwitch = function (name, value) {
|
||
|
app.commandLine.appendSwitch(name, value);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Start the app
|
||
|
*
|
||
|
* Check if another instance is already opened,
|
||
|
* if so, transmit options and close instantly.
|
||
|
* Otherwise, open main window.
|
||
|
*/
|
||
|
App.prototype.start = function () {
|
||
|
this.chainOptions(function () {
|
||
|
// enable MIDI support
|
||
|
this.addSwitch('enable-web-midi');
|
||
|
|
||
|
// create main window
|
||
|
var window = this.addWindow({
|
||
|
title: 'Piano',
|
||
|
icon: __dirname + '/images/logos/logo32.png',
|
||
|
|
||
|
'min-width': 750,
|
||
|
'min-height': 400,
|
||
|
width: 937,
|
||
|
height: 500,
|
||
|
show: false
|
||
|
});
|
||
|
|
||
|
window.loadUrl('file://' + __dirname + '/index.html');
|
||
|
|
||
|
// FIXME: atom-shell currently doesn't have a
|
||
|
// minimize/restore event, so we poll
|
||
|
//
|
||
|
// https://github.com/atom/atom-shell/issues/73
|
||
|
setInterval(function () {
|
||
|
if (this.visible && window.isMinimized()) {
|
||
|
this.visible = false;
|
||
|
window.webContents.send('visible', false);
|
||
|
}
|
||
|
|
||
|
if (!this.visible && !window.isMinimized()) {
|
||
|
this.visible = true;
|
||
|
window.webContents.send('visible', true);
|
||
|
}
|
||
|
}.bind(this), 500);
|
||
|
|
||
|
// start sending options
|
||
|
this.on('options', function (options) {
|
||
|
window.webContents.send('options', options);
|
||
|
});
|
||
|
|
||
|
ipc.on('ready', function () {
|
||
|
window.show();
|
||
|
window.focus();
|
||
|
window.webContents.send('visible', true);
|
||
|
|
||
|
this.fetchOptions();
|
||
|
}.bind(this));
|
||
|
}.bind(this));
|
||
|
};
|