2017-03-01 18:32:21 -06:00
'use strict' ;
const electron = require ( 'electron' ) ;
const app = electron . app ;
2017-09-18 10:47:45 -05:00
const crashReporter = electron . crashReporter ;
2017-05-19 10:01:41 -05:00
const BrowserWindow = electron . BrowserWindow ;
2017-03-01 18:32:21 -06:00
const path = require ( 'path' ) ;
2017-04-18 11:02:25 -05:00
const nodeURL = require ( 'url' ) ;
2017-04-20 13:54:11 -05:00
const querystring = require ( 'querystring' ) ;
2017-06-27 10:08:58 -05:00
const filesize = require ( 'filesize' ) ;
2017-03-01 18:32:21 -06:00
2017-05-19 10:01:41 -05:00
const { getTemplate , getMinimizeOnClose } = require ( './menus/menuTemplate.js' ) ;
2017-03-01 18:32:21 -06:00
const loadErrors = require ( './dialogs/showLoadError.js' ) ;
2017-04-20 13:54:11 -05:00
const isInDisplayBounds = require ( './utils/isInDisplayBounds.js' ) ;
2017-03-09 12:12:28 -06:00
const getGuid = require ( './utils/getGuid.js' ) ;
2017-05-08 13:30:45 -05:00
const log = require ( './log.js' ) ;
2017-03-01 18:32:21 -06:00
const logLevels = require ( './enums/logLevels.js' ) ;
2017-04-06 12:07:58 -05:00
const notify = require ( './notify/electron-notify.js' ) ;
2017-06-15 12:11:29 -05:00
const eventEmitter = require ( './eventEmitter' ) ;
2017-04-20 13:54:11 -05:00
const throttle = require ( './utils/throttle.js' ) ;
2017-05-19 10:01:41 -05:00
const { getConfigField , updateConfigField } = require ( './config.js' ) ;
2017-08-08 04:50:03 -05:00
const { isMac , isNodeEnv } = require ( './utils/misc' ) ;
2017-05-24 08:32:49 -05:00
2017-03-01 18:32:21 -06:00
// show dialog when certificate errors occur
require ( './dialogs/showCertError.js' ) ;
// 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.
let mainWindow ;
let windows = { } ;
let willQuitApp = false ;
let isOnline = true ;
2017-04-20 13:54:11 -05:00
let boundsChangeWindow ;
2017-06-15 12:11:29 -05:00
let alwaysOnTop = false ;
2017-06-16 17:29:56 -05:00
let position = 'lower-right' ;
let display ;
2017-07-14 02:27:38 -05:00
let sandboxed = false ;
2017-03-07 16:44:31 -06:00
2017-04-18 11:02:25 -05:00
// note: this file is built using browserify in prebuild step.
2017-03-07 16:44:31 -06:00
const preloadMainScript = path . join ( _ _dirname , 'preload/_preloadMain.js' ) ;
2017-03-01 18:32:21 -06:00
2017-05-11 13:11:42 -05:00
const MIN _WIDTH = 300 ;
const MIN _HEIGHT = 600 ;
2017-08-24 05:48:32 -05:00
/ * *
* Adds a window key
* @ param key
* @ param browserWin
* /
2017-03-01 18:32:21 -06:00
function addWindowKey ( key , browserWin ) {
2017-05-08 13:30:45 -05:00
windows [ key ] = browserWin ;
2017-03-01 18:32:21 -06:00
}
2017-08-24 05:48:32 -05:00
/ * *
* Removes a window key
* @ param key
* /
2017-03-01 18:32:21 -06:00
function removeWindowKey ( key ) {
2017-05-08 13:30:45 -05:00
delete windows [ key ] ;
2017-03-01 18:32:21 -06:00
}
2017-08-24 05:48:32 -05:00
/ * *
* Gets the parsed url
* @ param url
* @ returns { Url }
* /
2017-04-20 13:54:11 -05:00
function getParsedUrl ( url ) {
2017-05-13 13:23:44 -05:00
return nodeURL . parse ( url ) ;
2017-04-18 11:02:25 -05:00
}
2017-08-24 05:48:32 -05:00
/ * *
* Creates the main window
* @ param initialUrl
* /
2017-04-18 11:02:25 -05:00
function createMainWindow ( initialUrl ) {
2017-04-20 13:54:11 -05:00
getConfigField ( 'mainWinPos' ) . then (
2017-05-08 13:30:45 -05:00
function ( bounds ) {
2017-04-20 13:54:11 -05:00
doCreateMainWindow ( initialUrl , bounds ) ;
} ,
2017-05-08 13:30:45 -05:00
function ( ) {
2017-04-20 13:54:11 -05:00
// failed, use default bounds
doCreateMainWindow ( initialUrl , null ) ;
}
2017-09-18 10:47:45 -05:00
) ;
2017-04-20 13:54:11 -05:00
}
2017-08-24 05:48:32 -05:00
/ * *
* Creates the main window with bounds
* @ param initialUrl
* @ param initialBounds
* /
2017-04-20 13:54:11 -05:00
function doCreateMainWindow ( initialUrl , initialBounds ) {
2017-04-18 11:02:25 -05:00
let url = initialUrl ;
2017-03-01 18:32:21 -06:00
let key = getGuid ( ) ;
2017-05-31 23:39:08 -05:00
log . send ( logLevels . INFO , 'creating main window url: ' + url ) ;
2017-04-18 11:02:25 -05:00
let newWinOpts = {
2017-03-01 18:32:21 -06:00
title : 'Symphony' ,
show : true ,
2017-05-11 13:11:42 -05:00
minWidth : MIN _WIDTH ,
minHeight : MIN _HEIGHT ,
2017-06-15 12:11:29 -05:00
alwaysOnTop : false ,
2017-03-01 18:32:21 -06:00
webPreferences : {
2017-07-14 02:27:38 -05:00
sandbox : sandboxed ,
2017-07-10 02:39:10 -05:00
nodeIntegration : isNodeEnv ,
2017-03-07 16:44:31 -06:00
preload : preloadMainScript ,
2017-07-19 04:49:46 -05:00
nativeWindowOpen : true
2017-03-01 18:32:21 -06:00
}
2017-04-18 11:02:25 -05:00
} ;
2017-05-13 13:23:44 -05:00
// set size and position
2017-04-20 13:54:11 -05:00
let bounds = initialBounds ;
// if bounds if not fully contained in some display then use default size
// and position.
if ( ! isInDisplayBounds ( bounds ) ) {
bounds = null ;
}
if ( bounds && bounds . width && bounds . height ) {
newWinOpts . width = bounds . width ;
newWinOpts . height = bounds . height ;
} else {
newWinOpts . width = 1024 ;
newWinOpts . height = 768 ;
}
// will center on screen if values not provided
if ( bounds && bounds . x && bounds . y ) {
newWinOpts . x = bounds . x ;
newWinOpts . y = bounds . y ;
}
2017-06-15 12:11:29 -05:00
// will set the main window on top as per the user prefs
if ( alwaysOnTop ) {
newWinOpts . alwaysOnTop = alwaysOnTop ;
}
2017-04-18 11:02:25 -05:00
// note: augmenting with some custom values
newWinOpts . winKey = key ;
2017-05-19 10:01:41 -05:00
mainWindow = new BrowserWindow ( newWinOpts ) ;
2017-04-18 11:02:25 -05:00
mainWindow . winName = 'main' ;
2017-03-01 18:32:21 -06:00
2017-04-20 13:54:11 -05:00
let throttledMainWinBoundsChange = throttle ( 5000 , saveMainWinBounds ) ;
mainWindow . on ( 'move' , throttledMainWinBoundsChange ) ;
2017-05-08 13:30:45 -05:00
mainWindow . on ( 'resize' , throttledMainWinBoundsChange ) ;
2017-04-20 13:54:11 -05:00
2017-03-01 18:32:21 -06:00
function retry ( ) {
2017-03-03 18:07:48 -06:00
if ( ! isOnline ) {
2017-03-01 18:32:21 -06:00
loadErrors . showNetworkConnectivityError ( mainWindow , url , retry ) ;
2017-03-03 18:07:48 -06:00
return ;
}
if ( mainWindow . webContents ) {
mainWindow . webContents . reload ( ) ;
2017-03-01 18:32:21 -06:00
}
}
// content can be cached and will still finish load but
2017-05-13 13:23:44 -05:00
// we might not have network connectivity, so warn the user.
2017-05-08 13:30:45 -05:00
mainWindow . webContents . on ( 'did-finish-load' , function ( ) {
2017-04-18 11:02:25 -05:00
url = mainWindow . webContents . getURL ( ) ;
2017-03-01 18:32:21 -06:00
if ( ! isOnline ) {
loadErrors . showNetworkConnectivityError ( mainWindow , url , retry ) ;
} else {
2017-06-16 17:29:56 -05:00
// updates the notify config with user preference
notify . updateConfig ( { position : position , display : display } ) ;
2017-04-06 12:07:58 -05:00
// removes all existing notifications when main window reloads
notify . reset ( ) ;
2017-05-31 23:39:08 -05:00
log . send ( logLevels . INFO , 'loaded main window url: ' + url ) ;
2017-05-08 13:30:45 -05:00
2017-03-01 18:32:21 -06:00
}
} ) ;
2017-05-08 13:30:45 -05:00
mainWindow . webContents . on ( 'did-fail-load' , function ( event , errorCode ,
errorDesc , validatedURL ) {
2017-09-14 06:00:13 -05:00
loadErrors . showLoadFailure ( mainWindow , validatedURL , errorDesc , errorCode , retry , false ) ;
2017-03-01 18:32:21 -06:00
} ) ;
2017-05-24 08:32:49 -05:00
// In case a renderer process crashes, provide an
// option for the user to either reload or close the window
mainWindow . webContents . on ( 'crashed' , function ( ) {
const options = {
type : 'error' ,
title : 'Renderer Process Crashed' ,
2017-09-13 06:01:09 -05:00
message : 'Oops! Looks like we have had a crash. Please reload or close this window.' ,
2017-05-24 08:32:49 -05:00
buttons : [ 'Reload' , 'Close' ]
} ;
2017-09-13 06:01:09 -05:00
electron . dialog . showMessageBox ( options , function ( index ) {
2017-05-24 08:32:49 -05:00
if ( index === 0 ) {
mainWindow . reload ( ) ;
}
2017-09-25 04:03:12 -05:00
else {
mainWindow . close ( ) ;
}
2017-05-24 08:32:49 -05:00
} ) ;
} ) ;
2017-03-01 18:32:21 -06:00
addWindowKey ( key , mainWindow ) ;
mainWindow . loadURL ( url ) ;
2017-05-19 10:01:41 -05:00
const menu = electron . Menu . buildFromTemplate ( getTemplate ( app ) ) ;
2017-03-01 18:32:21 -06:00
electron . Menu . setApplicationMenu ( menu ) ;
2017-05-19 10:01:41 -05:00
mainWindow . on ( 'close' , function ( e ) {
2017-03-01 18:32:21 -06:00
if ( willQuitApp ) {
2017-04-18 11:02:25 -05:00
destroyAllWindows ( ) ;
2017-03-01 18:32:21 -06:00
return ;
}
2017-05-19 10:01:41 -05:00
if ( getMinimizeOnClose ( ) ) {
2017-03-01 18:32:21 -06:00
e . preventDefault ( ) ;
2017-05-19 10:01:41 -05:00
mainWindow . minimize ( ) ;
} else {
app . quit ( ) ;
2017-03-01 18:32:21 -06:00
}
} ) ;
2017-04-18 11:02:25 -05:00
function destroyAllWindows ( ) {
2017-04-18 15:40:26 -05:00
let keys = Object . keys ( windows ) ;
2017-08-24 02:51:02 -05:00
for ( let i = 0 , len = keys . length ; i < len ; i ++ ) {
2017-04-18 11:02:25 -05:00
let winKey = keys [ i ] ;
removeWindowKey ( winKey ) ;
2017-03-03 18:07:48 -06:00
}
2017-04-18 11:02:25 -05:00
mainWindow = null ;
}
2017-03-01 18:32:21 -06:00
2017-04-18 11:02:25 -05:00
mainWindow . on ( 'closed' , destroyAllWindows ) ;
2017-06-27 10:08:58 -05:00
// Manage File Downloads
mainWindow . webContents . session . on ( 'will-download' , ( event , item , webContents ) => {
// When download is in progress, send necessary data to indicate the same
webContents . send ( 'downloadProgress' ) ;
// Send file path when download is complete
2017-07-02 07:53:34 -05:00
item . once ( 'done' , ( e , state ) => {
2017-06-27 10:08:58 -05:00
if ( state === 'completed' ) {
let data = {
_id : getGuid ( ) ,
savedPath : item . getSavePath ( ) ? item . getSavePath ( ) : '' ,
total : filesize ( item . getTotalBytes ( ) ? item . getTotalBytes ( ) : 0 ) ,
fileName : item . getFilename ( ) ? item . getFilename ( ) : 'No name'
} ;
webContents . send ( 'downloadCompleted' , data ) ;
}
} ) ;
} ) ;
2017-10-05 11:48:52 -05:00
getConfigField ( 'url' )
. then ( initializeCrashReporter )
. catch ( app . quit ) ;
function initializeCrashReporter ( podUrl ) {
getConfigField ( 'crashReporter' )
. then ( ( crashReporterConfig ) => {
log . send ( logLevels . INFO , 'Initializing crash reporter on the main window!' ) ;
crashReporter . start ( { companyName : crashReporterConfig . companyName , submitURL : crashReporterConfig . submitURL , uploadToServer : crashReporterConfig . uploadToServer , extra : { 'process' : 'renderer / main window' , podUrl : podUrl } } ) ;
log . send ( logLevels . INFO , 'initialized crash reporter on the main window!' ) ;
mainWindow . webContents . send ( 'register-crash-reporter' , { companyName : crashReporterConfig . companyName , submitURL : crashReporterConfig . submitURL , uploadToServer : crashReporterConfig . uploadToServer , process : 'preload script / main window renderer' } ) ;
} )
. catch ( ( err ) => {
log . send ( logLevels . ERROR , 'Unable to initialize crash reporter in the main window. Error is -> ' + err ) ;
} ) ;
2017-10-09 09:27:38 -05:00
}
2017-05-25 11:48:40 -05:00
// open external links in default browser - a tag with href='_blank' or window.open
2017-05-08 13:30:45 -05:00
mainWindow . webContents . on ( 'new-window' , function ( event , newWinUrl ,
frameName , disposition , newWinOptions ) {
2017-06-15 12:11:29 -05:00
2017-04-20 13:54:11 -05:00
let newWinParsedUrl = getParsedUrl ( newWinUrl ) ;
let mainWinParsedUrl = getParsedUrl ( url ) ;
let newWinHost = newWinParsedUrl && newWinParsedUrl . host ;
let mainWinHost = mainWinParsedUrl && mainWinParsedUrl . host ;
2017-04-18 11:02:25 -05:00
2017-05-25 11:48:40 -05:00
// only allow window.open to succeed is if coming from same hsot,
// otherwise open in default browser.
if ( disposition === 'new-window' && newWinHost === mainWinHost ) {
2017-04-18 11:02:25 -05:00
// handle: window.open
if ( ! frameName ) {
// abort - no frame name provided.
return ;
}
2017-04-18 15:40:26 -05:00
2017-05-31 23:39:08 -05:00
log . send ( logLevels . INFO , 'creating pop-out window url: ' + newWinParsedUrl ) ;
2017-04-20 13:54:11 -05:00
let x = 0 ;
let y = 0 ;
2017-05-11 13:11:42 -05:00
let width = newWinOptions . width || MIN _WIDTH ;
let height = newWinOptions . height || MIN _HEIGHT ;
2017-04-20 13:54:11 -05:00
// try getting x and y position from query parameters
2017-08-24 02:51:02 -05:00
let query = newWinParsedUrl && querystring . parse ( newWinParsedUrl . query ) ;
2017-04-20 13:54:11 -05:00
if ( query && query . x && query . y ) {
let newX = Number . parseInt ( query . x , 10 ) ;
let newY = Number . parseInt ( query . y , 10 ) ;
2017-05-08 13:30:45 -05:00
let newWinRect = { x : newX , y : newY , width , height } ;
2017-04-20 13:54:11 -05:00
// only accept if both are successfully parsed.
if ( Number . isInteger ( newX ) && Number . isInteger ( newY ) &&
isInDisplayBounds ( newWinRect ) ) {
x = newX ;
y = newY ;
} else {
x = 0 ;
y = 0 ;
}
} else {
// create new window at slight offset from main window.
2017-05-08 13:30:45 -05:00
( { x , y } = getWindowSizeAndPosition ( mainWindow ) ) ;
x += 50 ;
y += 50 ;
2017-04-20 13:54:11 -05:00
}
2017-04-18 11:02:25 -05:00
2017-04-20 13:54:11 -05:00
/* eslint-disable no-param-reassign */
newWinOptions . x = x ;
newWinOptions . y = y ;
2017-05-11 13:11:42 -05:00
newWinOptions . width = Math . max ( width , MIN _WIDTH ) ;
newWinOptions . height = Math . max ( height , MIN _HEIGHT ) ;
newWinOptions . minWidth = MIN _WIDTH ;
newWinOptions . minHeight = MIN _HEIGHT ;
2017-06-15 12:11:29 -05:00
newWinOptions . alwaysOnTop = alwaysOnTop ;
2017-04-18 11:02:25 -05:00
2017-04-20 13:54:11 -05:00
let newWinKey = getGuid ( ) ;
2017-04-18 11:02:25 -05:00
2017-04-20 13:54:11 -05:00
newWinOptions . winKey = newWinKey ;
/* eslint-enable no-param-reassign */
2017-04-18 15:40:26 -05:00
2017-04-20 13:54:11 -05:00
let webContents = newWinOptions . webContents ;
2017-04-18 11:02:25 -05:00
2017-05-08 13:30:45 -05:00
webContents . once ( 'did-finish-load' , function ( ) {
2017-05-19 10:01:41 -05:00
let browserWin = BrowserWindow . fromWebContents ( webContents ) ;
2017-04-18 11:02:25 -05:00
2017-04-20 13:54:11 -05:00
if ( browserWin ) {
2017-05-31 23:39:08 -05:00
log . send ( logLevels . INFO , 'loaded pop-out window url: ' + newWinParsedUrl ) ;
2017-10-05 11:48:52 -05:00
getConfigField ( 'url' )
. then ( ( podUrl ) => {
getConfigField ( 'crashReporter' )
. then ( ( crashReporterConfig ) => {
crashReporter . start ( { companyName : crashReporterConfig . companyName , submitURL : crashReporterConfig . submitURL , uploadToServer : crashReporterConfig . uploadToServer , extra : { 'process' : 'renderer / child window' , podUrl : podUrl } } ) ;
log . send ( logLevels . INFO , 'initialized crash reporter on a child window!' ) ;
browserWin . webContents . send ( 'register-crash-reporter' , { companyName : crashReporterConfig . companyName , submitURL : crashReporterConfig . submitURL , uploadToServer : crashReporterConfig . uploadToServer , process : 'preload script / child window renderer' } ) ;
} )
. catch ( ( err ) => {
log . send ( logLevels . ERROR , 'Unable to initialize crash reporter in the child window. Error is -> ' + err ) ;
} ) ;
} )
. catch ( app . quit ) ;
2017-09-25 05:40:03 -05:00
2017-04-20 13:54:11 -05:00
browserWin . winName = frameName ;
2017-06-15 12:11:29 -05:00
browserWin . setAlwaysOnTop ( alwaysOnTop ) ;
2017-04-18 11:02:25 -05:00
2017-10-08 09:02:44 -05:00
let handleChildWindowClosed = ( ) => {
2017-04-20 13:54:11 -05:00
removeWindowKey ( newWinKey ) ;
browserWin . removeListener ( 'move' , throttledBoundsChange ) ;
2017-10-08 09:02:44 -05:00
browserWin . removeListener ( 'resize' , throttledBoundsChange ) ;
} ;
browserWin . once ( 'closed' , ( ) => {
handleChildWindowClosed ( ) ;
} ) ;
browserWin . on ( 'close' , ( ) => {
browserWin . webContents . removeListener ( 'new-window' , handleChildNewWindowEvent ) ;
browserWin . webContents . removeListener ( 'crashed' , handleChildWindowCrashEvent ) ;
2017-04-20 13:54:11 -05:00
} ) ;
2017-04-18 11:02:25 -05:00
2017-10-08 09:02:44 -05:00
let handleChildWindowCrashEvent = ( ) => {
2017-09-25 05:40:03 -05:00
const options = {
type : 'error' ,
title : 'Renderer Process Crashed' ,
message : 'Oops! Looks like we have had a crash. Please reload or close this window.' ,
buttons : [ 'Reload' , 'Close' ]
} ;
electron . dialog . showMessageBox ( options , function ( index ) {
if ( index === 0 ) {
2017-10-06 13:14:16 -05:00
browserWin . reload ( ) ;
2017-09-25 05:40:03 -05:00
}
else {
2017-10-06 13:14:16 -05:00
browserWin . close ( ) ;
2017-09-25 05:40:03 -05:00
}
} ) ;
2017-10-08 09:02:44 -05:00
} ;
browserWin . webContents . on ( 'crashed' , handleChildWindowCrashEvent ) ;
2017-09-25 05:40:03 -05:00
2017-10-08 09:02:44 -05:00
let handleChildNewWindowEvent = ( childEvent , childWinUrl ) => {
childEvent . preventDefault ( ) ;
openUrlInDefaultBrowser ( childWinUrl ) ;
} ;
2017-10-06 05:30:50 -05:00
// In case we navigate to an external link from inside a pop-out,
// we open that link in an external browser rather than creating
// a new window
2017-10-08 09:02:44 -05:00
browserWin . webContents . on ( 'new-window' , handleChildNewWindowEvent ) ;
2017-09-25 05:40:03 -05:00
2017-04-20 13:54:11 -05:00
addWindowKey ( newWinKey , browserWin ) ;
2017-10-06 00:59:48 -05:00
// Method that sends bound changes as soon
// as a new window is created
// issue https://perzoinc.atlassian.net/browse/ELECTRON-172
sendChildWinBoundsChange ( browserWin ) ;
2017-04-20 13:54:11 -05:00
// throttle changes so we don't flood client.
let throttledBoundsChange = throttle ( 1000 ,
sendChildWinBoundsChange . bind ( null , browserWin ) ) ;
browserWin . on ( 'move' , throttledBoundsChange ) ;
2017-10-05 11:48:52 -05:00
browserWin . on ( 'resize' , throttledBoundsChange ) ;
2017-04-20 13:54:11 -05:00
}
} ) ;
2017-05-25 11:48:40 -05:00
} else {
event . preventDefault ( ) ;
2017-10-06 05:37:13 -05:00
openUrlInDefaultBrowser ( newWinUrl ) ;
2017-04-18 11:02:25 -05:00
}
2017-03-01 18:32:21 -06:00
} ) ;
2017-04-18 11:02:25 -05:00
2017-03-01 18:32:21 -06:00
}
2017-08-24 05:48:32 -05:00
/ * *
* Handles the event before - quit emitted by electron
* /
2017-05-08 13:30:45 -05:00
app . on ( 'before-quit' , function ( ) {
2017-03-01 18:32:21 -06:00
willQuitApp = true ;
} ) ;
2017-08-24 05:48:32 -05:00
/ * *
* Saves the main window bounds
* /
2017-04-20 13:54:11 -05:00
function saveMainWinBounds ( ) {
let newBounds = getWindowSizeAndPosition ( mainWindow ) ;
if ( newBounds ) {
updateConfigField ( 'mainWinPos' , newBounds ) ;
}
}
2017-08-24 05:48:32 -05:00
/ * *
* Gets the main window
* @ returns { * }
* /
2017-03-06 23:09:10 -06:00
function getMainWindow ( ) {
return mainWindow ;
}
2017-08-24 05:48:32 -05:00
/ * *
* Gets a window ' s size and position
* @ param window
* @ returns { * }
* /
2017-04-20 13:54:11 -05:00
function getWindowSizeAndPosition ( window ) {
2017-05-25 11:48:40 -05:00
if ( window ) {
let newPos = window . getPosition ( ) ;
let newSize = window . getSize ( ) ;
if ( newPos && newPos . length === 2 &&
newSize && newSize . length === 2 ) {
return {
x : newPos [ 0 ] ,
y : newPos [ 1 ] ,
width : newSize [ 0 ] ,
height : newSize [ 1 ] ,
} ;
}
2017-04-20 13:54:11 -05:00
}
return null ;
}
2017-08-24 05:48:32 -05:00
/ * *
* Shows the main window
* /
2017-03-01 18:32:21 -06:00
function showMainWindow ( ) {
mainWindow . show ( ) ;
}
2017-08-24 05:48:32 -05:00
/ * *
* Tells if a window is the main window
* @ param win
* @ returns { boolean }
* /
2017-03-01 18:32:21 -06:00
function isMainWindow ( win ) {
return mainWindow === win ;
}
2017-08-24 05:48:32 -05:00
/ * *
* Checks if the window and a key has a window
* @ param win
* @ param winKey
* @ returns { * }
* /
2017-03-01 18:32:21 -06:00
function hasWindow ( win , winKey ) {
2017-05-19 10:01:41 -05:00
if ( win instanceof BrowserWindow ) {
2017-05-08 13:30:45 -05:00
let browserWin = windows [ winKey ] ;
2017-03-01 18:32:21 -06:00
return browserWin && win === browserWin ;
}
return false ;
}
2017-08-24 05:48:32 -05:00
/ * *
* Sets if a user is online
* @ param status
* /
2017-03-01 18:32:21 -06:00
function setIsOnline ( status ) {
isOnline = status ;
}
2017-04-20 13:54:11 -05:00
/ * *
2017-10-08 09:02:44 -05:00
* Tries finding a window we have created with given name . If found , then
2017-04-20 13:54:11 -05:00
* brings to front and gives focus .
* @ param { String } windowName Name of target window . Note : main window has
* name 'main' .
* /
2017-04-18 11:02:25 -05:00
function activate ( windowName ) {
2017-04-18 15:40:26 -05:00
let keys = Object . keys ( windows ) ;
2017-05-08 13:30:45 -05:00
for ( let i = 0 , len = keys . length ; i < len ; i ++ ) {
2017-04-18 15:40:26 -05:00
let window = windows [ keys [ i ] ] ;
2017-05-08 12:44:00 -05:00
if ( window && ! window . isDestroyed ( ) && window . winName === windowName ) {
if ( window . isMinimized ( ) ) {
window . restore ( ) ;
} else {
window . show ( ) ;
}
2017-04-18 11:02:25 -05:00
return ;
}
}
}
2017-04-20 13:54:11 -05:00
/ * *
* name of renderer window to notify when bounds of child window changes .
* @ param { object } window Renderer window to use IPC with to inform about size /
* position change .
* /
function setBoundsChangeWindow ( window ) {
boundsChangeWindow = window ;
}
/ * *
* Called when bounds of child window changes size / position
* @ param { object } window Child window which has changed size / position .
* /
function sendChildWinBoundsChange ( window ) {
let newBounds = getWindowSizeAndPosition ( window ) ;
if ( newBounds && boundsChangeWindow ) {
newBounds . windowName = window . winName ;
2017-04-26 11:46:15 -05:00
// ipc msg back to renderer to inform bounds has changed.
2017-04-20 13:54:11 -05:00
boundsChangeWindow . send ( 'boundsChange' , newBounds ) ;
}
}
2017-08-24 05:48:32 -05:00
/ * *
* Opens an external url in the system ' s default browser
* @ param urlToOpen
* /
2017-10-06 05:37:13 -05:00
function openUrlInDefaultBrowser ( urlToOpen ) {
2017-10-06 05:28:26 -05:00
if ( urlToOpen ) {
2017-05-25 11:48:40 -05:00
electron . shell . openExternal ( urlToOpen ) ;
}
}
2017-06-15 12:11:29 -05:00
/ * *
* Called when an event is received from menu
* @ param boolean weather to enable or disable alwaysOnTop .
* /
function isAlwaysOnTop ( boolean ) {
alwaysOnTop = boolean ;
let browserWins = BrowserWindow . getAllWindows ( ) ;
if ( browserWins . length > 0 ) {
browserWins . forEach ( function ( browser ) {
browser . setAlwaysOnTop ( boolean ) ;
} ) ;
}
}
// node event emitter to update always on top
eventEmitter . on ( 'isAlwaysOnTop' , ( boolean ) => {
isAlwaysOnTop ( boolean ) ;
} ) ;
2017-06-16 17:29:56 -05:00
// node event emitter for notification settings
eventEmitter . on ( 'notificationSettings' , ( notificationSettings ) => {
position = notificationSettings . position ;
display = notificationSettings . display ;
} ) ;
2017-08-08 04:50:03 -05:00
/ * *
* Method that gets invoked when an external display
* is removed using electron 'display-removed' event .
* /
function verifyDisplays ( ) {
// This is only for Windows, macOS handles this by itself
if ( ! mainWindow || isMac ) {
return ;
}
const bounds = mainWindow . getBounds ( ) ;
if ( bounds ) {
let isXAxisValid = true ;
let isYAxisValid = true ;
// checks to make sure the x,y are valid pairs
if ( ( bounds . x === undefined && ( bounds . y || bounds . y === 0 ) ) ) {
isXAxisValid = false ;
}
if ( ( bounds . y === undefined && ( bounds . x || bounds . x === 0 ) ) ) {
isYAxisValid = false ;
}
if ( ! isXAxisValid && ! isYAxisValid ) {
return ;
}
let externalDisplay = checkExternalDisplay ( bounds ) ;
// If external window doesn't exists, reposition main window
if ( ! externalDisplay ) {
repositionMainWindow ( ) ;
}
}
}
/ * *
* Method that verifies if wrapper exists in any of the available
* external display by comparing the app bounds with the display bounds
* if not exists returns false otherwise true
* @ param appBounds { Electron . Rectangle } - current electron wrapper bounds
* @ returns { boolean }
* /
function checkExternalDisplay ( appBounds ) {
const x = appBounds . x ;
const y = appBounds . y ;
const width = appBounds . width ;
const height = appBounds . height ;
const factor = 0.2 ;
const screen = electron . screen ;
// Loops through all the available displays and
// verifies if the wrapper exists within the display bounds
// returns false if not exists otherwise true
return ! ! screen . getAllDisplays ( ) . find ( ( { bounds } ) => {
const leftMost = x + ( width * factor ) ;
const topMost = y + ( height * factor ) ;
const rightMost = x + width - ( width * factor ) ;
const bottomMost = y + height - ( height * factor ) ;
if ( leftMost < bounds . x || topMost < bounds . y ) {
return false ;
}
2017-08-24 02:51:02 -05:00
return ! ( rightMost > bounds . x + bounds . width || bottomMost > bounds . y + bounds . height ) ;
2017-08-08 04:50:03 -05:00
} ) ;
}
/ * *
* Method that resets the main window bounds when an external display
* was removed and if the wrapper was contained within that bounds
* /
function repositionMainWindow ( ) {
const screen = electron . screen ;
const { workArea } = screen . getPrimaryDisplay ( ) ;
const bounds = workArea ;
if ( ! bounds ) {
return ;
}
const windowWidth = Math . round ( bounds . width * 0.6 ) ;
const windowHeight = Math . round ( bounds . height * 0.8 ) ;
// Calculating the center of the primary display
// to place the wrapper
const centerX = bounds . x + bounds . width / 2.0 ;
const centerY = bounds . y + bounds . height / 2.0 ;
const x = Math . round ( centerX - ( windowWidth / 2.0 ) ) ;
const y = Math . round ( centerY - ( windowHeight / 2.0 ) ) ;
let rectangle = { x , y , width : windowWidth , height : windowHeight } ;
// resetting the main window bounds
if ( mainWindow ) {
if ( ! mainWindow . isVisible ( ) ) {
mainWindow . show ( ) ;
}
if ( mainWindow . isMinimized ( ) ) {
mainWindow . restore ( ) ;
}
mainWindow . focus ( ) ;
mainWindow . flashFrame ( false ) ;
mainWindow . setBounds ( rectangle , true ) ;
}
}
2017-03-01 18:32:21 -06:00
module . exports = {
createMainWindow : createMainWindow ,
2017-03-06 23:09:10 -06:00
getMainWindow : getMainWindow ,
2017-03-01 18:32:21 -06:00
showMainWindow : showMainWindow ,
isMainWindow : isMainWindow ,
hasWindow : hasWindow ,
2017-04-18 11:02:25 -05:00
setIsOnline : setIsOnline ,
2017-04-20 13:54:11 -05:00
activate : activate ,
2017-08-08 04:50:03 -05:00
setBoundsChangeWindow : setBoundsChangeWindow ,
verifyDisplays : verifyDisplays
2017-03-01 18:32:21 -06:00
} ;