'use strict' ; import fs from 'fs-jetpack' ; import log from 'electron-log' ; import { autoUpdater } from 'electron-updater' ; import { FILE_EXTENSION , WINDOW_TYPE , MAX_RECENTS } from './constants' ; import { app , protocol , dialog , BrowserWindow , ipcMain as ipc , Event } from 'electron' ; import { createProtocol , installVueDevtools } from 'vue-cli-plugin-electron-builder/lib' ; import { setWindowMenu , setAppMenu } from './menu' ; import Store from 'electron-store' ; const isDevelopment = process . env . NODE_ENV !== 'production' ; protocol . registerStandardSchemes ( [ 'app' ] , { secure : true } ) ; app . commandLine . appendSwitch ( '--ignore-gpu-blacklist' ) ; const store = new Store ( { defaults : { recents : [ ] as string [ ] } } ) ; let welcomeWindow ; const playgroundWindows = new Set ( ) ; const openFiles = new Map ( ) ; function newWelcomeWindow ( hidden = false ) { const window = new BrowserWindow ( { title : 'Welcome' , show : false , width : 650 , height : 400 , minimizable : false , maximizable : false , resizable : false , fullscreenable : false , frame : false , backgroundColor : '#3c3c3c' , webPreferences : { enableBlinkFeatures : 'OverlayScrollbars' } } ) ; loadWindowContents ( window , WINDOW_TYPE . WELCOME ) ; setMenu ( window , WINDOW_TYPE . WELCOME ) ; window . on ( 'close' , ( event ) => { if ( playgroundWindows . size === 0 && ( process . platform !== 'darwin' || appQuitting ) ) { window . destroy ( ) ; } else { event . preventDefault ( ) ; window . hide ( ) ; } } ) ; window . webContents . on ( 'did-finish-load' , ( ) => { window . webContents . send ( 'recents' , recents ) ; if ( ! isDevelopment ) autoUpdater . checkForUpdates ( ) ; if ( ! hidden ) window . show ( ) ; } ) ; return window ; } function newPlaygroundWindow ( filePath ? ) { const window = new BrowserWindow ( { show : false , width : 1000 , height : 700 , minWidth : 700 , minHeight : 600 , useContentSize : true , titleBarStyle : 'hidden' , backgroundColor : '#3c3c3c' , webPreferences : { experimentalFeatures : true , enableBlinkFeatures : 'OverlayScrollbars' } } ) ; loadWindowContents ( window , WINDOW_TYPE . PLAYGROUND ) ; setMenu ( window , WINDOW_TYPE . PLAYGROUND ) ; adjustPlaygroundWindowPosition ( window ) ; window . on ( 'close' , ( event ) => { event . preventDefault ( ) ; window . webContents . send ( 'close' ) ; } ) ; window . on ( 'closed' , ( ) => { playgroundWindows . delete ( window ) ; } ) ; window . webContents . on ( 'did-finish-load' , ( ) => { if ( filePath ) { window . webContents . send ( 'open' , filePath ) ; } else { window . webContents . send ( 'new' ) ; } } ) ; return window ; } ipc . on ( 'close-window' , ( event , proceed , openFile ) => { const window = BrowserWindow . fromWebContents ( event . sender ) ; if ( proceed ) { window . destroy ( ) ; if ( openFile ) { openFiles . delete ( openFile ) ; } if ( playgroundWindows . size === 0 ) { if ( appQuitting ) { app . quit ( ) ; } else { showWelcomeWindow ( ) ; } } } else { appQuitting = false ; } } ) ; ipc . on ( 'opened-file' , ( event , filePath ) => { const window = BrowserWindow . fromWebContents ( event . sender ) ; openFiles . set ( filePath , window ) ; addToRecentDocuments ( filePath ) ; } ) ; ipc . on ( 'open-file' , ( event , filePath ? ) => { if ( filePath ) { openFile ( filePath ) ; } else { showOpenFileDialog ( ) ; } } ) ; ipc . on ( 'new-file' , ( ) => { newFile ( ) ; } ) ; let appQuitting = false ; let triggerFiles = new Set ( ) ; const gotTheLock = app . requestSingleInstanceLock ( ) ; if ( ! gotTheLock ) { app . quit ( ) ; } else { app . on ( 'second-instance' , ( event , argv ) => { app . focus ( ) ; const window = BrowserWindow . getFocusedWindow ( ) ; if ( window ) window . focus ( ) ; if ( process . platform === 'win32' && app . isReady ( ) && argv . length > 1 && argv [ 1 ] !== '--updated' ) openFile ( argv [ 1 ] ) ; } ) ; } app . on ( 'ready' , async ( ) => { if ( isDevelopment && ! process . env . IS_TEST ) { await installVueDevtools ( ) ; } loadRecents ( ) ; const triggerFile = ( process . platform === 'win32' && process . argv . length > 1 && process . argv [ 1 ] !== '--updated' ) ? process . argv [ 1 ] : '' ; const hidden = ( triggerFiles . size > 0 ) || ( triggerFile !== '' ) ; welcomeWindow = newWelcomeWindow ( hidden ) ; if ( triggerFile ) { openFile ( triggerFile ) ; } else if ( triggerFiles . size > 0 ) { for ( let file of triggerFiles ) { openFile ( file ) ; } } } ) ; app . on ( 'window-all-closed' , ( ) => { if ( process . platform !== 'darwin' ) { app . quit ( ) ; } } ) ; app . on ( 'activate' , ( ) => { if ( playgroundWindows . size === 0 ) { showWelcomeWindow ( ) ; } } ) ; app . on ( 'will-finish-launching' , ( ) => { if ( process . platform === 'darwin' ) { app . on ( 'open-file' , ( event , filePath ) => { if ( app . isReady ( ) ) { openFile ( filePath ) ; } else { triggerFiles . add ( filePath ) ; } } ) ; } } ) ; app . on ( 'before-quit' , ( ) => { appQuitting = true ; } ) ; let recents = [ ] ; function addToRecentDocuments ( filePath ) { const index = recents . indexOf ( filePath ) ; if ( index < 0 ) { recents . unshift ( filePath ) ; } else if ( index > 0 ) { recents . splice ( index , 1 ) ; recents . unshift ( filePath ) ; } if ( recents . length > MAX_RECENTS ) recents . length = MAX_RECENTS ; store . set ( 'recents' , recents ) ; app . addRecentDocument ( filePath ) ; welcomeWindow . webContents . send ( 'recents' , recents ) ; } function clearRecentDocuments ( ) { recents = [ ] ; store . set ( 'recents' , [ ] ) ; app . clearRecentDocuments ( ) ; welcomeWindow . webContents . send ( 'recents' , recents ) ; } function loadRecents ( ) { recents = store . get ( 'recents' ) ; app . clearRecentDocuments ( ) ; for ( let index = recents . length - 1 ; index >= 0 ; index -- ) { app . addRecentDocument ( recents [ index ] ) ; } } autoUpdater . logger = log ; autoUpdater . allowPrerelease = false ; autoUpdater . autoDownload = true ; autoUpdater . autoInstallOnAppQuit = false ; autoUpdater . on ( 'download-progress' , ( { percent } ) => { if ( welcomeWindow ) welcomeWindow . webContents . send ( 'auto-update' , percent ) ; } ) ; autoUpdater . on ( 'update-downloaded' , ( ) => { if ( welcomeWindow ) welcomeWindow . webContents . send ( 'auto-update' , 'downloaded' ) ; } ) ; autoUpdater . on ( 'error' , ( ) => { if ( welcomeWindow ) welcomeWindow . webContents . send ( 'auto-update' , 'failed' ) ; } ) ; ipc . on ( 'quit-and-install' , ( ) => { if ( ! isDevelopment ) { appQuitting = true ; autoUpdater . quitAndInstall ( ) ; } } ) ; function loadWindowContents ( window , type ) { if ( process . env . WEBPACK_DEV_SERVER_URL ) { window . loadURL ( process . env . WEBPACK_DEV_SERVER_URL + type + '.html' ) ; } else { createProtocol ( 'app' ) ; window . loadURL ( `app://./${ type }.html` ) ; } } function setMenu ( window , type ) { if ( process . platform !== 'darwin' ) { setWindowMenu ( window , type ) ; } else { window . on ( 'focus' , ( ) => { setAppMenu ( type ) ; } ) ; } } function showOpenFileDialog ( ) { welcomeWindow . hide ( ) ; app . focus ( ) ; const filePaths = dialog . showOpenDialog ( { properties : [ 'openFile' ] , title : 'Open file' , filters : [ { name : 'Shader Playgrounds Files' , extensions : [ FILE_EXTENSION ] } ] } ) ; if ( filePaths ) { openFile ( filePaths [ 0 ] ) ; } else if ( playgroundWindows . size === 0 ) { showWelcomeWindow ( ) ; } } function showFileNotFoundDialog ( ) { enum options { ok } const optionsLabels = [ 'Ok' ] ; dialog . showMessageBox ( { title : 'File Not Found' , message : 'The selected file is unavailable. It might have been moved, renamed or removed.' , type : 'warning' , buttons : optionsLabels , defaultId : options . ok , cancelId : options . ok } ) ; } function openFile ( filePath ) { if ( fs . exists ( filePath ) === 'file' ) { const windowWorkingOnFile = openFiles . get ( filePath ) ; if ( windowWorkingOnFile ) { windowWorkingOnFile . focus ( ) ; } else { welcomeWindow . hide ( ) ; const newPlayground = newPlaygroundWindow ( filePath ) ; playgroundWindows . add ( newPlayground ) ; } } else { showFileNotFoundDialog ( ) ; if ( playgroundWindows . size === 0 ) { showWelcomeWindow ( ) ; } } } function newFile ( ) { welcomeWindow . hide ( ) ; const newPlayground = newPlaygroundWindow ( ) ; playgroundWindows . add ( newPlayground ) ; } function showWelcomeWindow ( ) { if ( ! welcomeWindow . isVisible ( ) ) { welcomeWindow . setVisibleOnAllWorkspaces ( true ) ; welcomeWindow . show ( ) ; welcomeWindow . setVisibleOnAllWorkspaces ( false ) ; } } function getFocusedPlaygroundWindow ( ) { const focusedWindow = BrowserWindow . getFocusedWindow ( ) ; if ( focusedWindow && focusedWindow !== welcomeWindow ) { return focusedWindow ; } } function adjustPlaygroundWindowPosition ( window ) { const focusedPlaygroundWindow = getFocusedPlaygroundWindow ( ) ; if ( focusedPlaygroundWindow ) { const [ focusedX , focusedY ] = focusedPlaygroundWindow . getPosition ( ) ; const offset = 22 ; window . setPosition ( focusedX + offset , focusedY + offset ) ; } } export { showOpenFileDialog , newFile , clearRecentDocuments , showWelcomeWindow } ; if ( isDevelopment ) { if ( process . platform === 'win32' ) { process . on ( 'message' , ( data ) => { if ( data === 'graceful-exit' ) { app . quit ( ) ; } } ) ; } else { process . on ( 'SIGTERM' , ( ) => { app . quit ( ) ; } ) ; } }