'use strict' ;
const { app , protocol , BrowserWindow , dialog , shell , Menu , ipcMain } = require ( 'electron' ) ;
// Menu
const appMenu = require ( './menu' ) ;
// Tray
const tray = require ( './tray' ) ;
// Window State Plugin
const windowStateKeeper = require ( 'electron-window-state' ) ;
// Global Settings
var globalSettings = require ( './global_settings.js' ) ;
const isDev = require ( 'electron-is-dev' ) ;
const updater = require ( './updater' ) ;
// this should be placed at top of main.js to handle setup events quickly
if ( handleSquirrelEvent ( ) ) {
// squirrel event handled and app will exit in 1000ms, so don't do anything else
return ;
}
function handleSquirrelEvent ( ) {
if ( process . argv . length === 1 ) {
return false ;
}
const ChildProcess = require ( 'child_process' ) ;
const path = require ( 'path' ) ;
const appFolder = path . resolve ( process . execPath , '..' ) ;
const rootAtomFolder = path . resolve ( appFolder , '..' ) ;
const updateDotExe = path . resolve ( path . join ( rootAtomFolder , 'Update.exe' ) ) ;
const exeName = path . basename ( process . execPath ) ;
const spawn = function ( command , args ) {
let spawnedProcess , error ;
try {
spawnedProcess = ChildProcess . spawn ( command , args , { detached : true } ) ;
} catch ( error ) { }
return spawnedProcess ;
} ;
const spawnUpdate = function ( args ) {
return spawn ( updateDotExe , args ) ;
} ;
const squirrelEvent = process . argv [ 1 ] ;
switch ( squirrelEvent ) {
case '--squirrel-install' :
case '--squirrel-updated' :
// Optionally do things such as:
// - Add your .exe to the PATH
// - Write to the registry for things like file associations and
// explorer context menus
// Install desktop and start menu shortcuts
spawnUpdate ( [ '--createShortcut' , exeName ] ) ;
setTimeout ( app . quit , 1000 ) ;
return true ;
case '--squirrel-uninstall' :
// Undo anything you did in the --squirrel-install and
// --squirrel-updated handlers
// Remove desktop and start menu shortcuts
spawnUpdate ( [ '--removeShortcut' , exeName ] ) ;
setTimeout ( app . quit , 1000 ) ;
return true ;
case '--squirrel-obsolete' :
// This is called on the outgoing version of your app before
// we update to the new version - it's the opposite of
// --squirrel-updated
app . quit ( ) ;
return true ;
}
} ;
// 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 isQuitting = false ;
function createWindow ( ) {
// Load the previous state with fallback to defaults
let mainWindowState = windowStateKeeper ( {
defaultWidth : 1000
, defaultHeight : 800
, maximize : false
} ) ;
// Create the browser window using the state information
mainWindow = new BrowserWindow ( {
title : 'Rambox'
, icon : _ _dirname + '/../resources/Icon.ico'
, x : mainWindowState . x
, y : mainWindowState . y
, width : mainWindowState . width
, height : mainWindowState . height
, backgroundColor : '#2E658E'
, alwaysOnTop : parseInt ( globalSettings . get ( 'always_on_top' ) ) ? true : false
, autoHideMenuBar : parseInt ( globalSettings . get ( 'hide_menu_bar' ) ) ? true : false
, skipTaskbar : parseInt ( globalSettings . get ( 'skip_taskbar' ) ) ? true : false
, show : parseInt ( globalSettings . get ( 'start_minimized' ) ) ? false : true
, webPreferences : {
webSecurity : false
, nodeIntegration : true
, plugins : true
, partition : 'persist:rambox'
}
} ) ;
if ( ! parseInt ( globalSettings . get ( 'start_minimized' ) ) && mainWindowState . isMaximized ) mainWindow . maximize ( ) ;
// Let us register listeners on the window, so we can update the state
// automatically (the listeners will be removed when the window is closed)
// and restore the maximized or full screen state
mainWindowState . manage ( mainWindow ) ;
process . setMaxListeners ( 10000 ) ;
// and load the index.html of the app.
mainWindow . loadURL ( 'file://' + _ _dirname + '/../index.html' ) ;
Menu . setApplicationMenu ( appMenu ) ;
tray . create ( mainWindow , mainWindowState ) ;
if ( ! isDev && process . platform === 'win32' ) updater . initialize ( mainWindow ) ;
mainWindow . on ( 'page-title-updated' , ( e , title ) => updateBadge ( title ) ) ;
// Open links in default browser
mainWindow . webContents . on ( 'new-window' , function ( e , url , frameName , disposition , options ) {
if ( disposition !== 'foreground-tab' ) return ;
const protocol = require ( 'url' ) . parse ( url ) . protocol ;
if ( protocol === 'http:' || protocol === 'https:' || protocol === 'mailto:' ) {
e . preventDefault ( ) ;
shell . openExternal ( url ) ;
}
} ) ;
mainWindow . webContents . on ( 'will-navigate' , function ( event , url ) {
event . preventDefault ( ) ;
} ) ;
mainWindow . on ( 'app-command' , ( e , cmd ) => {
// Navigate the window back when the user hits their mouse back button
if ( cmd === 'browser-backward' ) mainWindow . webContents . executeJavaScript ( 'Ext.cq1("app-main").getActiveTab().goBack();' ) ;
// Navigate the window forward when the user hits their mouse forward button
if ( cmd === 'browser-forward' ) mainWindow . webContents . executeJavaScript ( 'Ext.cq1("app-main").getActiveTab().goForward();' ) ;
} ) ;
mainWindow . on ( 'focus' , ( e ) => {
// Make focus on current service when user use Alt + Tab to activate Rambox
} ) ;
// Emitted when the window is closed.
mainWindow . on ( 'close' , function ( e ) {
if ( ! isQuitting ) {
e . preventDefault ( ) ;
if ( process . platform === 'darwin' ) {
app . hide ( ) ;
} else {
parseInt ( globalSettings . get ( 'keep_in_taskbar_on_close' ) ) ? mainWindow . minimize ( ) : mainWindow . hide ( ) ;
}
}
} ) ;
mainWindow . on ( 'closed' , function ( e ) {
mainWindow = null ;
} ) ;
}
function updateBadge ( title ) {
var messageCount = title . match ( /\d+/g ) ? parseInt ( title . match ( /\d+/g ) . join ( "" ) ) : 0 ;
if ( process . platform === 'win32' ) {
tray . setBadge ( messageCount ) ;
}
app . setBadgeCount ( messageCount ) ;
}
const shouldQuit = app . makeSingleInstance ( ( commandLine , workingDirectory ) => {
// Someone tried to run a second instance, we should focus our window.
if ( mainWindow ) {
if ( mainWindow . isMinimized ( ) ) mainWindow . restore ( ) ;
mainWindow . focus ( ) ;
}
} ) ;
if ( shouldQuit ) {
app . quit ( ) ;
return ;
}
var allowedURLCertificates = [ ] ;
ipcMain . on ( 'allowCertificate' , ( event , url ) => {
allowedURLCertificates . push ( require ( 'url' ) . parse ( url ) . host ) ;
} ) ;
app . on ( 'certificate-error' , function ( event , webContents , url , error , certificate , callback ) {
if ( allowedURLCertificates . indexOf ( require ( 'url' ) . parse ( url ) . host ) >= 0 ) {
event . preventDefault ( ) ;
callback ( true ) ;
} else {
callback ( false ) ;
dialog . showMessageBox ( mainWindow , {
title : 'Certification Error'
, message : 'The service with the following URL has an invalid authority certification.\n\n' + url + '\n\nYou have to remove the service and add it again, enabling the "Trust invalid authority certificates" in the Options.'
, buttons : [ 'OK' ]
, type : 'error'
} , function ( ) {
} ) ;
}
} ) ;
// Code for downloading images as temporal files
// Credit: Ghetto Skype (https://github.com/stanfieldr/ghetto-skype)
const tmp = require ( 'tmp' ) ;
const mime = require ( 'mime' ) ;
var imageCache = { } ;
ipcMain . on ( 'image:download' , function ( event , url , partition ) {
let file = imageCache [ url ] ;
if ( file ) {
if ( file . complete ) {
shell . openItem ( file . path ) ;
}
// Pending downloads intentionally do not proceed
return ;
}
let tmpWindow = new BrowserWindow ( {
show : false
, webPreferences : {
partition : partition
}
} ) ;
tmpWindow . webContents . session . once ( 'will-download' , ( event , downloadItem ) => {
imageCache [ url ] = file = {
path : tmp . tmpNameSync ( ) + '.' + mime . extension ( downloadItem . getMimeType ( ) )
, complete : false
} ;
downloadItem . setSavePath ( file . path ) ;
downloadItem . once ( 'done' , ( ) => {
tmpWindow . destroy ( ) ;
tmpWindow = null ;
shell . openItem ( file . path ) ;
file . complete = true ;
} ) ;
} ) ;
tmpWindow . webContents . downloadURL ( url ) ;
} ) ;
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app . on ( 'ready' , createWindow ) ;
// 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 ( ) ;
}
} ) ;
app . on ( 'activate' , function ( ) {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if ( mainWindow === null ) {
createWindow ( ) ;
}
} ) ;
app . on ( 'before-quit' , function ( ) {
isQuitting = true ;
} ) ;