import { app , BrowserWindow , ipcMain , screen , shell , Tray , Menu , nativeImage } from 'electron' ; import * as path from 'path' ; import * as url from 'url' ; import settings from 'electron-settings' ; import { MACOS , WINDOWS , LINUX , CONTAINER , SETTINGS_CONTAINER , DEFAULT_SETTINGS } from '../constants' ; import '../../build/Release/black-magic.node' ; import '../../icon.png' ; import '../../icon.ico' ; import { version } from '../../version.generated' ; app . commandLine . appendSwitch ( 'disable-gpu-vsync' ) ; app . commandLine . appendArgument ( 'disable-gpu-vsync' ) ; app . commandLine . appendSwitch ( 'enable-transparent-visuals' ) ; const HARDWARE_ACCELERATION = Boolean ( settings . getSync ( 'hardware_acceleration' ) ) ; const windowConfig = { } ; if ( ! HARDWARE_ACCELERATION || LINUX ) { app . disableHardwareAcceleration ( ) ; } let mainWindow = null ; let mousePoller ; let initialBounds ; let isSingleInstance = app . requestSingleInstanceLock ( ) ; if ( ! isSingleInstance ) { app . quit ( ) ; } function createWindow ( ) { mainWindow = new BrowserWindow ( { x : windowConfig . x , y : windowConfig . y , height : CONTAINER . VERTICAL , width : CONTAINER . HORIZONTAL , frame : false , resizable : false , maximizable : false , minimizable : true , transparent : true , hasShadow : false , skipTaskbar : ! windowConfig . show_in_taskbar , webPreferences : { allowRunningInsecureContent : false , nodeIntegration : true , nativeWindowOpen : true , enableRemoteModule : true , } , backgroundColor : '#00000000' , } ) ; mainWindow . on ( 'focus' , ( ) => { mainWindow . setSkipTaskbar ( ! windowConfig . show_in_taskbar ) ; } ) ; mainWindow . setAlwaysOnTop ( windowConfig . always_on_top , 'floating' , 1 ) ; mainWindow . setFocusable ( windowConfig . show_in_taskbar ) ; mainWindow . setVisibleOnAllWorkspaces ( true ) ; mainWindow . loadURL ( url . format ( { pathname : path . join ( __dirname , './index.html' ) , protocol : 'file:' , slashes : true , } ) ) ; mousePoller = setInterval ( ( ) => { try { let p = screen . getCursorScreenPoint ( ) ; let b = mainWindow . getBounds ( ) ; let bb = { ix : b . x + ( CONTAINER . HORIZONTAL - windowConfig . side ) / 2 , iy : b . y + ( CONTAINER . VERTICAL - windowConfig . side ) / 2 , ax : b . x + ( windowConfig . side + ( CONTAINER . HORIZONTAL - windowConfig . side ) / 2 ) , ay : b . y + ( windowConfig . side + ( CONTAINER . VERTICAL - windowConfig . side ) / 2 ) , } ; if ( bb . ix <= p . x && p . x <= bb . ax && bb . iy <= p . y && p . y <= bb . ay ) { mainWindow . setIgnoreMouseEvents ( false ) ; } else { mainWindow . setIgnoreMouseEvents ( true ) ; } } catch ( e ) { } } , 10 ) ; if ( Boolean ( settings . getSync ( 'debug' ) ) === true ) { mainWindow . webContents . openDevTools ( { mode : 'detach' } ) ; } ipcMain . on ( 'windowMoving' , ( e , { mouseX , mouseY } ) => { const { x , y } = screen . getCursorScreenPoint ( ) ; let bounds = { x : x - mouseX , y : y - mouseY , } ; if ( ! initialBounds ) { initialBounds = mainWindow . getBounds ( ) ; } else { bounds . width = initialBounds . width ; bounds . height = initialBounds . height ; } mainWindow . setBounds ( bounds ) ; if ( WINDOWS ) { if ( HARDWARE_ACCELERATION ) { mainWindow . setOpacity ( 1 ) ; } } } ) ; ipcMain . on ( 'windowMoved' , ( e , { mouseX , mouseY } ) => { const { x , y } = screen . getCursorScreenPoint ( ) ; windowConfig . x = x - mouseX ; windowConfig . y = y - mouseY ; } ) ; ipcMain . on ( 'windowResizing' , ( e , length ) => { windowConfig . side = length ; } ) ; mainWindow . webContents . on ( 'new-window' , function ( event , url , frameName , disposition , options ) { event . preventDefault ( ) ; switch ( frameName ) { case 'settings' : { createSettingsWindow ( event , options ) ; break ; } case 'about' : { createAboutWindow ( event , options ) ; break ; } default : { shell . openExternal ( url ) ; } } } ) ; } function createSettingsWindow ( event , options ) { Object . assign ( options , { x : screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . x - SETTINGS_CONTAINER . HORIZONTAL / 2 + screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . width / 2 , y : screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . y - SETTINGS_CONTAINER . VERTICAL / 2 + screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . height / 2 , height : SETTINGS_CONTAINER . VERTICAL , width : SETTINGS_CONTAINER . HORIZONTAL , modal : false , parent : mainWindow , frame : false , resizable : true , maximizable : false , focusable : true , title : 'Lofi Settings' , } ) ; event . newGuest = new BrowserWindow ( options ) ; event . newGuest . setMenu ( null ) ; event . newGuest . setResizable ( true ) ; if ( Boolean ( settings . getSync ( 'debug' ) ) === true ) { event . newGuest . webContents . openDevTools ( { mode : 'detach' } ) ; } } function createAboutWindow ( event , options ) { Object . assign ( options , { x : screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . x - 400 / 2 + screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . width / 2 , y : screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . y - 400 / 2 + screen . getDisplayMatching ( mainWindow . getBounds ( ) ) . bounds . height / 2 , height : 400 , width : 400 , modal : false , parent : mainWindow , frame : false , resizable : false , maximizable : false , focusable : true , title : 'About Lofi' , } ) ; event . newGuest = new BrowserWindow ( options ) ; event . newGuest . setMenu ( null ) ; event . newGuest . setResizable ( true ) ; if ( Boolean ( settings . getSync ( 'debug' ) ) === true ) { event . newGuest . webContents . openDevTools ( { mode : 'detach' } ) ; } } let tray = null ; app . on ( 'ready' , ( ) => { settings . defaults ( DEFAULT_SETTINGS ) ; if ( ! settings . hasSync ( 'version' ) || String ( settings . getSync ( 'version' ) ) !== version ) { settings . resetToDefaultsSync ( ) ; settings . setSync ( 'lofi.window.x' , 0 - CONTAINER . HORIZONTAL / 2 + screen . getPrimaryDisplay ( ) . size . width / 2 ) ; settings . setSync ( 'lofi.window.y' , 0 - CONTAINER . VERTICAL / 2 + screen . getPrimaryDisplay ( ) . size . height / 2 ) ; } Object . assign ( windowConfig , { x : Number ( settings . getSync ( 'lofi.window.x' ) ) , y : Number ( settings . getSync ( 'lofi.window.y' ) ) , always_on_top : Boolean ( settings . getSync ( 'lofi.window.always_on_top' ) ) , show_in_taskbar : Boolean ( settings . getSync ( 'lofi.window.show_in_taskbar' ) ) , side : Number ( settings . getSync ( 'lofi.window.side' ) ) , } ) ; if ( LINUX ) { setTimeout ( createWindow , 1000 ) ; } else { createWindow ( ) ; } tray = new Tray ( nativeImage . createFromPath ( __dirname + '/icon.png' ) . resize ( { height : 16 } ) ) ; const contextMenu = Menu . buildFromTemplate ( [ { label : `lofi v${ version }` , enabled : false , icon : nativeImage . createFromPath ( __dirname + '/icon.png' ) . resize ( { height : 16 } ) , } , { type : 'separator' } , { label : 'Settings' , type : 'normal' , click : ( ) => { mainWindow . webContents . send ( 'show-settings' ) ; } , } , { label : 'About' , type : 'normal' , click : ( ) => { mainWindow . webContents . send ( 'show-about' ) ; } , } , { label : 'Exit' , type : 'normal' , click : ( ) => { app . quit ( ) ; } , } , ] ) ; tray . setContextMenu ( contextMenu ) ; tray . setToolTip ( `lofi v${ version }` ) ; } ) ; app . on ( 'window-all-closed' , ( ) => { clearTimeout ( mousePoller ) ; app . quit ( ) ; } ) ; app . on ( 'will-quit' , ( ) => { settings . setSync ( 'lofi.window.x' , windowConfig . x ) ; settings . setSync ( 'lofi.window.y' , windowConfig . y ) ; settings . setSync ( 'lofi.window.side' , windowConfig . side ) ; } ) ; app . on ( 'activate' , ( ) => { if ( MACOS && mainWindow === null ) { createWindow ( ) ; } } ) ;