src/main/util.js
const { app, BrowserWindow, os, screen, shell } = require( 'electron' )
const isDev = require( 'electron-is-dev' )
const { productName } = require( '../../package.json' )
const { electronVersion } = process.versions.electron || '0.0.0'
const activeWindow = () => BrowserWindow.getFocusedWindow()
const debugInfo = () => `
${app.getName()} ${app.getVersion()}
Electron ${electronVersion}
${process.platform} ${os.release()}
Locale: ${app.getLocale()}
`.trim()
const is = {
macos: process.platform === 'darwin',
linux: process.platform === 'linux',
windows: process.platform === 'win32',
main: process.type === 'browser',
renderer: process.type === 'renderer',
development: isDev,
macAppStore: process.mas === true,
windowsStore: process.windowsStore === true,
}
const getWindowBoundsCentered = options => {
options = {
window: BrowserWindow.getFocusedWindow(),
...options,
}
const currentDisplay = screen.getDisplayNearestPoint( screen.getCursorScreenPoint() )
const [ width, height ] = options.window.getSize()
const windowSize = options.size || { width, height }
const screenSize = options.useFullBounds
? currentDisplay.bounds
: currentDisplay.workArea
const x = Math.floor( screenSize.x + ( ( screenSize.width / 2 ) - ( windowSize.width / 2 ) ) )
const y = Math.floor( ( ( screenSize.height + screenSize.y ) / 2 ) - ( windowSize.height / 2 ) )
return {
x,
y,
width: windowSize.width,
height: windowSize.height,
}
}
const centerWindow = options => {
options = {
window: activeWindow(),
animated: true,
...options,
}
const bounds = getWindowBoundsCentered( options )
options.window.setBounds( bounds, options.animated )
}
const newGithubIssueUrl = ( options = {} ) => {
let repoUrl
if ( options.repoUrl ) {
repoUrl = options.repoUrl
} else if ( options.user && options.repo ) {
repoUrl = `https://github.com/${options.user}/${options.repo}`
} else {
throw new Error( 'You need to specify either the `repoUrl` option or both the `user` and `repo` options' )
}
const url = new URL( `${repoUrl}/issues/new` )
const types = [
'body',
'title',
'labels',
'template',
'milestone',
'assignee',
'projects',
]
for ( const type of types ) {
let value = options[type]
if ( value === undefined ) {
continue
}
if ( type === 'labels' || type === 'projects' ) {
if ( !Array.isArray( value ) ) {
throw new TypeError( `The \`${type}\` option should be an array` )
}
value = value.join( ',' )
}
url.searchParams.set( type, value )
}
return url.toString()
}
const openNewGitHubIssue = options => {
const url = newGithubIssueUrl( options )
shell.openExternal( url )
}
const openUrlMenuItem = ( options = {} ) => {
if ( !options.url ) {
throw new Error( 'The `url` option is required' )
}
const { url } = options
delete options.url
const click = ( ...args ) => {
if ( options.click ) {
options.click( ...args )
}
shell.openExternal( url )
}
return {
...options,
click,
}
}
const aboutMenuItem = ( options = {} ) => {
options = {
title: 'About',
...options,
}
// TODO: When https://github.com/electron/electron/issues/15589 is fixed,
// handle the macOS case here, so the user doesn't need a conditional
// when used in a cross-platform app
return {
label: `${options.title}`,
click() {
showAboutWindow( options )
},
}
}
const showAboutWindow = ( options = {} ) => {
// TODO: When https://github.com/electron/electron/issues/18918 is fixed,
// these defaults should not need to be set for Linux.
// TODO: The defaults are standardized here, instead of being set in
// Electron when https://github.com/electron/electron/issues/23851 is fixed.
const appName = app.getName()
const appVersion = app.getVersion()
const aboutPanelOptions = {
applicationName: appName,
applicationVersion: appVersion,
}
if ( options.icon ) {
aboutPanelOptions.iconPath = options.icon
}
if ( options.copyright ) {
aboutPanelOptions.copyright = options.copyright
}
if ( options.text ) {
aboutPanelOptions.copyright = ( options.copyright || '' ) + '\n\n' + options.text
}
if ( options.website ) {
aboutPanelOptions.website = options.website
}
app.setAboutPanelOptions( aboutPanelOptions )
app.showAboutPanel()
}
const appMenu = ( menuItems = [] ) => ( {
label: productName,
submenu: [
{
role: 'about',
},
{
type: 'separator',
},
...menuItems,
{
type: 'separator',
},
{
role: 'services',
},
{
type: 'separator',
},
{
role: 'hide',
},
{
role: 'hideothers',
},
{
role: 'unhide',
},
{
type: 'separator',
},
{
role: 'quit',
},
].filter( Boolean ),
} )
module.exports = {
is,
activeWindow,
centerWindow,
debugInfo,
appMenu,
aboutMenuItem,
showAboutWindow,
openUrlMenuItem,
openNewGitHubIssue,
getWindowBoundsCentered,
}