2017-03-01 16:32:21 -08:00
'use strict' ;
2017-11-10 14:13:41 +05:30
const fs = require ( 'fs' ) ;
2017-03-01 16:32:21 -08:00
const electron = require ( 'electron' ) ;
const app = electron . app ;
2018-04-30 17:32:10 +05:30
const electronSession = electron . session ;
2018-03-29 12:43:54 +05:30
const globalShortcut = electron . globalShortcut ;
2017-05-19 08:01:41 -07:00
const BrowserWindow = electron . BrowserWindow ;
2017-03-01 16:32:21 -08:00
const path = require ( 'path' ) ;
2017-04-18 09:02:25 -07:00
const nodeURL = require ( 'url' ) ;
2017-04-20 11:54:11 -07:00
const querystring = require ( 'querystring' ) ;
2017-06-27 20:38:58 +05:30
const filesize = require ( 'filesize' ) ;
2017-03-01 16:32:21 -08:00
2018-06-06 17:27:10 +05:30
const { getTemplate , getMinimizeOnClose , getTitleBarStyle } = require ( './menus/menuTemplate.js' ) ;
2017-03-01 16:32:21 -08:00
const loadErrors = require ( './dialogs/showLoadError.js' ) ;
2017-04-20 11:54:11 -07:00
const isInDisplayBounds = require ( './utils/isInDisplayBounds.js' ) ;
2017-03-09 10:12:28 -08:00
const getGuid = require ( './utils/getGuid.js' ) ;
2017-05-09 00:00:45 +05:30
const log = require ( './log.js' ) ;
2017-03-01 16:32:21 -08:00
const logLevels = require ( './enums/logLevels.js' ) ;
2017-04-06 10:07:58 -07:00
const notify = require ( './notify/electron-notify.js' ) ;
2017-06-15 22:41:29 +05:30
const eventEmitter = require ( './eventEmitter' ) ;
2017-04-20 11:54:11 -07:00
const throttle = require ( './utils/throttle.js' ) ;
2018-06-06 17:27:10 +05:30
const { getConfigField , updateConfigField , readConfigFileSync , getMultipleConfigField } = require ( './config.js' ) ;
2018-03-16 12:26:07 +05:30
const { isMac , isNodeEnv , isWindows10 , isWindowsOS } = require ( './utils/misc' ) ;
2018-05-21 17:04:24 +05:30
const { isWhitelisted , parseDomain } = require ( './utils/whitelistHandler' ) ;
2018-04-11 13:13:59 +00:00
const { initCrashReporterMain , initCrashReporterRenderer } = require ( './crashReporter.js' ) ;
2018-06-19 20:26:04 +05:30
const i18n = require ( './translation/i18n' ) ;
2018-06-25 14:36:20 +05:30
const getCmdLineArg = require ( './utils/getCmdLineArg' ) ;
2017-05-24 19:02:49 +05:30
2017-03-01 16:32:21 -08:00
// show dialog when certificate errors occur
require ( './dialogs/showCertError.js' ) ;
2017-10-18 12:17:09 +05:30
require ( './dialogs/showBasicAuth.js' ) ;
2017-03-01 16:32:21 -08:00
// 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 11:54:11 -07:00
let boundsChangeWindow ;
2017-06-15 22:41:29 +05:30
let alwaysOnTop = false ;
2017-06-17 03:59:56 +05:30
let position = 'lower-right' ;
let display ;
2017-07-14 12:57:38 +05:30
let sandboxed = false ;
2018-04-11 13:06:46 +00:00
let isAutoReload = false ;
2018-07-20 16:23:08 +05:30
let devToolsEnabled = true ;
2017-12-13 20:10:18 +05:30
2018-07-09 13:24:35 +05:30
const KeyCodes = {
Esc : 27 ,
} ;
2018-03-09 16:16:47 +05:30
// Application menu
let menu ;
2018-06-21 18:13:03 +05:30
let lang ;
2018-03-09 16:16:47 +05:30
2017-04-18 09:02:25 -07:00
// note: this file is built using browserify in prebuild step.
2017-03-07 14:44:31 -08:00
const preloadMainScript = path . join ( _ _dirname , 'preload/_preloadMain.js' ) ;
2017-03-01 16:32:21 -08:00
2017-05-11 11:11:42 -07:00
const MIN _WIDTH = 300 ;
2017-10-31 10:20:44 +05:30
const MIN _HEIGHT = 300 ;
// Default window size for pop-out windows
const DEFAULT _WIDTH = 300 ;
const DEFAULT _HEIGHT = 600 ;
2017-05-11 11:11:42 -07:00
2018-05-21 17:04:24 +05:30
// Certificate transparency whitelist
let ctWhitelist = [ ] ;
2017-08-24 16:18:32 +05:30
/ * *
* Adds a window key
* @ param key
* @ param browserWin
* /
2017-03-01 16:32:21 -08:00
function addWindowKey ( key , browserWin ) {
2017-05-09 00:00:45 +05:30
windows [ key ] = browserWin ;
2017-03-01 16:32:21 -08:00
}
2017-08-24 16:18:32 +05:30
/ * *
* Removes a window key
* @ param key
* /
2017-03-01 16:32:21 -08:00
function removeWindowKey ( key ) {
2017-05-09 00:00:45 +05:30
delete windows [ key ] ;
2017-03-01 16:32:21 -08:00
}
2017-08-24 16:18:32 +05:30
/ * *
* Gets the parsed url
2018-04-02 15:51:22 +05:30
* @ returns { Url }
2018-03-29 15:54:42 +05:30
* @ param appUrl
2017-08-24 16:18:32 +05:30
* /
2018-03-29 15:54:42 +05:30
function getParsedUrl ( appUrl ) {
let parsedUrl = nodeURL . parse ( appUrl ) ;
2018-04-02 15:51:22 +05:30
if ( ! parsedUrl . protocol || parsedUrl . protocol !== 'https:' ) {
2018-03-29 15:54:42 +05:30
parsedUrl . protocol = 'https:' ;
parsedUrl . slashes = true
}
let url = nodeURL . format ( parsedUrl ) ;
2018-04-02 15:51:22 +05:30
return nodeURL . parse ( url ) ;
2017-04-18 09:02:25 -07:00
}
2017-08-24 16:18:32 +05:30
/ * *
* Creates the main window
* @ param initialUrl
* /
2017-04-18 09:02:25 -07:00
function createMainWindow ( initialUrl ) {
2018-07-20 16:23:08 +05:30
let configParams = [ 'mainWinPos' , 'isCustomTitleBar' , 'locale' , 'devToolsEnabled' ] ;
getMultipleConfigField ( configParams )
2018-06-06 17:27:10 +05:30
. then ( configData => {
2018-07-20 16:23:08 +05:30
lang = configData && configData . locale || app . getLocale ( ) ;
devToolsEnabled = configData && configData . devToolsEnabled ;
2018-06-06 17:27:10 +05:30
doCreateMainWindow ( initialUrl , configData . mainWinPos , configData . isCustomTitleBar ) ;
2018-05-10 18:11:52 +05:30
} )
. catch ( ( ) => {
// failed use default bounds and frame
2018-06-21 18:13:03 +05:30
lang = app . getLocale ( ) ;
2018-06-06 17:27:10 +05:30
doCreateMainWindow ( initialUrl , null , false ) ;
2018-05-10 18:11:52 +05:30
} ) ;
2017-04-20 11:54:11 -07:00
}
2017-08-24 16:18:32 +05:30
/ * *
* Creates the main window with bounds
* @ param initialUrl
* @ param initialBounds
2018-06-06 17:27:10 +05:30
* @ param isCustomTitleBar
2017-08-24 16:18:32 +05:30
* /
2018-06-06 17:27:10 +05:30
function doCreateMainWindow ( initialUrl , initialBounds , isCustomTitleBar ) {
2017-04-18 09:02:25 -07:00
let url = initialUrl ;
2017-03-01 16:32:21 -08:00
let key = getGuid ( ) ;
2018-05-10 18:11:52 +05:30
const config = readConfigFileSync ( ) ;
2018-03-09 16:16:47 +05:30
// condition whether to enable custom Windows 10 title bar
2018-06-06 17:27:10 +05:30
const isCustomTitleBarEnabled = typeof isCustomTitleBar === 'boolean'
&& isCustomTitleBar
2018-05-10 18:11:52 +05:30
&& isWindows10 ( ) ;
2018-05-21 17:04:24 +05:30
log . send ( logLevels . INFO , ` we are configuring a custom title bar for windows -> ${ isCustomTitleBarEnabled } ` ) ;
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
ctWhitelist = config && config . ctWhitelist ;
log . send ( logLevels . INFO , ` we are configuring certificate transparency whitelist for the domains -> ${ ctWhitelist } ` ) ;
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
log . send ( logLevels . INFO , ` creating main window for ${ url } ` ) ;
2018-07-19 18:45:16 +05:30
2018-04-30 17:32:10 +05:30
if ( config && config !== null && config . customFlags ) {
2018-07-19 18:45:16 +05:30
2018-04-30 17:32:10 +05:30
log . send ( logLevels . INFO , 'Chrome flags config found!' ) ;
2018-07-19 18:45:16 +05:30
2018-04-30 17:32:10 +05:30
if ( config . customFlags . authServerWhitelist && config . customFlags . authServerWhitelist !== "" ) {
log . send ( logLevels . INFO , 'setting ntlm domains' ) ;
electronSession . defaultSession . allowNTLMCredentialsForDomains ( config . customFlags . authServerWhitelist ) ;
}
2018-07-19 18:45:16 +05:30
2018-04-30 17:32:10 +05:30
}
2018-07-19 18:45:16 +05:30
2017-04-18 09:02:25 -07:00
let newWinOpts = {
2017-03-01 16:32:21 -08:00
title : 'Symphony' ,
show : true ,
2017-05-11 11:11:42 -07:00
minWidth : MIN _WIDTH ,
minHeight : MIN _HEIGHT ,
2018-03-09 16:16:47 +05:30
frame : ! isCustomTitleBarEnabled ,
2017-06-15 22:41:29 +05:30
alwaysOnTop : false ,
2017-03-01 16:32:21 -08:00
webPreferences : {
2017-07-14 12:57:38 +05:30
sandbox : sandboxed ,
2017-07-10 13:09:10 +05:30
nodeIntegration : isNodeEnv ,
2017-03-07 14:44:31 -08:00
preload : preloadMainScript ,
2017-07-19 15:19:46 +05:30
nativeWindowOpen : true
2017-03-01 16:32:21 -08:00
}
2017-04-18 09:02:25 -07:00
} ;
2017-05-13 23:53:44 +05:30
// set size and position
2017-04-20 11:54:11 -07:00
let bounds = initialBounds ;
// if bounds if not fully contained in some display then use default size
// and position.
2018-05-22 14:29:28 +05:30
if ( ! isInDisplayBounds ( bounds ) || initialBounds . isMaximized || initialBounds . isFullScreen ) {
2017-04-20 11:54:11 -07:00
bounds = null ;
}
if ( bounds && bounds . width && bounds . height ) {
newWinOpts . width = bounds . width ;
newWinOpts . height = bounds . height ;
} else {
2017-12-15 11:23:21 +05:30
newWinOpts . width = 900 ;
newWinOpts . height = 900 ;
2017-04-20 11:54:11 -07:00
}
// 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 22:41:29 +05:30
// will set the main window on top as per the user prefs
2017-12-29 12:48:19 +05:30
if ( alwaysOnTop ) {
2017-06-15 22:41:29 +05:30
newWinOpts . alwaysOnTop = alwaysOnTop ;
}
2017-04-18 09:02:25 -07:00
// note: augmenting with some custom values
newWinOpts . winKey = key ;
2017-05-19 08:01:41 -07:00
mainWindow = new BrowserWindow ( newWinOpts ) ;
2017-04-18 09:02:25 -07:00
mainWindow . winName = 'main' ;
2017-03-01 16:32:21 -08:00
2018-05-22 14:29:28 +05:30
let throttledMainWinBoundsChange = throttle ( 1000 , saveMainWinBounds ) ;
2017-04-20 11:54:11 -07:00
mainWindow . on ( 'move' , throttledMainWinBoundsChange ) ;
2017-05-09 00:00:45 +05:30
mainWindow . on ( 'resize' , throttledMainWinBoundsChange ) ;
2018-07-09 13:24:35 +05:30
mainWindow . on ( 'enter-full-screen' , ( ) => {
const snackBarContent = i18n . getMessageFor ( 'SnackBar' ) ;
// event sent to renderer process to show snack bar
mainWindow . webContents . send ( 'window-enter-full-screen' , { snackBar : snackBarContent } ) ;
} ) ;
mainWindow . on ( 'leave-full-screen' , ( ) => {
// event sent to renderer process to remove snack bar
mainWindow . webContents . send ( 'window-leave-full-screen' ) ;
} ) ;
2017-04-20 11:54:11 -07:00
2018-05-22 14:29:28 +05:30
if ( initialBounds && ! isNodeEnv ) {
// maximizes the application if previously maximized
if ( initialBounds . isMaximized ) {
mainWindow . maximize ( ) ;
}
// Sets the application to full-screen if previously set to full-screen
if ( isMac && initialBounds . isFullScreen ) {
mainWindow . setFullScreen ( true ) ;
}
}
2017-03-01 16:32:21 -08:00
function retry ( ) {
2017-03-03 16:07:48 -08:00
if ( ! isOnline ) {
2017-03-01 16:32:21 -08:00
loadErrors . showNetworkConnectivityError ( mainWindow , url , retry ) ;
2017-03-03 16:07:48 -08:00
return ;
}
if ( mainWindow . webContents ) {
mainWindow . webContents . reload ( ) ;
2017-03-01 16:32:21 -08:00
}
}
2018-07-09 13:33:19 +05:30
// Event needed to hide native menu bar on Windows 10 as we use custom menu bar
mainWindow . webContents . once ( 'did-start-loading' , ( ) => {
if ( isWindows10 ( ) && mainWindow && ! mainWindow . isDestroyed ( ) ) {
mainWindow . setMenuBarVisibility ( false ) ;
}
} ) ;
2017-03-01 16:32:21 -08:00
// content can be cached and will still finish load but
2017-05-13 23:53:44 +05:30
// we might not have network connectivity, so warn the user.
2017-05-09 00:00:45 +05:30
mainWindow . webContents . on ( 'did-finish-load' , function ( ) {
2018-04-11 13:13:59 +00:00
// Initialize crash reporter
initCrashReporterMain ( { process : 'main window' } ) ;
initCrashReporterRenderer ( mainWindow , { process : 'render | main window' } ) ;
2017-04-18 09:02:25 -07:00
url = mainWindow . webContents . getURL ( ) ;
2018-07-09 13:24:35 +05:30
mainWindow . webContents . send ( 'on-page-load' ) ;
// initializes and applies styles required for snack bar
mainWindow . webContents . insertCSS ( fs . readFileSync ( path . join ( _ _dirname , '/snackBar/style.css' ) , 'utf8' ) . toString ( ) ) ;
2018-06-06 17:27:10 +05:30
if ( isCustomTitleBarEnabled || isWindows10 ( ) ) {
2018-03-09 16:16:47 +05:30
mainWindow . webContents . insertCSS ( fs . readFileSync ( path . join ( _ _dirname , '/windowsTitleBar/style.css' ) , 'utf8' ) . toString ( ) ) ;
// This is required to initiate Windows title bar only after insertCSS
2018-06-06 17:27:10 +05:30
const titleBarStyle = getTitleBarStyle ( ) ;
mainWindow . webContents . send ( 'initiate-windows-title-bar' , titleBarStyle ) ;
2018-03-09 16:16:47 +05:30
}
2017-04-18 09:02:25 -07:00
2017-03-01 16:32:21 -08:00
if ( ! isOnline ) {
loadErrors . showNetworkConnectivityError ( mainWindow , url , retry ) ;
} else {
2017-06-17 03:59:56 +05:30
// updates the notify config with user preference
2017-12-29 12:48:19 +05:30
notify . updateConfig ( { position : position , display : display } ) ;
2017-04-06 10:07:58 -07:00
// removes all existing notifications when main window reloads
notify . reset ( ) ;
2017-05-31 21:39:08 -07:00
log . send ( logLevels . INFO , 'loaded main window url: ' + url ) ;
2017-05-09 00:00:45 +05:30
2017-03-01 16:32:21 -08:00
}
2018-06-25 14:36:20 +05:30
// ELECTRON-540 - needed to automatically
// select desktop capture source
const screenShareArg = getCmdLineArg ( process . argv , '--auto-select-desktop-capture-source' , false ) ;
if ( screenShareArg && typeof screenShareArg === 'string' ) {
mainWindow . webContents . send ( 'screen-share-argv' , screenShareArg ) ;
}
2018-07-17 10:42:33 +05:30
if ( config && config . permissions ) {
const permission = ' screen sharing' ;
const fullMessage = i18n . getMessageFor ( 'Your administrator has disabled' ) + permission + '. ' + i18n . getMessageFor ( 'Please contact your admin for help' ) ;
const dialogContent = { type : 'error' , title : i18n . getMessageFor ( 'Permission Denied' ) + '!' , message : fullMessage } ;
mainWindow . webContents . send ( 'is-screen-share-enabled' , config . permissions . media , dialogContent ) ;
}
2017-03-01 16:32:21 -08:00
} ) ;
2017-05-09 00:00:45 +05:30
mainWindow . webContents . on ( 'did-fail-load' , function ( event , errorCode ,
2017-12-29 12:48:19 +05:30
errorDesc , validatedURL ) {
2017-09-14 16:30:13 +05:30
loadErrors . showLoadFailure ( mainWindow , validatedURL , errorDesc , errorCode , retry , false ) ;
2017-03-01 16:32:21 -08:00
} ) ;
2017-05-24 19:02:49 +05:30
// 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' ,
2018-06-19 20:26:04 +05:30
title : i18n . getMessageFor ( 'Renderer Process Crashed' ) ,
message : i18n . getMessageFor ( 'Oops! Looks like we have had a crash. Please reload or close this window.' ) ,
2017-05-24 19:02:49 +05:30
buttons : [ 'Reload' , 'Close' ]
} ;
2017-09-13 16:31:09 +05:30
electron . dialog . showMessageBox ( options , function ( index ) {
2017-05-24 19:02:49 +05:30
if ( index === 0 ) {
mainWindow . reload ( ) ;
}
2017-09-25 14:33:12 +05:30
else {
mainWindow . close ( ) ;
}
2017-05-24 19:02:49 +05:30
} ) ;
} ) ;
2018-07-19 18:45:16 +05:30
2018-03-29 12:43:54 +05:30
registerShortcuts ( ) ;
2018-03-20 17:49:27 +05:30
handlePermissionRequests ( mainWindow . webContents ) ;
2017-05-24 19:02:49 +05:30
2017-03-01 16:32:21 -08:00
addWindowKey ( key , mainWindow ) ;
mainWindow . loadURL ( url ) ;
2018-07-19 18:45:16 +05:30
2018-06-21 18:13:03 +05:30
rebuildMenu ( lang ) ;
2017-03-01 16:32:21 -08:00
2017-12-29 12:48:19 +05:30
mainWindow . on ( 'close' , function ( e ) {
2017-03-01 16:32:21 -08:00
if ( willQuitApp ) {
2017-04-18 09:02:25 -07:00
destroyAllWindows ( ) ;
2017-03-01 16:32:21 -08:00
return ;
}
2017-05-19 08:01:41 -07:00
if ( getMinimizeOnClose ( ) ) {
2017-03-01 16:32:21 -08:00
e . preventDefault ( ) ;
2017-05-19 08:01:41 -07:00
mainWindow . minimize ( ) ;
2018-06-13 18:09:32 +05:30
} else if ( isMac ) {
e . preventDefault ( ) ;
mainWindow . hide ( ) ;
2017-05-19 08:01:41 -07:00
} else {
2018-06-13 18:09:32 +05:30
app . quit ( ) ;
2017-03-01 16:32:21 -08:00
}
} ) ;
2017-04-18 09:02:25 -07:00
function destroyAllWindows ( ) {
2017-04-18 13:40:26 -07:00
let keys = Object . keys ( windows ) ;
2017-08-24 13:21:02 +05:30
for ( let i = 0 , len = keys . length ; i < len ; i ++ ) {
2017-04-18 09:02:25 -07:00
let winKey = keys [ i ] ;
removeWindowKey ( winKey ) ;
2017-03-03 16:07:48 -08:00
}
2017-04-18 09:02:25 -07:00
mainWindow = null ;
}
2017-03-01 16:32:21 -08:00
2017-04-18 09:02:25 -07:00
mainWindow . on ( 'closed' , destroyAllWindows ) ;
2018-07-19 18:45:16 +05:30
2017-06-27 20:38:58 +05:30
// 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' ) ;
2018-07-19 18:45:16 +05:30
2018-05-01 13:35:57 +05:30
// Send file path when download is complete
2017-07-02 18:23:34 +05:30
item . once ( 'done' , ( e , state ) => {
2017-06-27 20:38:58 +05:30
if ( state === 'completed' ) {
let data = {
_id : getGuid ( ) ,
savedPath : item . getSavePath ( ) ? item . getSavePath ( ) : '' ,
total : filesize ( item . getTotalBytes ( ) ? item . getTotalBytes ( ) : 0 ) ,
2018-05-01 13:35:57 +05:30
fileName : item . getFilename ( ) ? item . getFilename ( ) : 'No name'
2017-06-27 20:38:58 +05:30
} ;
webContents . send ( 'downloadCompleted' , data ) ;
}
} ) ;
} ) ;
2017-05-25 09:48:40 -07:00
// open external links in default browser - a tag with href='_blank' or window.open
2018-03-15 17:18:06 +05:30
mainWindow . webContents . on ( 'new-window' , handleNewWindow ) ;
2018-05-21 17:04:24 +05:30
mainWindow . webContents . session . setCertificateVerifyProc ( handleCertificateTransparencyChecks ) ;
2018-03-15 17:18:06 +05:30
function handleNewWindow ( event , newWinUrl , frameName , disposition , newWinOptions ) {
2018-07-19 18:45:16 +05:30
2017-04-20 11:54:11 -07:00
let newWinParsedUrl = getParsedUrl ( newWinUrl ) ;
let mainWinParsedUrl = getParsedUrl ( url ) ;
let newWinHost = newWinParsedUrl && newWinParsedUrl . host ;
let mainWinHost = mainWinParsedUrl && mainWinParsedUrl . host ;
2017-04-18 09:02:25 -07:00
2018-01-04 23:00:08 +05:30
let emptyUrlString = 'about:blank' ;
2018-02-23 17:01:16 +05:30
let dispositionWhitelist = [ 'new-window' , 'foreground-tab' ] ;
2017-05-25 09:48:40 -07:00
// only allow window.open to succeed is if coming from same hsot,
// otherwise open in default browser.
2018-02-23 17:15:31 +05:30
if ( ( newWinHost === mainWinHost || newWinUrl === emptyUrlString ) && dispositionWhitelist . includes ( disposition ) ) {
2017-04-18 09:02:25 -07:00
// handle: window.open
if ( ! frameName ) {
// abort - no frame name provided.
return ;
}
2017-04-18 13:40:26 -07:00
2017-05-31 21:39:08 -07:00
log . send ( logLevels . INFO , 'creating pop-out window url: ' + newWinParsedUrl ) ;
2017-04-20 11:54:11 -07:00
let x = 0 ;
let y = 0 ;
2017-10-31 10:20:44 +05:30
let width = newWinOptions . width || DEFAULT _WIDTH ;
let height = newWinOptions . height || DEFAULT _HEIGHT ;
2017-04-20 11:54:11 -07:00
// try getting x and y position from query parameters
2017-08-24 13:21:02 +05:30
let query = newWinParsedUrl && querystring . parse ( newWinParsedUrl . query ) ;
2017-04-20 11:54:11 -07:00
if ( query && query . x && query . y ) {
let newX = Number . parseInt ( query . x , 10 ) ;
let newY = Number . parseInt ( query . y , 10 ) ;
2017-12-29 12:48:19 +05:30
let newWinRect = { x : newX , y : newY , width , height } ;
2017-04-20 11:54:11 -07: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-12-29 12:48:19 +05:30
( { x , y } = getWindowSizeAndPosition ( mainWindow ) ) ;
2017-05-09 00:00:45 +05:30
x += 50 ;
y += 50 ;
2017-04-20 11:54:11 -07:00
}
2017-04-18 09:02:25 -07:00
2017-04-20 11:54:11 -07:00
/* eslint-disable no-param-reassign */
newWinOptions . x = x ;
newWinOptions . y = y ;
2017-10-31 10:20:44 +05:30
newWinOptions . width = Math . max ( width , DEFAULT _WIDTH ) ;
newWinOptions . height = Math . max ( height , DEFAULT _HEIGHT ) ;
2017-05-11 11:11:42 -07:00
newWinOptions . minWidth = MIN _WIDTH ;
newWinOptions . minHeight = MIN _HEIGHT ;
2017-06-15 22:41:29 +05:30
newWinOptions . alwaysOnTop = alwaysOnTop ;
2018-03-09 16:16:47 +05:30
newWinOptions . frame = true ;
2017-04-18 09:02:25 -07:00
2017-04-20 11:54:11 -07:00
let newWinKey = getGuid ( ) ;
2017-04-18 09:02:25 -07:00
2017-04-20 11:54:11 -07:00
newWinOptions . winKey = newWinKey ;
/* eslint-enable no-param-reassign */
2017-04-18 13:40:26 -07:00
2017-04-20 11:54:11 -07:00
let webContents = newWinOptions . webContents ;
2017-04-18 09:02:25 -07:00
2018-07-09 13:33:19 +05:30
// Event needed to hide native menu bar
webContents . once ( 'did-start-loading' , ( ) => {
let browserWin = BrowserWindow . fromWebContents ( webContents ) ;
if ( isWindowsOS && browserWin && ! browserWin . isDestroyed ( ) ) {
browserWin . setMenuBarVisibility ( false ) ;
}
} ) ;
2017-05-09 00:00:45 +05:30
webContents . once ( 'did-finish-load' , function ( ) {
2017-05-19 08:01:41 -07:00
let browserWin = BrowserWindow . fromWebContents ( webContents ) ;
2017-04-18 09:02:25 -07:00
2017-04-20 11:54:11 -07:00
if ( browserWin ) {
2017-05-31 21:39:08 -07:00
log . send ( logLevels . INFO , 'loaded pop-out window url: ' + newWinParsedUrl ) ;
2017-11-09 12:53:49 +05:30
if ( ! isMac ) {
// Removes the menu bar from the pop-out window
// setMenu is currently only supported on Windows and Linux
browserWin . setMenu ( null ) ;
}
2018-07-09 13:24:35 +05:30
browserWin . webContents . send ( 'on-page-load' ) ;
// applies styles required for snack bar
browserWin . webContents . insertCSS ( fs . readFileSync ( path . join ( _ _dirname , '/snackBar/style.css' ) , 'utf8' ) . toString ( ) ) ;
2017-11-09 12:53:49 +05:30
2018-04-11 13:13:59 +00:00
initCrashReporterMain ( { process : 'pop-out window' } ) ;
initCrashReporterRenderer ( browserWin , { process : 'render | pop-out window' } ) ;
2017-09-25 16:10:03 +05:30
2017-04-20 11:54:11 -07:00
browserWin . winName = frameName ;
2017-06-15 22:41:29 +05:30
browserWin . setAlwaysOnTop ( alwaysOnTop ) ;
2017-04-18 09:02:25 -07:00
2018-04-11 13:13:59 +00:00
let handleChildWindowCrashEvent = ( e ) => {
2017-09-25 16:10:03 +05:30
const options = {
type : 'error' ,
2018-06-19 20:26:04 +05:30
title : i18n . getMessageFor ( 'Renderer Process Crashed' ) ,
message : i18n . getMessageFor ( 'Oops! Looks like we have had a crash. Please reload or close this window.' ) ,
2017-09-25 16:10:03 +05:30
buttons : [ 'Reload' , 'Close' ]
} ;
2018-04-11 13:13:59 +00:00
let childBrowserWindow = BrowserWindow . fromWebContents ( e . sender ) ;
if ( childBrowserWindow && ! childBrowserWindow . isDestroyed ( ) ) {
electron . dialog . showMessageBox ( childBrowserWindow , options , function ( index ) {
if ( index === 0 ) {
childBrowserWindow . reload ( ) ;
} else {
childBrowserWindow . close ( ) ;
}
} ) ;
}
2017-10-08 19:32:44 +05:30
} ;
browserWin . webContents . on ( 'crashed' , handleChildWindowCrashEvent ) ;
2017-09-25 16:10:03 +05:30
2017-10-06 16:00:50 +05:30
// 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
2018-03-15 17:18:06 +05:30
browserWin . webContents . on ( 'new-window' , handleNewWindow . bind ( this ) ) ;
2017-09-25 16:10:03 +05:30
2017-04-20 11:54:11 -07:00
addWindowKey ( newWinKey , browserWin ) ;
2017-10-06 11:29:48 +05:30
// Method that sends bound changes as soon
// as a new window is created
// issue https://perzoinc.atlassian.net/browse/ELECTRON-172
sendChildWinBoundsChange ( browserWin ) ;
2018-07-09 13:24:35 +05:30
// throttle full screen
let throttledFullScreen = throttle ( 1000 ,
handleChildWindowFullScreen . bind ( null , browserWin ) ) ;
// throttle leave full screen
let throttledLeaveFullScreen = throttle ( 1000 ,
handleChildWindowLeaveFullScreen . bind ( null , browserWin ) ) ;
2017-04-20 11:54:11 -07:00
// throttle changes so we don't flood client.
let throttledBoundsChange = throttle ( 1000 ,
sendChildWinBoundsChange . bind ( null , browserWin ) ) ;
2018-07-09 13:24:35 +05:30
2017-04-20 11:54:11 -07:00
browserWin . on ( 'move' , throttledBoundsChange ) ;
2017-12-29 12:48:19 +05:30
browserWin . on ( 'resize' , throttledBoundsChange ) ;
2018-07-09 13:24:35 +05:30
browserWin . on ( 'enter-full-screen' , throttledFullScreen ) ;
browserWin . on ( 'leave-full-screen' , throttledLeaveFullScreen ) ;
2018-05-09 12:34:04 +05:30
let handleChildWindowClosed = ( ) => {
removeWindowKey ( newWinKey ) ;
browserWin . removeListener ( 'move' , throttledBoundsChange ) ;
browserWin . removeListener ( 'resize' , throttledBoundsChange ) ;
2018-07-09 13:24:35 +05:30
browserWin . removeListener ( 'enter-full-screen' , throttledFullScreen ) ;
browserWin . removeListener ( 'leave-full-screen' , throttledLeaveFullScreen ) ;
2018-05-09 12:34:04 +05:30
} ;
2018-07-19 18:45:16 +05:30
2018-05-09 12:34:04 +05:30
browserWin . on ( 'close' , ( ) => {
browserWin . webContents . removeListener ( 'new-window' , handleNewWindow ) ;
browserWin . webContents . removeListener ( 'crashed' , handleChildWindowCrashEvent ) ;
} ) ;
2018-07-19 18:45:16 +05:30
2018-05-09 12:34:04 +05:30
browserWin . once ( 'closed' , ( ) => {
handleChildWindowClosed ( ) ;
} ) ;
2018-07-19 18:45:16 +05:30
2018-03-20 17:49:27 +05:30
handlePermissionRequests ( browserWin . webContents ) ;
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
browserWin . webContents . session . setCertificateVerifyProc ( handleCertificateTransparencyChecks ) ;
2018-07-20 16:23:08 +05:30
browserWin . webContents . on ( 'devtools-opened' , ( ) => {
handleDevTools ( browserWin ) ;
} ) ;
2017-04-20 11:54:11 -07:00
}
} ) ;
2017-05-25 09:48:40 -07:00
} else {
event . preventDefault ( ) ;
2017-10-06 16:07:13 +05:30
openUrlInDefaultBrowser ( newWinUrl ) ;
2017-04-18 09:02:25 -07:00
}
2018-03-15 17:18:06 +05:30
}
2017-04-18 09:02:25 -07:00
2017-12-21 12:53:57 +05:30
// whenever the main window is navigated for ex: window.location.href or url redirect
2017-12-29 12:48:19 +05:30
mainWindow . webContents . on ( 'will-navigate' , function ( event , navigatedURL ) {
2017-12-21 13:52:05 +05:30
isWhitelisted ( navigatedURL )
2017-12-21 12:53:57 +05:30
. catch ( ( ) => {
event . preventDefault ( ) ;
electron . dialog . showMessageBox ( mainWindow , {
type : 'warning' ,
2017-12-29 12:48:19 +05:30
buttons : [ 'Ok' ] ,
2018-06-19 20:26:04 +05:30
title : i18n . getMessageFor ( 'Not Allowed' ) ,
message : i18n . getMessageFor ( 'Sorry, you are not allowed to access this website' ) + ' (' + navigatedURL + '), ' + i18n . getMessageFor ( 'please contact your administrator for more details' ) ,
2017-12-21 12:53:57 +05:30
} ) ;
} ) ;
2017-12-12 13:00:32 +05:30
} ) ;
2018-07-19 18:45:16 +05:30
2018-07-20 16:23:08 +05:30
mainWindow . webContents . on ( 'devtools-opened' , ( ) => {
handleDevTools ( mainWindow ) ;
} ) ;
2018-03-29 12:43:54 +05:30
/ * *
* Register shortcuts for the app
* /
function registerShortcuts ( ) {
2018-07-09 13:24:35 +05:30
function devTools ( ) {
const focusedWindow = BrowserWindow . getFocusedWindow ( ) ;
2018-03-29 12:43:54 +05:30
if ( focusedWindow && ! focusedWindow . isDestroyed ( ) ) {
focusedWindow . webContents . toggleDevTools ( ) ;
}
2018-07-09 13:24:35 +05:30
}
2018-07-20 12:20:34 +05:30
// This will initially register the global shortcut
globalShortcut . register ( isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I' , devTools ) ;
2018-07-09 13:24:35 +05:30
app . on ( 'browser-window-focus' , function ( ) {
globalShortcut . register ( isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I' , devTools ) ;
2018-03-29 12:43:54 +05:30
} ) ;
2018-07-09 13:24:35 +05:30
app . on ( 'browser-window-blur' , function ( ) {
globalShortcut . unregister ( isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I' ) ;
} ) ;
2018-03-29 12:43:54 +05:30
}
2018-07-19 18:45:16 +05:30
2018-03-29 12:43:54 +05:30
/ * *
* Sets permission requests for the window
* @ param webContents Web contents of the window
* /
2018-03-20 17:49:27 +05:30
function handlePermissionRequests ( webContents ) {
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
let session = webContents . session ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
getConfigField ( 'permissions' )
. then ( ( permissions ) => {
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
if ( ! permissions ) {
log . send ( logLevels . ERROR , 'permissions configuration is invalid, so, everything will be true by default!' ) ;
return ;
}
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
session . setPermissionRequestHandler ( ( sessionWebContents , permission , callback ) => {
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
function handleSessionPermissions ( userPermission , message , cb ) {
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
log . send ( logLevels . INFO , 'permission is -> ' + userPermission ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
if ( ! userPermission ) {
2018-07-17 10:42:33 +05:30
const fullMessage = ` ${ i18n . getMessageFor ( 'Your administrator has disabled' ) } ${ message } . ${ i18n . getMessageFor ( 'Please contact your admin for help' ) } ` ;
2018-05-21 17:03:46 +05:30
const browserWindow = BrowserWindow . getFocusedWindow ( ) ;
if ( browserWindow && ! browserWindow . isDestroyed ( ) ) {
2018-07-17 10:42:33 +05:30
electron . dialog . showMessageBox ( browserWindow , { type : 'error' , title : ` ${ i18n . getMessageFor ( 'Permission Denied' ) } ! ` , message : fullMessage } ) ;
2018-05-21 17:03:46 +05:30
}
2018-03-20 17:49:27 +05:30
}
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
return cb ( userPermission ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
}
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
let PERMISSION _MEDIA = 'media' ;
let PERMISSION _LOCATION = 'geolocation' ;
let PERMISSION _NOTIFICATIONS = 'notifications' ;
let PERMISSION _MIDI _SYSEX = 'midiSysex' ;
let PERMISSION _POINTER _LOCK = 'pointerLock' ;
let PERMISSION _FULL _SCREEN = 'fullscreen' ;
let PERMISSION _OPEN _EXTERNAL = 'openExternal' ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
switch ( permission ) {
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _MEDIA :
return handleSessionPermissions ( permissions . media , 'sharing your camera, microphone, and speakers' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _LOCATION :
return handleSessionPermissions ( permissions . geolocation , 'sharing your location' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _NOTIFICATIONS :
return handleSessionPermissions ( permissions . notifications , 'notifications' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _MIDI _SYSEX :
return handleSessionPermissions ( permissions . midiSysex , 'MIDI Sysex' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _POINTER _LOCK :
return handleSessionPermissions ( permissions . pointerLock , 'Pointer Lock' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _FULL _SCREEN :
return handleSessionPermissions ( permissions . fullscreen , 'Full Screen' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
case PERMISSION _OPEN _EXTERNAL :
return handleSessionPermissions ( permissions . openExternal , 'Opening External App' , callback ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
default :
return callback ( false ) ;
}
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
} ) ;
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
} ) . catch ( ( error ) => {
log . send ( logLevels . ERROR , 'unable to get permissions configuration, so, everything will be true by default! ' + error ) ;
} )
2018-05-21 17:03:46 +05:30
2018-03-20 17:49:27 +05:30
}
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
function handleCertificateTransparencyChecks ( request , callback ) {
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
const { hostname : hostUrl , errorCode } = request ;
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
if ( errorCode === 0 ) {
return callback ( 0 ) ;
}
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
let { tld , domain } = parseDomain ( hostUrl ) ;
let host = domain + tld ;
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
if ( ctWhitelist && Array . isArray ( ctWhitelist ) && ctWhitelist . length > 0 && ctWhitelist . indexOf ( host ) > - 1 ) {
return callback ( 0 ) ;
}
2018-07-19 18:45:16 +05:30
2018-05-21 17:04:24 +05:30
return callback ( - 2 ) ;
}
2017-12-12 13:00:32 +05:30
2018-07-20 16:23:08 +05:30
function handleDevTools ( browserWindow ) {
if ( ! devToolsEnabled ) {
log . send ( logLevels . INFO , ` dev tools disabled for ${ browserWindow . winName } window ` ) ;
browserWindow . webContents . closeDevTools ( ) ;
electron . dialog . showMessageBox ( browserWindow , {
type : 'warning' ,
buttons : [ 'Ok' ] ,
title : i18n . getMessageFor ( 'Dev Tools disabled' ) ,
message : i18n . getMessageFor ( 'Dev Tools has been disabled! Please contact your system administrator to enable it!' ) ,
} ) ;
}
}
2017-03-01 16:32:21 -08:00
}
2017-08-24 16:18:32 +05:30
/ * *
* Handles the event before - quit emitted by electron
* /
2017-05-09 00:00:45 +05:30
app . on ( 'before-quit' , function ( ) {
2017-03-01 16:32:21 -08:00
willQuitApp = true ;
} ) ;
2017-08-24 16:18:32 +05:30
/ * *
* Saves the main window bounds
* /
2017-04-20 11:54:11 -07:00
function saveMainWinBounds ( ) {
let newBounds = getWindowSizeAndPosition ( mainWindow ) ;
2018-05-22 14:29:28 +05:30
// set application full-screen and maximized state
if ( mainWindow && ! mainWindow . isDestroyed ( ) ) {
newBounds . isMaximized = mainWindow . isMaximized ( ) ;
newBounds . isFullScreen = mainWindow . isFullScreen ( ) ;
}
2017-04-20 11:54:11 -07:00
if ( newBounds ) {
updateConfigField ( 'mainWinPos' , newBounds ) ;
}
}
2017-08-24 16:18:32 +05:30
/ * *
* Gets the main window
* @ returns { * }
* /
2017-03-06 21:09:10 -08:00
function getMainWindow ( ) {
return mainWindow ;
}
2018-03-09 16:16:47 +05:30
/ * *
* Gets the application menu
* @ returns { * }
* /
function getMenu ( ) {
return menu ;
}
2017-08-24 16:18:32 +05:30
/ * *
* Gets a window ' s size and position
* @ param window
* @ returns { * }
* /
2017-04-20 11:54:11 -07:00
function getWindowSizeAndPosition ( window ) {
2017-05-25 09:48:40 -07: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 11:54:11 -07:00
}
return null ;
}
2017-08-24 16:18:32 +05:30
/ * *
* Shows the main window
* /
2017-03-01 16:32:21 -08:00
function showMainWindow ( ) {
2018-06-12 15:17:02 +05:30
if ( mainWindow ) {
mainWindow . show ( ) ;
}
2017-03-01 16:32:21 -08:00
}
2017-08-24 16:18:32 +05:30
/ * *
* Tells if a window is the main window
* @ param win
* @ returns { boolean }
* /
2017-03-01 16:32:21 -08:00
function isMainWindow ( win ) {
return mainWindow === win ;
}
2017-08-24 16:18:32 +05:30
/ * *
* Checks if the window and a key has a window
* @ param win
* @ param winKey
* @ returns { * }
* /
2017-03-01 16:32:21 -08:00
function hasWindow ( win , winKey ) {
2017-05-19 08:01:41 -07:00
if ( win instanceof BrowserWindow ) {
2017-05-09 00:00:45 +05:30
let browserWin = windows [ winKey ] ;
2017-03-01 16:32:21 -08:00
return browserWin && win === browserWin ;
}
return false ;
}
2017-08-24 16:18:32 +05:30
/ * *
* Sets if a user is online
* @ param status
* /
2017-03-01 16:32:21 -08:00
function setIsOnline ( status ) {
isOnline = status ;
}
2017-04-20 11:54:11 -07:00
/ * *
2017-10-08 19:32:44 +05:30
* Tries finding a window we have created with given name . If found , then
2017-04-20 11:54:11 -07:00
* brings to front and gives focus .
2018-03-16 12:26:07 +05:30
* @ param { String } windowName Name of target window . Note : main window has
2017-04-20 11:54:11 -07:00
* name 'main' .
2018-03-16 12:26:07 +05:30
* @ param { Boolean } shouldFocus whether to get window to focus or just show
* without giving focus
2017-04-20 11:54:11 -07:00
* /
2018-03-16 12:26:07 +05:30
function activate ( windowName , shouldFocus = true ) {
2018-04-11 13:06:46 +00:00
// don't activate when the app is reloaded programmatically
// Electron-136
if ( isAutoReload ) {
return null ;
}
2017-04-18 13:40:26 -07:00
let keys = Object . keys ( windows ) ;
2017-05-09 00:00:45 +05:30
for ( let i = 0 , len = keys . length ; i < len ; i ++ ) {
2017-04-18 13:40:26 -07:00
let window = windows [ keys [ i ] ] ;
2017-05-08 10:44:00 -07:00
if ( window && ! window . isDestroyed ( ) && window . winName === windowName ) {
2018-03-16 12:26:07 +05:30
// Flash task bar icon in Windows
if ( isWindowsOS && ! shouldFocus ) {
return window . flashFrame ( true ) ;
}
// brings window without giving focus on mac
if ( isMac && ! shouldFocus ) {
return window . showInactive ( ) ;
}
2017-05-08 10:44:00 -07:00
if ( window . isMinimized ( ) ) {
2018-03-16 12:26:07 +05:30
return window . restore ( ) ;
2017-05-08 10:44:00 -07:00
}
2018-03-16 12:26:07 +05:30
return window . show ( ) ;
2017-04-18 09:02:25 -07:00
}
}
2018-03-16 12:26:07 +05:30
return null ;
2017-04-18 09:02:25 -07:00
}
2018-04-11 13:06:46 +00:00
/ * *
* Sets if is auto reloading the app
* @ param reload
* /
function setIsAutoReload ( reload ) {
if ( typeof reload === 'boolean' ) {
isAutoReload = reload
}
}
2017-04-20 11:54:11 -07: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 09:46:15 -07:00
// ipc msg back to renderer to inform bounds has changed.
2017-04-20 11:54:11 -07:00
boundsChangeWindow . send ( 'boundsChange' , newBounds ) ;
}
}
2018-07-09 13:24:35 +05:30
/ * *
* Called when the child window is set to full screen
* /
function handleChildWindowFullScreen ( browserWindow ) {
const snackBarContent = i18n . getMessageFor ( 'SnackBar' ) ;
browserWindow . webContents . send ( 'window-enter-full-screen' , { snackBar : snackBarContent } ) ;
}
/ * *
* Called when the child window left full screen
* /
function handleChildWindowLeaveFullScreen ( browserWindow ) {
browserWindow . webContents . send ( 'window-leave-full-screen' ) ;
}
2017-08-24 16:18:32 +05:30
/ * *
* Opens an external url in the system ' s default browser
* @ param urlToOpen
* /
2017-10-06 16:07:13 +05:30
function openUrlInDefaultBrowser ( urlToOpen ) {
2017-12-29 12:48:19 +05:30
if ( urlToOpen ) {
2017-05-25 09:48:40 -07:00
electron . shell . openExternal ( urlToOpen ) ;
}
}
2017-06-15 22:41:29 +05:30
/ * *
* Called when an event is received from menu
2018-05-09 14:49:18 +05:30
* @ param { boolean } boolean whether to enable or disable alwaysOnTop .
* @ param { boolean } shouldActivateMainWindow whether to activate main window
2017-06-15 22:41:29 +05:30
* /
2018-05-09 14:49:18 +05:30
function isAlwaysOnTop ( boolean , shouldActivateMainWindow = true ) {
2017-06-15 22:41:29 +05:30
alwaysOnTop = boolean ;
let browserWins = BrowserWindow . getAllWindows ( ) ;
if ( browserWins . length > 0 ) {
2018-05-07 14:52:02 +05:30
browserWins
. filter ( ( browser ) => typeof browser . notfyObj !== 'object' )
. forEach ( function ( browser ) {
browser . setAlwaysOnTop ( boolean ) ;
} ) ;
2017-11-21 11:40:04 +05:30
// An issue where changing the alwaysOnTop property
// focus the pop-out window
2018-05-09 14:49:18 +05:30
// Issue - Electron-209/470
if ( mainWindow && mainWindow . winName && shouldActivateMainWindow ) {
2017-11-21 11:40:04 +05:30
activate ( mainWindow . winName ) ;
}
2017-06-15 22:41:29 +05:30
}
}
// node event emitter to update always on top
2018-05-09 14:49:18 +05:30
eventEmitter . on ( 'isAlwaysOnTop' , ( params ) => {
isAlwaysOnTop ( params . isAlwaysOnTop , params . shouldActivateMainWindow ) ;
2017-06-15 22:41:29 +05:30
} ) ;
2017-06-17 03:59:56 +05:30
// node event emitter for notification settings
eventEmitter . on ( 'notificationSettings' , ( notificationSettings ) => {
position = notificationSettings . position ;
display = notificationSettings . display ;
} ) ;
2018-06-19 20:26:04 +05:30
eventEmitter . on ( 'language-changed' , ( opts ) => {
2018-06-25 15:13:38 +05:30
const language = opts && opts . language || app . getLocale ( ) ;
log . send ( logLevels . INFO , ` language changed to ${ language } . Updating menu and user config ` ) ;
rebuildMenu ( language ) ;
updateConfigField ( 'locale' , language ) ;
2018-06-19 20:26:04 +05:30
} ) ;
function rebuildMenu ( language ) {
setLanguage ( language ) ;
menu = electron . Menu . buildFromTemplate ( getTemplate ( app ) ) ;
2018-07-09 13:33:19 +05:30
electron . Menu . setApplicationMenu ( menu ) ;
2018-06-19 20:26:04 +05:30
}
2018-06-25 15:33:11 +05:30
function setLanguage ( language ) {
i18n . setLanguage ( language ) ;
2018-06-19 20:26:04 +05:30
}
2017-08-08 15:20:03 +05:30
/ * *
* 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
2017-12-29 12:48:19 +05:30
if ( ! mainWindow || isMac ) {
2017-08-08 15:20:03 +05:30
return ;
}
const bounds = mainWindow . getBounds ( ) ;
if ( bounds ) {
let isXAxisValid = true ;
let isYAxisValid = true ;
// checks to make sure the x,y are valid pairs
2017-12-29 12:48:19 +05:30
if ( ( bounds . x === undefined && ( bounds . y || bounds . y === 0 ) ) ) {
2017-08-08 15:20:03 +05:30
isXAxisValid = false ;
}
2017-12-29 12:48:19 +05:30
if ( ( bounds . y === undefined && ( bounds . x || bounds . x === 0 ) ) ) {
2017-08-08 15:20:03 +05:30
isYAxisValid = false ;
}
2017-12-29 12:48:19 +05:30
if ( ! isXAxisValid && ! isYAxisValid ) {
2017-08-08 15:20:03 +05:30
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 ;
2018-07-19 18:45:16 +05:30
2017-08-08 15:20:03 +05:30
// Loops through all the available displays and
// verifies if the wrapper exists within the display bounds
// returns false if not exists otherwise true
2018-03-20 17:49:27 +05:30
return ! ! electron . screen . getAllDisplays ( ) . find ( ( { bounds } ) => {
2017-08-08 15:20:03 +05:30
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 13:21:02 +05:30
return ! ( rightMost > bounds . x + bounds . width || bottomMost > bounds . y + bounds . height ) ;
2017-08-08 15:20:03 +05:30
} ) ;
}
/ * *
* Method that resets the main window bounds when an external display
* was removed and if the wrapper was contained within that bounds
* /
function repositionMainWindow ( ) {
2018-07-19 18:45:16 +05:30
2018-03-20 17:49:27 +05:30
const { workArea } = electron . screen . getPrimaryDisplay ( ) ;
2017-08-08 15:20:03 +05:30
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 ) ) ;
2017-12-29 12:48:19 +05:30
let rectangle = { x , y , width : windowWidth , height : windowHeight } ;
2017-08-08 15:20:03 +05:30
// resetting the main window bounds
2017-12-29 12:48:19 +05:30
if ( mainWindow ) {
2017-08-08 15:20:03 +05:30
if ( ! mainWindow . isVisible ( ) ) {
mainWindow . show ( ) ;
}
if ( mainWindow . isMinimized ( ) ) {
mainWindow . restore ( ) ;
}
mainWindow . focus ( ) ;
mainWindow . flashFrame ( false ) ;
mainWindow . setBounds ( rectangle , true ) ;
}
}
2018-07-09 13:24:35 +05:30
/ * *
* Method that handles key press
* @ param keyCode { number }
* /
function handleKeyPress ( keyCode ) {
switch ( keyCode ) {
case KeyCodes . Esc : {
const focusedWindow = BrowserWindow . getFocusedWindow ( ) ;
if ( focusedWindow && ! focusedWindow . isDestroyed ( ) && focusedWindow . isFullScreen ( ) ) {
focusedWindow . setFullScreen ( false ) ;
}
break ;
}
default :
break ;
}
}
2017-03-01 16:32:21 -08:00
module . exports = {
createMainWindow : createMainWindow ,
2017-03-06 21:09:10 -08:00
getMainWindow : getMainWindow ,
2017-03-01 16:32:21 -08:00
showMainWindow : showMainWindow ,
isMainWindow : isMainWindow ,
hasWindow : hasWindow ,
2017-04-18 09:02:25 -07:00
setIsOnline : setIsOnline ,
2017-04-20 11:54:11 -07:00
activate : activate ,
2017-08-08 15:20:03 +05:30
setBoundsChangeWindow : setBoundsChangeWindow ,
2018-03-09 16:16:47 +05:30
verifyDisplays : verifyDisplays ,
2018-04-11 13:06:46 +00:00
getMenu : getMenu ,
2018-07-09 13:24:35 +05:30
setIsAutoReload : setIsAutoReload ,
handleKeyPress : handleKeyPress
2017-03-01 16:32:21 -08:00
} ;