- This is your domain. 4096 cubic kilometers of space for you
- to build, explore, and share. We’ve started you off with a
- home full of goodies to help you learn the ropes. Enjoy!
-
-
-
diff --git a/console/src/index.js b/console/src/index.js
deleted file mode 100755
index 6da2986a0f..0000000000
--- a/console/src/index.js
+++ /dev/null
@@ -1,110 +0,0 @@
-$(function() {
- const ipcRenderer = require('electron').ipcRenderer;
- const HFProcess = require('./modules/hf-process.js');
-
- var settingsButton = $('#manage-server #settings');
-
- function toggleManageButton(button, enabled) {
- if (enabled) {
- button.attr('href', '#');
- button.removeClass('disabled');
- } else {
- button.removeAttr('href');
- button.addClass('disabled');
- }
- }
-
- function onProcessUpdate(event, arg) {
- console.log("update", event, arg);
-
- // var interfaceState = arg.interface.state;
- // $('#process-interface .status').text(interfaceState);
- // var interfaceOn = interfaceState != 'stopped';
- // $('#process-interface .power-on').prop('disabled', interfaceOn);
- // $('#process-interface .power-off').prop('disabled', !interfaceOn);
-
- var sendingProcess = arg;
-
- var processCircle = null;
- if (sendingProcess.name == "domain-server") {
- processCircle = $('#ds-status .circle');
- } else if (sendingProcess.name == "ac-monitor") {
- processCircle = $('#ac-status .circle');
- } else {
- return;
- }
-
- if (sendingProcess.name == "domain-server") {
- toggleManageButton(settingsButton,
- sendingProcess.state == HFProcess.ProcessStates.STARTED);
- }
-
- switch (sendingProcess.state) {
- case HFProcess.ProcessStates.STOPPED:
- processCircle.attr('class', 'circle stopped');
- break;
- case HFProcess.ProcessStates.STOPPING:
- processCircle.attr('class', 'circle stopping');
- break;
- case HFProcess.ProcessStates.STARTED:
- processCircle.attr('class', 'circle started');
- break;
- }
- }
-
- function onProcessGroupUpdate(event, arg) {
- var sendingGroup = arg;
- var stopButton = $('#manage-server #stop');
- var goButton = $('#go-server-button');
- var serverStopped = $('#server-stopped-text');
-
- switch (sendingGroup.state) {
- case HFProcess.ProcessGroupStates.STOPPED:
- case HFProcess.ProcessGroupStates.STOPPING:
- // if the process group is stopping, the stop button should be disabled
- toggleManageButton(stopButton, false);
-
- // disable the go button
- goButton.addClass('disabled');
-
- // show the server stopped text
- serverStopped.show();
-
- break;
- case HFProcess.ProcessGroupStates.STARTED:
- // if the process group is going, the stop button should be active
- toggleManageButton(stopButton, true);
-
- // enable the go button
- goButton.removeClass('disabled');
-
- // hide the server stopped text
- serverStopped.hide();
-
- break;
- }
- }
-
- $('#last-visited-link').click(function() {
- ipcRenderer.send('start-interface');
- });
-
- $('#go-server-button:not(.disabled)').click(function(){
- ipcRenderer.send('start-interface', { url: 'hifi://localhost' });
- })
-
- $('#manage-server #restart').click(function() {
- ipcRenderer.send('restart-server', { name: 'home' });
- });
- $('#manage-server #stop').click(function() {
- ipcRenderer.send('stop-server', { name: 'home' });
- });
- $('#open-logs').click(function() {
- ipcRenderer.send('open-logs');
- });
-
- ipcRenderer.on('process-update', onProcessUpdate);
- ipcRenderer.on('process-group-update', onProcessGroupUpdate);
-
- ipcRenderer.send('update-all-processes');
-});
diff --git a/console/src/main.js b/console/src/main.js
index 4b09379576..e05b16730c 100644
--- a/console/src/main.js
+++ b/console/src/main.js
@@ -2,7 +2,8 @@
var electron = require('electron');
var app = electron.app; // Module to control application life.
-var BrowserWindow = require('browser-window'); // Module to create native browser window.
+var BrowserWindow = electron.BrowserWindow;
+
var Menu = require('menu');
var Tray = require('tray');
var shell = require('shell');
@@ -13,27 +14,31 @@ var path = require('path');
var hfprocess = require('./modules/hf-process.js');
var Process = hfprocess.Process;
var ProcessGroup = hfprocess.ProcessGroup;
+var ProcessGroupStates = hfprocess.ProcessGroupStates;
const ipcMain = electron.ipcMain;
-// Keep a global reference of the window object, if you don't, the window will
-// be closed automatically when the JavaScript object is garbage collected.
-var mainWindow = null;
-var tray = null;
+const osType = os.type();
var path = require('path');
-var TRAY_ICON = path.join(__dirname, '../resources/console-tray.png');
-var APP_ICON = path.join(__dirname, '../resources/console.png');
-// Quit when all windows are closed.
-app.on('window-all-closed', function() {
- // On OS X it is common for applications and their menu bar
- // to stay active until the user quits explicitly with Cmd + Q
- if (process.platform != 'darwin') {
- app.quit();
- }
+const TRAY_FILENAME = (osType == "Darwin" ? "console-tray-Template.png" : "console-tray.png");
+const TRAY_ICON = path.join(__dirname, '../resources/' + TRAY_FILENAME);
+const APP_ICON = path.join(__dirname, '../resources/console.png');
+
+// print out uncaught exceptions in the console
+process.on('uncaughtException', console.log.bind(console));
+
+var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
+ // Someone tried to run a second instance, focus the window (if there is one)
+ return true;
});
+if (shouldQuit) {
+ app.quit();
+ return;
+}
+
// Check command line arguments to see how to find binaries
var argv = require('yargs').argv;
var pathFinder = require('./modules/path-finder.js');
@@ -50,77 +55,144 @@ if (argv.localDebugBuilds || argv.localReleaseBuilds) {
acPath = pathFinder.discoveredPath("assignment-client", argv.localReleaseBuilds);
}
+// if at this point any of the paths are null, we're missing something we wanted to find
+// TODO: show an error for the binaries that couldn't be found
+
function openFileBrowser(path) {
- var type = os.type();
- console.log(type);
- if (type == "Windows_NT") {
+ if (osType == "Windows_NT") {
childProcess.exec('start ' + path);
- } else if (type == "Darwin") {
+ } else if (osType == "Darwin") {
childProcess.exec('open ' + path);
- } else if (type == "Linux") {
+ } else if (osType == "Linux") {
childProcess.exec('xdg-open ' + path);
}
}
-// if at this point any of the paths are null, we're missing something we wanted to find
-// TODO: show an error for the binaries that couldn't be found
+function startInterface(url) {
+ var argArray = [];
+
+ // check if we have a url parameter to include
+ if (url) {
+ argArray = ["--url", url];
+ }
+
+ // create a new Interface instance - Interface makes sure only one is running at a time
+ var pInterface = new Process('interface', interfacePath, argArray);
+ pInterface.start();
+}
+
+var tray = null;
+var homeServer = null;
+
+const GO_HOME_INDEX = 0;
+const SERVER_LABEL_INDEX = 2;
+const RESTART_INDEX = 3;
+const STOP_INDEX = 4;
+const SETTINGS_INDEX = 5;
+
+function buildMenuArray(serverState) {
+ var menuArray = [
+ {
+ label: 'Go Home',
+ click: function() { startInterface('hifi://localhost'); },
+ enabled: false
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: "Server - Stopped",
+ enabled: false
+ },
+ {
+ label: "Start",
+ click: function() { homeServer.restart(); }
+ },
+ {
+ label: "Stop",
+ visible: false,
+ click: function() { homeServer.stop(); }
+ },
+ {
+ label: "Settings",
+ click: function() { shell.openExternal('http://localhost:40100/settings'); },
+ enabled: false
+ },
+ {
+ label: "View Logs",
+ click: function() { openFileBrowser(logPath); }
+ },
+ {
+ type: 'separator'
+ },
+ {
+ label: 'Quit',
+ accelerator: 'Command+Q',
+ click: function() { app.quit(); }
+ }
+ ];
+
+ updateMenuArray(menuArray, serverState);
+
+ return menuArray;
+}
+
+function updateMenuArray(menuArray, serverState) {
+ // update the tray menu state
+ var running = serverState == ProcessGroupStates.STARTED;
+
+ var serverLabelItem = menuArray[SERVER_LABEL_INDEX];
+ var restartItem = menuArray[RESTART_INDEX];
+
+ // Go Home is only enabled if running
+ menuArray[GO_HOME_INDEX].enabled = running;
+
+ // Stop is only visible if running
+ menuArray[STOP_INDEX].visible = running;
+
+ // Settings is only visible if running
+ menuArray[SETTINGS_INDEX].enabled = running;
+
+ if (serverState == ProcessGroupStates.STARTED) {
+ serverLabelItem.label = "Server - Started";
+ restartItem.label = "Restart";
+ } else if (serverState == ProcessGroupStates.STOPPED) {
+ serverLabelItem.label = "Server - Stopped";
+ restartItem.label = "Start";
+ } else if (serverState == ProcessGroupStates.STOPPING) {
+ serverLabelItem.label = "Server - Stopping";
+ restartItem.label = "Restart";
+ }
+}
+
+function updateTrayMenu(serverState) {
+ if (tray) {
+ var menuArray = buildMenuArray(serverState);
+ tray.setContextMenu(Menu.buildFromTemplate(menuArray));
+ }
+}
+
+var hiddenWindow = null;
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', function() {
- // Create tray icon
- tray = new Tray(TRAY_ICON);
- tray.setToolTip('High Fidelity');
- var contextMenu = Menu.buildFromTemplate([{
- label: 'Quit',
- accelerator: 'Command+Q',
- click: function() { app.quit(); }
- }]);
- tray.setContextMenu(contextMenu);
- // Require electron-compile to use LESS files in place of basic CSS
- require('electron-compile').init();
-
- // Create the browser window.
- mainWindow = new BrowserWindow({
- title: "High Fidelity",
- width: 970,
- height: 775,
- icon: APP_ICON,
- resizable: false
- });
-
- // In debug mode, keep the menu bar, but auto-hide it so the UI still looks the same.
- if (debug) {
- mainWindow.setAutoHideMenuBar(true);
- } else {
- mainWindow.setMenu(null);
+ if (app.dock) {
+ // hide the dock icon on OS X
+ app.dock.hide()
}
- // and load the index.html of the app.
- mainWindow.loadURL('file://' + __dirname + '/index.html');
-
- // Open the DevTools.
- mainWindow.webContents.openDevTools();
-
- // Emitted when the window is closed.
- mainWindow.on('closed', function() {
- // Dereference the window object, usually you would store windows
- // in an array if your app supports multi windows, this is the time
- // when you should delete the corresponding element.
- mainWindow = null;
- });
-
- // When a link is clicked that has `_target="_blank"`, open it in the user's native browser
- mainWindow.webContents.on('new-window', function(e, url) {
- e.preventDefault();
- shell.openExternal(url);
- });
-
var logPath = path.join(app.getAppPath(), 'logs');
+ // Create tray icon
+ tray = new Tray(TRAY_ICON);
+ tray.setToolTip('High Fidelity');
+
+ updateTrayMenu(ProcessGroupStates.STOPPED);
+
if (interfacePath && dsPath && acPath) {
- var homeServer = new ProcessGroup('home', [
+ homeServer = new ProcessGroup('home', [
new Process('domain-server', dsPath),
new Process('ac-monitor', acPath, ['-n6', '--log-directory', logPath])
]);
@@ -134,58 +206,11 @@ app.on('ready', function() {
home: homeServer
};
- function sendProcessUpdate(process) {
- if (mainWindow) {
- console.log("Sending process update to web view for " + process.name);
- mainWindow.webContents.send('process-update', process);
- }
- };
-
- function sendProcessGroupUpdate(processGroup) {
- if (mainWindow) {
- mainWindow.webContents.send('process-group-update', processGroup);
- }
- }
-
// handle process updates
- homeServer.on('process-update', sendProcessUpdate);
- homeServer.on('state-update', sendProcessGroupUpdate);
+ // homeServer.on('process-update', sendProcessUpdate);
+ homeServer.on('state-update', function(processGroup) { updateTrayMenu(processGroup.state); });
// start the home server
homeServer.start();
-
- ipcMain.on('start-interface', function(event, arg) {
- // check if we have a url parameter to include
- var argArray = [];
- if (arg && arg.url) {
- argArray = ["--url", arg.url];
- }
-
- // create a new Interface instance - Interface makes sure only one is running at a time
- var pInterface = new Process('interface', interfacePath, argArray);
- pInterface.start();
- });
-
- ipcMain.on('restart-server', function(event, arg) {
- homeServer.restart();
- });
-
- ipcMain.on('stop-server', function(event, arg) {
- homeServer.stop();
- });
-
- ipcMain.on('open-logs', function(event, arg) {
- openFileBrowser(logPath);
- });
-
- ipcMain.on('update-all-processes', function(event, arg) {
- // enumerate our processes and call sendProcessUpdate to update
- // the window with their status
- for (let process of homeServer.processes) {
- sendProcessUpdate(process);
- }
-
- sendProcessGroupUpdate(homeServer);
- });
}
});
diff --git a/console/src/vendor/Raleway/OFL.txt b/console/src/vendor/Raleway/OFL.txt
deleted file mode 100755
index 1c9779ddcd..0000000000
--- a/console/src/vendor/Raleway/OFL.txt
+++ /dev/null
@@ -1,94 +0,0 @@
-Copyright (c) 2010, Matt McInerney (matt@pixelspread.com),
-Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com),
-Copyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-This license is copied below, and is also available with a FAQ at:
-http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/console/src/vendor/Raleway/Raleway-Regular.ttf b/console/src/vendor/Raleway/Raleway-Regular.ttf
deleted file mode 100755
index 252cad14a6..0000000000
Binary files a/console/src/vendor/Raleway/Raleway-Regular.ttf and /dev/null differ
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index d383ee3339..724e72b7a5 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -33,6 +33,9 @@
#include
#include
+#include
+#include
+
#include
#include
#include
@@ -5115,3 +5118,30 @@ void Application::setActiveDisplayPlugin(const QString& pluginName) {
}
updateDisplayMode();
}
+
+void Application::handleLocalServerConnection() {
+ auto server = qobject_cast(sender());
+
+ qDebug() << "Got connection on local server from additional instance - waiting for parameters";
+
+ auto socket = server->nextPendingConnection();
+
+ connect(socket, &QLocalSocket::readyRead, this, &Application::readArgumentsFromLocalSocket);
+
+ qApp->getWindow()->raise();
+ qApp->getWindow()->activateWindow();
+}
+
+void Application::readArgumentsFromLocalSocket() {
+ auto socket = qobject_cast(sender());
+
+ auto message = socket->readAll();
+ socket->deleteLater();
+
+ qDebug() << "Read from connection: " << message;
+
+ // If we received a message, try to open it as a URL
+ if (message.length() > 0) {
+ qApp->openUrl(QString::fromUtf8(message));
+ }
+}
diff --git a/interface/src/Application.h b/interface/src/Application.h
index 0953aedd8c..9b1cffc659 100644
--- a/interface/src/Application.h
+++ b/interface/src/Application.h
@@ -264,6 +264,9 @@ public slots:
void loadScriptURLDialog();
void toggleLogDialog();
+ void handleLocalServerConnection();
+ void readArgumentsFromLocalSocket();
+
ScriptEngine* loadScript(const QString& scriptFilename = QString(), bool isUserLoaded = true,
bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false);
void stopAllScripts(bool restart = false);
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 7a0514ada9..6de32657f1 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -42,52 +42,48 @@ static BOOL CALLBACK enumWindowsCallback(HWND hWnd, LPARAM lParam) {
#endif
int main(int argc, const char* argv[]) {
- QString applicationName = "High Fidelity Interface";
+ QString applicationName = "High Fidelity Interface - " + qgetenv("USERNAME");
- // Try to create a shared memory block - if it can't be created, there is an instance of
- // interface already running.
- QSharedMemory sharedMemory { applicationName };
- if (!sharedMemory.create(1, QSharedMemory::ReadOnly)) {
- // Connect to and send message to existing interface instance
- QLocalSocket socket;
+ // Connect to and send message to existing interface instance
+ QLocalSocket socket;
- socket.connectToServer(applicationName);
+ socket.connectToServer(applicationName);
- // Try to connect - if we can't connect, interface has probably just gone down
- if (socket.waitForConnected(100)) {
+ static const int LOCAL_SERVER_TIMEOUT_MS = 500;
- QStringList arguments;
- for (int i = 0; i < argc; ++i) {
- arguments << argv[i];
- }
+ // Try to connect - if we can't connect, interface has probably just gone down
+ if (socket.waitForConnected(LOCAL_SERVER_TIMEOUT_MS)) {
- QCommandLineParser parser;
- QCommandLineOption urlOption("url", "", "value");
- parser.addOption(urlOption);
- parser.process(arguments);
-
- if (parser.isSet(urlOption)) {
- QUrl url = QUrl(parser.value(urlOption));
- if (url.isValid() && url.scheme() == HIFI_URL_SCHEME) {
- socket.write(url.toString().toUtf8());
- socket.waitForBytesWritten(5000);
- }
- }
-
- socket.close();
+ QStringList arguments;
+ for (int i = 0; i < argc; ++i) {
+ arguments << argv[i];
}
+ QCommandLineParser parser;
+ QCommandLineOption urlOption("url", "", "value");
+ parser.addOption(urlOption);
+ parser.process(arguments);
+
+ if (parser.isSet(urlOption)) {
+ QUrl url = QUrl(parser.value(urlOption));
+ if (url.isValid() && url.scheme() == HIFI_URL_SCHEME) {
+ socket.write(url.toString().toUtf8());
+ socket.waitForBytesWritten(5000);
+ }
+ }
+
+ socket.close();
+
qDebug() << "Interface instance appears to be running, exiting";
return EXIT_SUCCESS;
}
-
QElapsedTimer startupTime;
startupTime.start();
-
- // Debug option to demonstrate that the client's local time does not
- // need to be in sync with any other network node. This forces clock
+
+ // Debug option to demonstrate that the client's local time does not
+ // need to be in sync with any other network node. This forces clock
// skew for the individual client
const char* CLOCK_SKEW = "--clockSkew";
const char* clockSkewOption = getCmdOption(argc, argv, CLOCK_SKEW);
@@ -109,36 +105,16 @@ int main(int argc, const char* argv[]) {
// Setup local server
QLocalServer server { &app };
- // We have already acquired the shared memory block, so we can safely remove
- // any existing servers. This can occur on Unix platforms after a crash.
+ // We failed to connect to a local server, so we remove any existing servers.
server.removeServer(applicationName);
server.listen(applicationName);
- QObject::connect(&server, &QLocalServer::newConnection, qApp, [&server]() {
- qDebug() << "Got connection on local server";
-
- auto socket = server.nextPendingConnection();
-
- QObject::connect(socket, &QLocalSocket::readyRead, qApp, [&socket]() {
- auto message = socket->readAll();
- socket->close();
-
- qDebug() << "Read from connection: " << message;
-
- // If we received a message, try to open it as a URL
- if (message.length() > 0) {
- qApp->openUrl(QString::fromUtf8(message));
- }
- });
-
- qApp->getWindow()->raise();
- qApp->getWindow()->activateWindow();
- });
+ QObject::connect(&server, &QLocalServer::newConnection, &app, &Application::handleLocalServerConnection);
QTranslator translator;
translator.load("i18n/interface_en");
app.installTranslator(&translator);
-
+
qCDebug(interfaceapp, "Created QT Application.");
exitCode = app.exec();
server.close();
@@ -148,4 +124,4 @@ int main(int argc, const char* argv[]) {
qCDebug(interfaceapp, "Normal exit.");
return exitCode;
-}
+}