mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-17 23:20:13 +01:00
This commit is contained in:
parent
a99cb898c4
commit
910a600d5d
12 changed files with 400 additions and 388 deletions
|
|
@ -358,8 +358,10 @@
|
||||||
if (!fs.existsSync(initPath)) {
|
if (!fs.existsSync(initPath)) {
|
||||||
fs.mkdirSync(initPath, {mode: 0o755, recursive: true})
|
fs.mkdirSync(initPath, {mode: 0o755, recursive: true})
|
||||||
}
|
}
|
||||||
const lang = document.querySelector('.lang').value
|
ipcRenderer.send('siyuan-first-init', {
|
||||||
ipcRenderer.send('siyuan-first-init', `${initPath}-${lang}`)
|
workspace: initPath,
|
||||||
|
lang: document.querySelector('.lang').value
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ const {
|
||||||
} = require('electron')
|
} = require('electron')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const net = require("net");
|
const net = require('net')
|
||||||
const fetch = require('electron-fetch').default
|
const fetch = require('electron-fetch').default
|
||||||
process.noAsar = true
|
process.noAsar = true
|
||||||
const appDir = path.dirname(app.getAppPath())
|
const appDir = path.dirname(app.getAppPath())
|
||||||
|
|
@ -35,14 +35,13 @@ const isDevEnv = process.env.NODE_ENV === 'development'
|
||||||
const appVer = app.getVersion()
|
const appVer = app.getVersion()
|
||||||
const confDir = path.join(app.getPath('home'), '.config', 'siyuan')
|
const confDir = path.join(app.getPath('home'), '.config', 'siyuan')
|
||||||
const windowStatePath = path.join(confDir, 'windowState.json')
|
const windowStatePath = path.join(confDir, 'windowState.json')
|
||||||
let tray // 托盘必须使用全局变量,以防止被垃圾回收 https://www.electronjs.org/docs/faq#my-apps-windowtray-disappeared-after-a-few-minutes
|
|
||||||
let mainWindow // 从托盘处激活报错 https://github.com/siyuan-note/siyuan/issues/769
|
|
||||||
let firstOpenWindow, bootWindow
|
let firstOpenWindow, bootWindow
|
||||||
let closeButtonBehavior = 0
|
|
||||||
let siyuanOpenURL
|
let siyuanOpenURL
|
||||||
let firstOpen = false
|
let firstOpen = false
|
||||||
let resetWindowStateOnRestart = false
|
let resetWindowStateOnRestart = false
|
||||||
const localhost = "127.0.0.1"
|
let workspaces = []
|
||||||
|
const localhost = '127.0.0.1'
|
||||||
|
let kernelPort = 6806
|
||||||
require('@electron/remote/main').initialize()
|
require('@electron/remote/main').initialize()
|
||||||
|
|
||||||
if (!app.requestSingleInstanceLock()) {
|
if (!app.requestSingleInstanceLock()) {
|
||||||
|
|
@ -50,6 +49,28 @@ if (!app.requestSingleInstanceLock()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
firstOpen = !fs.existsSync(path.join(confDir, 'workspace.json'))
|
||||||
|
if (!fs.existsSync(confDir)) {
|
||||||
|
fs.mkdirSync(confDir, {mode: 0o755, recursive: true})
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
require('electron').
|
||||||
|
dialog.
|
||||||
|
showErrorBox('创建配置目录失败 Failed to create config directory',
|
||||||
|
'思源需要在用户家目录下创建配置文件夹(~/.config/siyuan),请确保该路径具有写入权限。\n\nSiYuan needs to create a configuration folder (~/.config/siyuan) in the user\'s home directory. Please make sure that the path has write permissions.')
|
||||||
|
app.exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getServer = () => {
|
||||||
|
return 'http://' + localhost + ':' + kernelPort
|
||||||
|
}
|
||||||
|
|
||||||
|
const sleep = (ms) => {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
const showErrorWindow = (title, content) => {
|
const showErrorWindow = (title, content) => {
|
||||||
let errorHTMLPath = path.join(appDir, 'app', 'electron', 'error.html')
|
let errorHTMLPath = path.join(appDir, 'app', 'electron', 'error.html')
|
||||||
if (isDevEnv) {
|
if (isDevEnv) {
|
||||||
|
|
@ -81,18 +102,6 @@ const showErrorWindow = (title, content) => {
|
||||||
errWindow.show()
|
errWindow.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
firstOpen = !fs.existsSync(path.join(confDir, 'workspace.json'))
|
|
||||||
if (!fs.existsSync(confDir)) {
|
|
||||||
fs.mkdirSync(confDir, {mode: 0o755, recursive: true})
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
require('electron').dialog.showErrorBox('创建配置目录失败 Failed to create config directory',
|
|
||||||
'思源需要在用户家目录下创建配置文件夹(~/.config/siyuan),请确保该路径具有写入权限。\n\nSiYuan needs to create a configuration folder (~/.config/siyuan) in the user\'s home directory. Please make sure that the path has write permissions.')
|
|
||||||
app.exit()
|
|
||||||
}
|
|
||||||
|
|
||||||
const writeLog = (out) => {
|
const writeLog = (out) => {
|
||||||
console.log(out)
|
console.log(out)
|
||||||
const logFile = path.join(confDir, 'app.log')
|
const logFile = path.join(confDir, 'app.log')
|
||||||
|
|
@ -173,7 +182,7 @@ const boot = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建主窗体
|
// 创建主窗体
|
||||||
mainWindow = new BrowserWindow({
|
const currentWindow = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
backgroundColor: '#FFF', // 桌面端主窗体背景色设置为 `#FFF` Fix https://github.com/siyuan-note/siyuan/issues/4544
|
backgroundColor: '#FFF', // 桌面端主窗体背景色设置为 `#FFF` Fix https://github.com/siyuan-note/siyuan/issues/4544
|
||||||
width: windowState.width,
|
width: windowState.width,
|
||||||
|
|
@ -196,15 +205,14 @@ const boot = () => {
|
||||||
titleBarStyle: 'hidden',
|
titleBarStyle: 'hidden',
|
||||||
icon: path.join(appDir, 'stage', 'icon-large.png'),
|
icon: path.join(appDir, 'stage', 'icon-large.png'),
|
||||||
})
|
})
|
||||||
|
require('@electron/remote/main').enable(currentWindow.webContents)
|
||||||
require('@electron/remote/main').enable(mainWindow.webContents)
|
currentWindow.webContents.userAgent = 'SiYuan/' + appVer +
|
||||||
mainWindow.webContents.userAgent = 'SiYuan/' + appVer +
|
|
||||||
' https://b3log.org/siyuan Electron'
|
' https://b3log.org/siyuan Electron'
|
||||||
|
|
||||||
mainWindow.webContents.session.setSpellCheckerLanguages(['en-US'])
|
currentWindow.webContents.session.setSpellCheckerLanguages(['en-US'])
|
||||||
|
|
||||||
// 发起互联网服务请求时绕过安全策略 https://github.com/siyuan-note/siyuan/issues/5516
|
// 发起互联网服务请求时绕过安全策略 https://github.com/siyuan-note/siyuan/issues/5516
|
||||||
mainWindow.webContents.session.webRequest.onBeforeSendHeaders(
|
currentWindow.webContents.session.webRequest.onBeforeSendHeaders(
|
||||||
(details, cb) => {
|
(details, cb) => {
|
||||||
if (-1 < details.url.indexOf('bili')) {
|
if (-1 < details.url.indexOf('bili')) {
|
||||||
// B 站不移除 Referer https://github.com/siyuan-note/siyuan/issues/94
|
// B 站不移除 Referer https://github.com/siyuan-note/siyuan/issues/94
|
||||||
|
|
@ -219,50 +227,51 @@ const boot = () => {
|
||||||
}
|
}
|
||||||
cb({requestHeaders: details.requestHeaders})
|
cb({requestHeaders: details.requestHeaders})
|
||||||
})
|
})
|
||||||
mainWindow.webContents.session.webRequest.onHeadersReceived((details, cb) => {
|
currentWindow.webContents.session.webRequest.onHeadersReceived(
|
||||||
for (let key in details.responseHeaders) {
|
(details, cb) => {
|
||||||
if ('x-frame-options' === key.toLowerCase()) {
|
for (let key in details.responseHeaders) {
|
||||||
delete details.responseHeaders[key]
|
if ('x-frame-options' === key.toLowerCase()) {
|
||||||
} else if ('content-security-policy' === key.toLowerCase()) {
|
delete details.responseHeaders[key]
|
||||||
delete details.responseHeaders[key]
|
} else if ('content-security-policy' === key.toLowerCase()) {
|
||||||
} else if ('access-control-allow-origin' === key.toLowerCase()) {
|
delete details.responseHeaders[key]
|
||||||
delete details.responseHeaders[key]
|
} else if ('access-control-allow-origin' === key.toLowerCase()) {
|
||||||
|
delete details.responseHeaders[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
cb({responseHeaders: details.responseHeaders})
|
||||||
cb({responseHeaders: details.responseHeaders})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
mainWindow.webContents.on('did-finish-load', () => {
|
currentWindow.webContents.on('did-finish-load', () => {
|
||||||
if ('win32' === process.platform || 'linux' === process.platform) {
|
if ('win32' === process.platform || 'linux' === process.platform) {
|
||||||
siyuanOpenURL = process.argv.find((arg) => arg.startsWith('siyuan://'))
|
siyuanOpenURL = process.argv.find((arg) => arg.startsWith('siyuan://'))
|
||||||
}
|
}
|
||||||
if (siyuanOpenURL) {
|
if (siyuanOpenURL) {
|
||||||
if (mainWindow.isMinimized()) {
|
if (currentWindow.isMinimized()) {
|
||||||
mainWindow.restore()
|
currentWindow.restore()
|
||||||
}
|
}
|
||||||
if (!mainWindow.isVisible()) {
|
if (!currentWindow.isVisible()) {
|
||||||
mainWindow.show()
|
currentWindow.show()
|
||||||
}
|
}
|
||||||
mainWindow.focus()
|
currentWindow.focus()
|
||||||
setTimeout(() => { // 等待界面js执行完毕
|
setTimeout(() => { // 等待界面js执行完毕
|
||||||
writeLog(siyuanOpenURL)
|
writeLog(siyuanOpenURL)
|
||||||
mainWindow.webContents.send('siyuan-openurl', siyuanOpenURL)
|
currentWindow.webContents.send('siyuan-openurl', siyuanOpenURL)
|
||||||
siyuanOpenURL = null
|
siyuanOpenURL = null
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (windowState.isDevToolsOpened) {
|
if (windowState.isDevToolsOpened) {
|
||||||
mainWindow.webContents.openDevTools({mode: 'bottom'})
|
currentWindow.webContents.openDevTools({mode: 'bottom'})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主界面事件监听
|
// 主界面事件监听
|
||||||
mainWindow.once('ready-to-show', () => {
|
currentWindow.once('ready-to-show', () => {
|
||||||
mainWindow.show()
|
currentWindow.show()
|
||||||
if (windowState.isMaximized) {
|
if (windowState.isMaximized) {
|
||||||
mainWindow.maximize()
|
currentWindow.maximize()
|
||||||
} else {
|
} else {
|
||||||
mainWindow.unmaximize()
|
currentWindow.unmaximize()
|
||||||
}
|
}
|
||||||
if (bootWindow && !bootWindow.isDestroyed()) {
|
if (bootWindow && !bootWindow.isDestroyed()) {
|
||||||
bootWindow.destroy()
|
bootWindow.destroy()
|
||||||
|
|
@ -270,7 +279,7 @@ const boot = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// 加载主界面
|
// 加载主界面
|
||||||
mainWindow.loadURL(getServer() + '/stage/build/app/index.html?v=' +
|
currentWindow.loadURL(getServer() + '/stage/build/app/index.html?v=' +
|
||||||
new Date().getTime())
|
new Date().getTime())
|
||||||
|
|
||||||
// 菜单
|
// 菜单
|
||||||
|
|
@ -333,7 +342,7 @@ const boot = () => {
|
||||||
const menu = Menu.buildFromTemplate(template)
|
const menu = Menu.buildFromTemplate(template)
|
||||||
Menu.setApplicationMenu(menu)
|
Menu.setApplicationMenu(menu)
|
||||||
// 当前页面链接使用浏览器打开
|
// 当前页面链接使用浏览器打开
|
||||||
mainWindow.webContents.on('will-navigate', (event, url) => {
|
currentWindow.webContents.on('will-navigate', (event, url) => {
|
||||||
if (url.startsWith(getServer())) {
|
if (url.startsWith(getServer())) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -342,218 +351,48 @@ const boot = () => {
|
||||||
shell.openExternal(url)
|
shell.openExternal(url)
|
||||||
})
|
})
|
||||||
|
|
||||||
mainWindow.on('close', (event) => {
|
currentWindow.on('close', (event) => {
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (currentWindow && !currentWindow.isDestroyed()) {
|
||||||
mainWindow.webContents.send('siyuan-save-close', false)
|
currentWindow.webContents.send('siyuan-save-close', false)
|
||||||
}
|
}
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
})
|
})
|
||||||
// 监听主题切换
|
workspaces.push({
|
||||||
ipcMain.on('siyuan-config-theme', (event, theme) => {
|
browserWindow: currentWindow,
|
||||||
nativeTheme.themeSource = theme
|
id: currentWindow.id,
|
||||||
})
|
})
|
||||||
ipcMain.on('siyuan-config-close', (event, close) => {
|
|
||||||
closeButtonBehavior = close
|
|
||||||
})
|
|
||||||
ipcMain.on('siyuan-config-tray', () => {
|
|
||||||
mainWindow.hide()
|
|
||||||
})
|
|
||||||
ipcMain.on('siyuan-config-closetray', () => {
|
|
||||||
if ('win32' === process.platform) {
|
|
||||||
tray.destroy()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
ipcMain.on('siyuan-export-pdf', (event, data) => {
|
|
||||||
mainWindow.webContents.send('siyuan-export-pdf', data)
|
|
||||||
})
|
|
||||||
ipcMain.on('siyuan-export-close', (event, data) => {
|
|
||||||
mainWindow.webContents.send('siyuan-export-close', data)
|
|
||||||
})
|
|
||||||
ipcMain.on('siyuan-quit', () => {
|
|
||||||
try {
|
|
||||||
if (resetWindowStateOnRestart) {
|
|
||||||
fs.writeFileSync(windowStatePath, '{}')
|
|
||||||
} else {
|
|
||||||
const bounds = mainWindow.getBounds()
|
|
||||||
fs.writeFileSync(windowStatePath, JSON.stringify({
|
|
||||||
isMaximized: mainWindow.isMaximized(),
|
|
||||||
fullscreen: mainWindow.isFullScreen(),
|
|
||||||
isDevToolsOpened: mainWindow.webContents.isDevToolsOpened(),
|
|
||||||
x: bounds.x,
|
|
||||||
y: bounds.y,
|
|
||||||
width: bounds.width,
|
|
||||||
height: bounds.height,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
writeLog(e)
|
|
||||||
}
|
|
||||||
app.exit()
|
|
||||||
globalShortcut.unregisterAll()
|
|
||||||
writeLog('exited ui')
|
|
||||||
})
|
|
||||||
|
|
||||||
let trayMenu = {
|
|
||||||
"showWindow": "Show Window",
|
|
||||||
"hideWindow": "Hide Window",
|
|
||||||
"setWindowTop": "Set Window top",
|
|
||||||
"cancelWindowTop": "Cancel Window top",
|
|
||||||
"officialWebsite": "Visit official website",
|
|
||||||
"openSource": "Visit Project on Github",
|
|
||||||
"resetWindow": "Reset Window on restart",
|
|
||||||
"quit": "Quit application"
|
|
||||||
}
|
|
||||||
ipcMain.on('siyuan-init', async (event, languages) => {
|
|
||||||
trayMenu = languages['_trayMenu'];
|
|
||||||
resetTrayMenu()
|
|
||||||
await fetch(getServer() + '/api/system/uiproc?pid=' + process.pid,
|
|
||||||
{method: 'POST'})
|
|
||||||
})
|
|
||||||
|
|
||||||
const resetTrayMenu = () => {
|
|
||||||
if ('win32' !== process.platform && 'linux' !== process.platform) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const trayMenuTemplate = buildTrayMenuTemplate()
|
|
||||||
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate)
|
|
||||||
tray.setContextMenu(contextMenu)
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildShowWndMenu = () => {
|
|
||||||
const ret = {
|
|
||||||
label: trayMenu.hideWindow,
|
|
||||||
click: () => {
|
|
||||||
showHideWnd()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainWindow.isVisible()) {
|
|
||||||
ret.label = trayMenu.hideWindow
|
|
||||||
} else {
|
|
||||||
ret.label = trayMenu.showWindow
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
const showHideWnd = () => {
|
|
||||||
if (!mainWindow.isVisible()) {
|
|
||||||
if (mainWindow.isMinimized()) {
|
|
||||||
mainWindow.restore()
|
|
||||||
}
|
|
||||||
mainWindow.show()
|
|
||||||
} else {
|
|
||||||
mainWindow.hide()
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTrayMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildSetWndTopMenu = () => {
|
|
||||||
const ret = {
|
|
||||||
label: trayMenu.setWindowTop,
|
|
||||||
click: () => {
|
|
||||||
setCancelWndTop()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if (mainWindow.isAlwaysOnTop()) {
|
|
||||||
ret.label = trayMenu.cancelWindowTop
|
|
||||||
} else {
|
|
||||||
ret.label = trayMenu.setWindowTop
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
const setCancelWndTop = () => {
|
|
||||||
if (!mainWindow.isAlwaysOnTop()) {
|
|
||||||
mainWindow.setAlwaysOnTop(true)
|
|
||||||
} else {
|
|
||||||
mainWindow.setAlwaysOnTop(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTrayMenu()
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildTrayMenuTemplate = () => {
|
|
||||||
let ret = [
|
|
||||||
buildShowWndMenu(),
|
|
||||||
{
|
|
||||||
label: trayMenu.officialWebsite,
|
|
||||||
click: () => {
|
|
||||||
shell.openExternal('https://b3log.org/siyuan/')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: trayMenu.openSource,
|
|
||||||
click: () => {
|
|
||||||
shell.openExternal('https://github.com/siyuan-note/siyuan')
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: trayMenu.resetWindow,
|
|
||||||
type: 'checkbox',
|
|
||||||
click: v => {
|
|
||||||
resetWindowStateOnRestart = v.checked
|
|
||||||
mainWindow.webContents.send('siyuan-save-close', true)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: trayMenu.quit,
|
|
||||||
click: () => {
|
|
||||||
mainWindow.webContents.send('siyuan-save-close', true)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
if ('win32' === process.platform) {
|
|
||||||
// Windows 端支持窗口置顶 https://github.com/siyuan-note/siyuan/issues/6860
|
|
||||||
ret.splice(1, 0, buildSetWndTopMenu())
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcMain.on('siyuan-hotkey', (event, hotkey) => {
|
|
||||||
globalShortcut.unregisterAll()
|
|
||||||
if (!hotkey) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
globalShortcut.register(hotkey, () => {
|
|
||||||
if (mainWindow.isMinimized()) {
|
|
||||||
mainWindow.restore()
|
|
||||||
if (!mainWindow.isVisible()) {
|
|
||||||
mainWindow.show()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (mainWindow.isVisible()) {
|
|
||||||
if (!mainWindow.isFocused()) {
|
|
||||||
mainWindow.show()
|
|
||||||
} else {
|
|
||||||
mainWindow.hide()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mainWindow.show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resetTrayMenu()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if ('win32' === process.platform || 'linux' === process.platform) {
|
|
||||||
// 系统托盘
|
|
||||||
|
|
||||||
tray = new Tray(path.join(appDir, 'stage', 'icon-large.png'))
|
|
||||||
tray.setToolTip('SiYuan v' + appVer)
|
|
||||||
|
|
||||||
const trayMenuTemplate = buildTrayMenuTemplate()
|
|
||||||
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate)
|
|
||||||
tray.setContextMenu(contextMenu)
|
|
||||||
tray.on('click', () => {
|
|
||||||
showHideWnd()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initKernel = (initData) => {
|
const initKernel = (workspace, lang) => {
|
||||||
|
const getKernelPort = async () => {
|
||||||
|
// TODO if (isDevEnv) {
|
||||||
|
// writeLog("got kernel port [" + kernelPort + "]")
|
||||||
|
// return kernelPort
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 改进桌面端拉起内核 https://github.com/siyuan-note/siyuan/issues/6894
|
||||||
|
const getAvailablePort = (port = kernelPort) => {
|
||||||
|
// https://gist.github.com/mikeal/1840641
|
||||||
|
let tryGetPortCount = 0
|
||||||
|
const server = net.createServer()
|
||||||
|
return new Promise((resolve, reject) => server.on('error', error => {
|
||||||
|
writeLog(error)
|
||||||
|
if (2048 < ++tryGetPortCount) {
|
||||||
|
writeLog('failed to get available port [tryCount=' + tryGetPortCount +
|
||||||
|
', port=' + port + ']')
|
||||||
|
reject(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
server.listen(++port)
|
||||||
|
}).on('listening', () => {
|
||||||
|
writeLog('found an available port [' + port + ']')
|
||||||
|
server.close(() => resolve(port))
|
||||||
|
}).listen(port, '127.0.0.1'))
|
||||||
|
}
|
||||||
|
kernelPort = await getAvailablePort()
|
||||||
|
writeLog('got kernel available port [' + kernelPort + ']')
|
||||||
|
return kernelPort
|
||||||
|
}
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
bootWindow = new BrowserWindow({
|
bootWindow = new BrowserWindow({
|
||||||
width: screen.getPrimaryDisplay().size.width / 2,
|
width: screen.getPrimaryDisplay().size.width / 2,
|
||||||
|
|
@ -566,7 +405,9 @@ const initKernel = (initData) => {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const kernelName = 'win32' === process.platform ? 'SiYuan-Kernel.exe' : 'SiYuan-Kernel'
|
const kernelName = 'win32' === process.platform
|
||||||
|
? 'SiYuan-Kernel.exe'
|
||||||
|
: 'SiYuan-Kernel'
|
||||||
const kernelPath = path.join(appDir, 'kernel', kernelName)
|
const kernelPath = path.join(appDir, 'kernel', kernelName)
|
||||||
if (!fs.existsSync(kernelPath)) {
|
if (!fs.existsSync(kernelPath)) {
|
||||||
showErrorWindow('⚠️ 内核文件丢失 Kernel is missing',
|
showErrorWindow('⚠️ 内核文件丢失 Kernel is missing',
|
||||||
|
|
@ -578,18 +419,19 @@ const initKernel = (initData) => {
|
||||||
|
|
||||||
const availablePort = await getKernelPort()
|
const availablePort = await getKernelPort()
|
||||||
const cmds = ['--port', availablePort, '--wd', appDir]
|
const cmds = ['--port', availablePort, '--wd', appDir]
|
||||||
if (isDevEnv) {
|
// TODO if (isDevEnv) {
|
||||||
cmds.push('--mode', 'dev')
|
// cmds.push('--mode', 'dev')
|
||||||
|
// }
|
||||||
|
if (workspace) {
|
||||||
|
cmds.push('--workspace', workspace)
|
||||||
|
cmds.push('--lang', lang)
|
||||||
}
|
}
|
||||||
if (initData) {
|
let cmd = `ui version [${appVer}], booting kernel [${kernelPath} ${cmds.join(
|
||||||
const initDatas = initData.split('-')
|
' ')}]`
|
||||||
cmds.push('--workspace', initDatas[0])
|
|
||||||
cmds.push('--lang', initDatas[1])
|
|
||||||
}
|
|
||||||
let cmd = `ui version [${appVer}], booting kernel [${kernelPath} ${cmds.join(' ')}]`
|
|
||||||
writeLog(cmd)
|
writeLog(cmd)
|
||||||
let kernelProcessPid = ""
|
let kernelProcessPid = ''
|
||||||
if (!isDevEnv) {
|
// TODO
|
||||||
|
if (isDevEnv) {
|
||||||
const cp = require('child_process')
|
const cp = require('child_process')
|
||||||
const kernelProcess = cp.spawn(kernelPath,
|
const kernelProcess = cp.spawn(kernelPath,
|
||||||
cmds, {
|
cmds, {
|
||||||
|
|
@ -609,8 +451,12 @@ const initKernel = (initData) => {
|
||||||
`<div>数据库文件正在被其他进程占用,请检查是否同时存在多个内核进程(SiYuan Kernel)服务相同的工作空间。</div><div>The database file is being occupied by other processes, please check whether there are multiple kernel processes (SiYuan Kernel) serving the same workspace at the same time.</div>`)
|
`<div>数据库文件正在被其他进程占用,请检查是否同时存在多个内核进程(SiYuan Kernel)服务相同的工作空间。</div><div>The database file is being occupied by other processes, please check whether there are multiple kernel processes (SiYuan Kernel) serving the same workspace at the same time.</div>`)
|
||||||
break
|
break
|
||||||
case 21:
|
case 21:
|
||||||
showErrorWindow('⚠️ 监听端口 ' + kernelPort + ' 失败 Failed to listen to port ' + kernelPort,
|
showErrorWindow('⚠️ 监听端口 ' + kernelPort +
|
||||||
'<div>监听 ' + kernelPort + ' 端口失败,请确保程序拥有网络权限并不受防火墙和杀毒软件阻止。</div><div>Failed to listen to port ' + kernelPort + ', please make sure the program has network permissions and is not blocked by firewalls and antivirus software.</div>')
|
' 失败 Failed to listen to port ' + kernelPort,
|
||||||
|
'<div>监听 ' + kernelPort +
|
||||||
|
' 端口失败,请确保程序拥有网络权限并不受防火墙和杀毒软件阻止。</div><div>Failed to listen to port ' +
|
||||||
|
kernelPort +
|
||||||
|
', please make sure the program has network permissions and is not blocked by firewalls and antivirus software.</div>')
|
||||||
break
|
break
|
||||||
case 22:
|
case 22:
|
||||||
showErrorWindow(
|
showErrorWindow(
|
||||||
|
|
@ -659,7 +505,8 @@ const initKernel = (initData) => {
|
||||||
if (14 < count) {
|
if (14 < count) {
|
||||||
writeLog('get kernel ver failed')
|
writeLog('get kernel ver failed')
|
||||||
|
|
||||||
showErrorWindow('⚠️ 获取内核服务端口失败 Failed to get kernel serve port',
|
showErrorWindow(
|
||||||
|
'⚠️ 获取内核服务端口失败 Failed to get kernel serve port',
|
||||||
'<div>获取内核服务端口失败,请确保程序拥有网络权限并不受防火墙和杀毒软件阻止。</div><div>Failed to get kernel serve port, please make sure the program has network permissions and is not blocked by firewalls and antivirus software.</div>')
|
'<div>获取内核服务端口失败,请确保程序拥有网络权限并不受防火墙和杀毒软件阻止。</div><div>Failed to get kernel serve port, please make sure the program has network permissions and is not blocked by firewalls and antivirus software.</div>')
|
||||||
bootWindow.destroy()
|
bootWindow.destroy()
|
||||||
resolve(false)
|
resolve(false)
|
||||||
|
|
@ -680,7 +527,8 @@ const initKernel = (initData) => {
|
||||||
let progressing = false
|
let progressing = false
|
||||||
while (!progressing) {
|
while (!progressing) {
|
||||||
try {
|
try {
|
||||||
const progressResult = await fetch(getServer() + '/api/system/bootProgress')
|
const progressResult = await fetch(
|
||||||
|
getServer() + '/api/system/bootProgress')
|
||||||
const progressData = await progressResult.json()
|
const progressData = await progressResult.json()
|
||||||
if (progressData.data.progress >= 100) {
|
if (progressData.data.progress >= 100) {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
|
|
@ -714,9 +562,199 @@ app.commandLine.appendSwitch('enable-features', 'PlatformHEVCDecoderSupport')
|
||||||
app.setPath('userData', app.getPath('userData') + '-Electron') // `~/.config` 下 Electron 相关文件夹名称改为 `SiYuan-Electron` https://github.com/siyuan-note/siyuan/issues/3349
|
app.setPath('userData', app.getPath('userData') + '-Electron') // `~/.config` 下 Electron 相关文件夹名称改为 `SiYuan-Electron` https://github.com/siyuan-note/siyuan/issues/3349
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
|
const resetTrayMenu = (tray, lang, mainWindow) => {
|
||||||
|
const trayMenuTemplate = [
|
||||||
|
{
|
||||||
|
label: mainWindow.isVisible()
|
||||||
|
? lang.hideWindow
|
||||||
|
: lang.showWindow,
|
||||||
|
click: () => {
|
||||||
|
showHideWnd(tray, lang, mainWindow)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: lang.officialWebsite,
|
||||||
|
click: () => {
|
||||||
|
shell.openExternal('https://b3log.org/siyuan/')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: lang.openSource,
|
||||||
|
click: () => {
|
||||||
|
shell.openExternal('https://github.com/siyuan-note/siyuan')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: lang.resetWindow,
|
||||||
|
type: 'checkbox',
|
||||||
|
click: v => {
|
||||||
|
resetWindowStateOnRestart = v.checked
|
||||||
|
mainWindow.webContents.send('siyuan-save-close', true)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: lang.quit,
|
||||||
|
click: () => {
|
||||||
|
mainWindow.webContents.send('siyuan-save-close', true)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
if ('win32' === process.platform) {
|
||||||
|
// Windows 端支持窗口置顶 https://github.com/siyuan-note/siyuan/issues/6860
|
||||||
|
trayMenuTemplate.splice(1, 0, {
|
||||||
|
label: mainWindow.isAlwaysOnTop()
|
||||||
|
? lang.cancelWindowTop
|
||||||
|
: lang.setWindowTop,
|
||||||
|
click: () => {
|
||||||
|
if (!mainWindow.isAlwaysOnTop()) {
|
||||||
|
mainWindow.setAlwaysOnTop(true)
|
||||||
|
} else {
|
||||||
|
mainWindow.setAlwaysOnTop(false)
|
||||||
|
}
|
||||||
|
resetTrayMenu(tray, lang, mainWindow)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const contextMenu = Menu.buildFromTemplate(trayMenuTemplate)
|
||||||
|
tray.setContextMenu(contextMenu)
|
||||||
|
}
|
||||||
|
const showHideWnd = (tray, lang, mainWindow) => {
|
||||||
|
if (!mainWindow.isVisible()) {
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore()
|
||||||
|
}
|
||||||
|
mainWindow.show()
|
||||||
|
} else {
|
||||||
|
mainWindow.hide()
|
||||||
|
}
|
||||||
|
|
||||||
|
resetTrayMenu(tray, lang, mainWindow)
|
||||||
|
}
|
||||||
|
|
||||||
ipcMain.on('siyuan-first-quit', () => {
|
ipcMain.on('siyuan-first-quit', () => {
|
||||||
app.exit()
|
app.exit()
|
||||||
})
|
})
|
||||||
|
ipcMain.on('siyuan-show', (event, id) => {
|
||||||
|
const mainWindow = BrowserWindow.fromId(id)
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore()
|
||||||
|
}
|
||||||
|
if (!mainWindow.isVisible()) {
|
||||||
|
mainWindow.show()
|
||||||
|
}
|
||||||
|
mainWindow.focus()
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-config-theme', (event, theme) => {
|
||||||
|
nativeTheme.themeSource = theme
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-config-tray', (event, id) => {
|
||||||
|
BrowserWindow.fromId(id).hide()
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-export-pdf', (event, data) => {
|
||||||
|
BrowserWindow.fromId(data.id).webContents.send('siyuan-export-pdf', data)
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-export-close', (event, id) => {
|
||||||
|
BrowserWindow.fromId(id).webContents.send('siyuan-export-close', data)
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-quit', (id) => {
|
||||||
|
const mainWindow = BrowserWindow.fromId(id)
|
||||||
|
let tray
|
||||||
|
workspaces.find((item, index) => {
|
||||||
|
if (item.id === id) {
|
||||||
|
mainWindow.destroy()
|
||||||
|
tray = item.tray
|
||||||
|
workspaces.splice(index, 1)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (tray && 'win32' === process.platform) {
|
||||||
|
tray.destroy()
|
||||||
|
}
|
||||||
|
if (workspaces.length === 0) {
|
||||||
|
try {
|
||||||
|
if (resetWindowStateOnRestart) {
|
||||||
|
fs.writeFileSync(windowStatePath, '{}')
|
||||||
|
} else {
|
||||||
|
const bounds = mainWindow.getBounds()
|
||||||
|
fs.writeFileSync(windowStatePath, JSON.stringify({
|
||||||
|
isMaximized: mainWindow.isMaximized(),
|
||||||
|
fullscreen: mainWindow.isFullScreen(),
|
||||||
|
isDevToolsOpened: mainWindow.webContents.isDevToolsOpened(),
|
||||||
|
x: bounds.x,
|
||||||
|
y: bounds.y,
|
||||||
|
width: bounds.width,
|
||||||
|
height: bounds.height,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
writeLog(e)
|
||||||
|
}
|
||||||
|
app.exit()
|
||||||
|
globalShortcut.unregisterAll()
|
||||||
|
writeLog('exited ui')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-open-workspace', (event, data) => {
|
||||||
|
initKernel(data.workspace, data.lang).then((isSucc) => {
|
||||||
|
if (isSucc) {
|
||||||
|
boot()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-init', async (event, data) => {
|
||||||
|
let tray
|
||||||
|
if ('win32' === process.platform || 'linux' === process.platform) {
|
||||||
|
// 系统托盘
|
||||||
|
tray = new Tray(path.join(appDir, 'stage', 'icon-large.png'))
|
||||||
|
tray.setToolTip('SiYuan v' + appVer)
|
||||||
|
const mainWindow = BrowserWindow.fromId(data.id)
|
||||||
|
resetTrayMenu(tray, data.languages, mainWindow)
|
||||||
|
tray.on('click', () => {
|
||||||
|
showHideWnd(tray, data.languages, mainWindow)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
workspaces.find(item => {
|
||||||
|
if (data.id === item.id) {
|
||||||
|
item.workspaceDir = data.workspaceDir
|
||||||
|
item.tray = tray
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await fetch(getServer() + '/api/system/uiproc?pid=' + process.pid,
|
||||||
|
{method: 'POST'})
|
||||||
|
})
|
||||||
|
ipcMain.on('siyuan-hotkey', (event, data) => {
|
||||||
|
globalShortcut.unregisterAll()
|
||||||
|
if (!data.hotkey) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
globalShortcut.register(data.hotkey, () => {
|
||||||
|
const mainWindow = BrowserWindow.fromId(data.id)
|
||||||
|
if (mainWindow.isMinimized()) {
|
||||||
|
mainWindow.restore()
|
||||||
|
if (!mainWindow.isVisible()) {
|
||||||
|
mainWindow.show()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (mainWindow.isVisible()) {
|
||||||
|
if (!mainWindow.isFocused()) {
|
||||||
|
mainWindow.show()
|
||||||
|
} else {
|
||||||
|
mainWindow.hide()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mainWindow.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
workspaces.find(item => {
|
||||||
|
if (item.id === data.id) {
|
||||||
|
resetTrayMenu(item.tray, data.languages, mainWindow)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
if (firstOpen) {
|
if (firstOpen) {
|
||||||
firstOpenWindow = new BrowserWindow({
|
firstOpenWindow = new BrowserWindow({
|
||||||
|
|
@ -740,8 +778,9 @@ app.whenReady().then(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 改进桌面端初始化时使用的外观语言 https://github.com/siyuan-note/siyuan/issues/6803
|
// 改进桌面端初始化时使用的外观语言 https://github.com/siyuan-note/siyuan/issues/6803
|
||||||
let languages = app.getPreferredSystemLanguages();
|
let languages = app.getPreferredSystemLanguages()
|
||||||
let language = languages && 0 < languages.length && "zh-Hans-CN" === languages[0] ? "zh_CN" : "en_US";
|
let language = languages && 0 < languages.length && 'zh-Hans-CN' ===
|
||||||
|
languages[0] ? 'zh_CN' : 'en_US'
|
||||||
firstOpenWindow.loadFile(
|
firstOpenWindow.loadFile(
|
||||||
initHTMLPath, {
|
initHTMLPath, {
|
||||||
query: {
|
query: {
|
||||||
|
|
@ -753,8 +792,8 @@ app.whenReady().then(() => {
|
||||||
})
|
})
|
||||||
firstOpenWindow.show()
|
firstOpenWindow.show()
|
||||||
// 初始化启动
|
// 初始化启动
|
||||||
ipcMain.on('siyuan-first-init', (event, initData) => {
|
ipcMain.on('siyuan-first-init', (event, data) => {
|
||||||
initKernel(initData).then((isSucc) => {
|
initKernel(data.workspace, data.lang).then((isSucc) => {
|
||||||
if (isSucc) {
|
if (isSucc) {
|
||||||
boot()
|
boot()
|
||||||
}
|
}
|
||||||
|
|
@ -773,34 +812,25 @@ app.whenReady().then(() => {
|
||||||
app.on('open-url', (event, url) => { // for macOS
|
app.on('open-url', (event, url) => { // for macOS
|
||||||
if (url.startsWith('siyuan://')) {
|
if (url.startsWith('siyuan://')) {
|
||||||
siyuanOpenURL = url
|
siyuanOpenURL = url
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
workspaces.forEach(item => {
|
||||||
if (mainWindow.isMinimized()) {
|
if (item.browserWindow && !item.browserWindow.isDestroyed()) {
|
||||||
mainWindow.restore()
|
item.browserWindow.webContents.send('siyuan-openurl', url)
|
||||||
}
|
}
|
||||||
if (!mainWindow.isVisible()) {
|
})
|
||||||
mainWindow.show()
|
|
||||||
}
|
|
||||||
mainWindow.focus()
|
|
||||||
mainWindow.webContents.send('siyuan-openurl', url)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('second-instance', (event, commandLine) => {
|
app.on('second-instance', (event, commandLine) => {
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
workspaces.forEach(item => {
|
||||||
if (mainWindow.isMinimized()) {
|
if (item.browserWindow && !item.browserWindow.isDestroyed()) {
|
||||||
mainWindow.restore()
|
item.browserWindow.webContents.send('siyuan-openurl',
|
||||||
|
commandLine.find((arg) => arg.startsWith('siyuan://')))
|
||||||
}
|
}
|
||||||
if (!mainWindow.isVisible()) {
|
})
|
||||||
mainWindow.show()
|
|
||||||
}
|
|
||||||
mainWindow.focus()
|
|
||||||
mainWindow.webContents.send('siyuan-openurl',
|
|
||||||
commandLine.find((arg) => arg.startsWith('siyuan://')))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
|
const mainWindow = workspaces[0].browserWindow
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow.show()
|
mainWindow.show()
|
||||||
}
|
}
|
||||||
|
|
@ -818,10 +848,12 @@ app.on('web-contents-created', (webContentsCreatedEvent, contents) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.on('before-quit', (event) => {
|
app.on('before-quit', (event) => {
|
||||||
if (mainWindow && !mainWindow.isDestroyed()) {
|
workspaces.forEach(item => {
|
||||||
event.preventDefault()
|
if (item.browserWindow && !item.browserWindow.isDestroyed()) {
|
||||||
mainWindow.webContents.send('siyuan-save-close', true)
|
event.preventDefault()
|
||||||
}
|
item.browserWindow.webContents.send('siyuan-save-close', true)
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const {powerMonitor} = require('electron')
|
const {powerMonitor} = require('electron')
|
||||||
|
|
@ -832,23 +864,36 @@ powerMonitor.on('suspend', () => {
|
||||||
|
|
||||||
powerMonitor.on('resume', async () => {
|
powerMonitor.on('resume', async () => {
|
||||||
writeLog('system resume')
|
writeLog('system resume')
|
||||||
|
const isOnline = async () => {
|
||||||
|
try {
|
||||||
|
const result = await fetch('https://icanhazip.com', {timeout: 1000})
|
||||||
|
return 200 === result.status
|
||||||
|
} catch (e) {
|
||||||
|
try {
|
||||||
|
const result = await fetch('https://www.baidu.com', {timeout: 1000})
|
||||||
|
return 200 === result.status
|
||||||
|
} catch (e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let online = false
|
let online = false
|
||||||
for (let i = 0; i < 7; i++) {
|
for (let i = 0; i < 7; i++) {
|
||||||
if (await isOnline()) {
|
if (await isOnline()) {
|
||||||
online = true
|
online = true
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLog("network is offline")
|
writeLog('network is offline')
|
||||||
await sleep(1000)
|
await sleep(1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!online) {
|
if (!online) {
|
||||||
writeLog("network is offline, do not sync after system resume")
|
writeLog('network is offline, do not sync after system resume')
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
writeLog("sync after system resume")
|
writeLog('sync after system resume')
|
||||||
// 桌面端系统休眠唤醒后同步延时 7s 后再执行 https://github.com/siyuan-note/siyuan/issues/6687
|
// 桌面端系统休眠唤醒后同步延时 7s 后再执行 https://github.com/siyuan-note/siyuan/issues/6687
|
||||||
fetch(getServer() + '/api/sync/performSync', {method: 'POST'})
|
fetch(getServer() + '/api/sync/performSync', {method: 'POST'})
|
||||||
})
|
})
|
||||||
|
|
@ -857,61 +902,3 @@ powerMonitor.on('shutdown', () => {
|
||||||
writeLog('system shutdown')
|
writeLog('system shutdown')
|
||||||
fetch(getServer() + '/api/system/exit', {method: 'POST'})
|
fetch(getServer() + '/api/system/exit', {method: 'POST'})
|
||||||
})
|
})
|
||||||
|
|
||||||
const sleep = (ms) => {
|
|
||||||
return new Promise(resolve => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
|
|
||||||
const isOnline = async () => {
|
|
||||||
try {
|
|
||||||
const result = await fetch("https://icanhazip.com", {timeout: 1000})
|
|
||||||
return 200 === result.status
|
|
||||||
} catch (e) {
|
|
||||||
try {
|
|
||||||
const result = await fetch("https://www.baidu.com", {timeout: 1000})
|
|
||||||
return 200 === result.status
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let kernelPort = 6806
|
|
||||||
|
|
||||||
const getKernelPort = async () => {
|
|
||||||
if (isDevEnv) {
|
|
||||||
writeLog("got kernel port [" + kernelPort + "]")
|
|
||||||
return kernelPort
|
|
||||||
}
|
|
||||||
|
|
||||||
// 改进桌面端拉起内核 https://github.com/siyuan-note/siyuan/issues/6894
|
|
||||||
kernelPort = await getAvailablePort()
|
|
||||||
writeLog("got kernel available port [" + kernelPort + "]")
|
|
||||||
return kernelPort
|
|
||||||
}
|
|
||||||
|
|
||||||
let tryGetPortCount = 0
|
|
||||||
const getAvailablePort = (port = kernelPort) => {
|
|
||||||
// https://gist.github.com/mikeal/1840641
|
|
||||||
|
|
||||||
const server = net.createServer()
|
|
||||||
return new Promise((resolve, reject) => server
|
|
||||||
.on('error', error => {
|
|
||||||
writeLog(error)
|
|
||||||
if (2048 < ++tryGetPortCount) {
|
|
||||||
writeLog('failed to get available port [tryCount=' + tryGetPortCount + ', port=' + port + ']')
|
|
||||||
reject(error)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
server.listen(++port)
|
|
||||||
})
|
|
||||||
.on('listening', () => {
|
|
||||||
writeLog('found an available port [' + port + ']')
|
|
||||||
server.close(() => resolve(port))
|
|
||||||
})
|
|
||||||
.listen(port, '127.0.0.1'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const getServer = () => {
|
|
||||||
return "http://" + localhost + ":" + kernelPort
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import {Constants} from "../constants";
|
import {Constants} from "../constants";
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
import {app, shell} from "electron";
|
import {app, ipcRenderer, shell} from "electron";
|
||||||
import {dialog} from "@electron/remote";
|
import {dialog} from "@electron/remote";
|
||||||
/// #endif
|
/// #endif
|
||||||
import {isBrowser} from "../util/functions";
|
import {isBrowser} from "../util/functions";
|
||||||
|
|
@ -242,8 +242,9 @@ export const about = {
|
||||||
fetchPost("/api/system/setWorkspaceDir", {
|
fetchPost("/api/system/setWorkspaceDir", {
|
||||||
path: workspace
|
path: workspace
|
||||||
}, () => {
|
}, () => {
|
||||||
exportLayout(false, () => {
|
ipcRenderer.send(Constants.SIYUAN_OPEN_WORKSPACE, {
|
||||||
exitSiYuan();
|
workspace,
|
||||||
|
lang: window.siyuan.config.appearance.lang
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,6 @@ export const appearance = {
|
||||||
}
|
}
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_THEME, data.modeOS ? "system" : (data.mode === 1 ? "dark" : "light"));
|
ipcRenderer.send(Constants.SIYUAN_CONFIG_THEME, data.modeOS ? "system" : (data.mode === 1 ? "dark" : "light"));
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSE, data.closeButtonBehavior);
|
|
||||||
/// #endif
|
/// #endif
|
||||||
if (needLoadAsset) {
|
if (needLoadAsset) {
|
||||||
loadAssets(data);
|
loadAssets(data);
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ import {hotKey2Electron, isCtrl, isMac, updateHotkeyTip} from "../protyle/util/c
|
||||||
import {Constants} from "../constants";
|
import {Constants} from "../constants";
|
||||||
import {showMessage} from "../dialog/message";
|
import {showMessage} from "../dialog/message";
|
||||||
import {fetchPost} from "../util/fetch";
|
import {fetchPost} from "../util/fetch";
|
||||||
import {ipcRenderer} from "electron";
|
|
||||||
import {exportLayout} from "../layout/util";
|
import {exportLayout} from "../layout/util";
|
||||||
|
/// #if !BROWSER
|
||||||
|
import {getCurrentWindow} from "@electron/remote";
|
||||||
|
import {ipcRenderer} from "electron";
|
||||||
|
/// #endif
|
||||||
import {confirmDialog} from "../dialog/confirmDialog";
|
import {confirmDialog} from "../dialog/confirmDialog";
|
||||||
|
|
||||||
export const keymap = {
|
export const keymap = {
|
||||||
|
|
@ -132,7 +135,11 @@ export const keymap = {
|
||||||
data
|
data
|
||||||
}, () => {
|
}, () => {
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_HOTKEY, hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom));
|
ipcRenderer.send(Constants.SIYUAN_HOTKEY, {
|
||||||
|
languages: window.siyuan.languages["_trayMenu"],
|
||||||
|
id: getCurrentWindow().id,
|
||||||
|
hotkey: hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom)
|
||||||
|
});
|
||||||
/// #endif
|
/// #endif
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
@ -219,7 +226,11 @@ export const keymap = {
|
||||||
}, () => {
|
}, () => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_HOTKEY, hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom));
|
ipcRenderer.send(Constants.SIYUAN_HOTKEY, {
|
||||||
|
languages: window.siyuan.languages["_trayMenu"],
|
||||||
|
id: getCurrentWindow().id,
|
||||||
|
hotkey: hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom)
|
||||||
|
});
|
||||||
/// #endif
|
/// #endif
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,10 @@ export abstract class Constants {
|
||||||
public static readonly SIYUAN_DROP_EDITOR: string = "application/siyuan-editor";
|
public static readonly SIYUAN_DROP_EDITOR: string = "application/siyuan-editor";
|
||||||
|
|
||||||
// 渲染进程调主进程
|
// 渲染进程调主进程
|
||||||
|
public static readonly SIYUAN_SHOW: string = "siyuan-show";
|
||||||
public static readonly SIYUAN_CONFIG_THEME: string = "siyuan-config-theme";
|
public static readonly SIYUAN_CONFIG_THEME: string = "siyuan-config-theme";
|
||||||
public static readonly SIYUAN_CONFIG_CLOSE: string = "siyuan-config-close";
|
|
||||||
public static readonly SIYUAN_CONFIG_TRAY: string = "siyuan-config-tray";
|
public static readonly SIYUAN_CONFIG_TRAY: string = "siyuan-config-tray";
|
||||||
public static readonly SIYUAN_CONFIG_CLOSETRAY: string = "siyuan-config-closetray";
|
public static readonly SIYUAN_OPEN_WORKSPACE: string = "siyuan-open-workspace";
|
||||||
public static readonly SIYUAN_QUIT: string = "siyuan-quit";
|
public static readonly SIYUAN_QUIT: string = "siyuan-quit";
|
||||||
public static readonly SIYUAN_HOTKEY: string = "siyuan-hotkey";
|
public static readonly SIYUAN_HOTKEY: string = "siyuan-hotkey";
|
||||||
public static readonly SIYUAN_INIT: string = "siyuan-init";
|
public static readonly SIYUAN_INIT: string = "siyuan-init";
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@ export const exitSiYuan = () => {
|
||||||
buttonElement.addEventListener("click", () => {
|
buttonElement.addEventListener("click", () => {
|
||||||
fetchPost("/api/system/exit", {force: true}, () => {
|
fetchPost("/api/system/exit", {force: true}, () => {
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSETRAY);
|
|
||||||
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
||||||
/// #else
|
/// #else
|
||||||
if (["ios", "android"].includes(window.siyuan.config.system.container) && (window.webkit?.messageHandlers || window.JSAndroid)) {
|
if (["ios", "android"].includes(window.siyuan.config.system.container) && (window.webkit?.messageHandlers || window.JSAndroid)) {
|
||||||
|
|
@ -118,7 +117,6 @@ export const exitSiYuan = () => {
|
||||||
}, 2000);
|
}, 2000);
|
||||||
// 然后等待一段时间后再退出,避免界面主进程退出以后内核子进程被杀死
|
// 然后等待一段时间后再退出,避免界面主进程退出以后内核子进程被杀死
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSETRAY);
|
|
||||||
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
||||||
}, 4000);
|
}, 4000);
|
||||||
/// #endif
|
/// #endif
|
||||||
|
|
@ -129,14 +127,12 @@ export const exitSiYuan = () => {
|
||||||
execInstallPkg: 1 // 0:默认检查新版本,1:不执行新版本安装,2:执行新版本安装
|
execInstallPkg: 1 // 0:默认检查新版本,1:不执行新版本安装,2:执行新版本安装
|
||||||
}, () => {
|
}, () => {
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSETRAY);
|
|
||||||
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
||||||
/// #endif
|
/// #endif
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else { // 正常退出
|
} else { // 正常退出
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSETRAY);
|
|
||||||
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
||||||
/// #else
|
/// #else
|
||||||
if (["ios", "android"].includes(window.siyuan.config.system.container) && (window.webkit?.messageHandlers || window.JSAndroid)) {
|
if (["ios", "android"].includes(window.siyuan.config.system.container) && (window.webkit?.messageHandlers || window.JSAndroid)) {
|
||||||
|
|
|
||||||
|
|
@ -416,11 +416,12 @@ const renderPDF = (id: string) => {
|
||||||
});
|
});
|
||||||
actionElement.querySelector('.b3-button--cancel').addEventListener('click', () => {
|
actionElement.querySelector('.b3-button--cancel').addEventListener('click', () => {
|
||||||
const {ipcRenderer} = require("electron");
|
const {ipcRenderer} = require("electron");
|
||||||
ipcRenderer.send("${Constants.SIYUAN_EXPORT_CLOSE}")
|
ipcRenderer.send("${Constants.SIYUAN_EXPORT_CLOSE}", getCurrentWindow().id)
|
||||||
});
|
});
|
||||||
actionElement.querySelector('.b3-button--text').addEventListener('click', () => {
|
actionElement.querySelector('.b3-button--text').addEventListener('click', () => {
|
||||||
const {ipcRenderer} = require("electron");
|
const {ipcRenderer} = require("electron");
|
||||||
ipcRenderer.send("${Constants.SIYUAN_EXPORT_PDF}", {
|
ipcRenderer.send("${Constants.SIYUAN_EXPORT_PDF}", {
|
||||||
|
id: getCurrentWindow().id,
|
||||||
pdfOptions:{
|
pdfOptions:{
|
||||||
printBackground: true,
|
printBackground: true,
|
||||||
landscape: actionElement.querySelector("#landscape").checked,
|
landscape: actionElement.querySelector("#landscape").checked,
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,6 @@ export const setMode = (modeElementValue: number) => {
|
||||||
window.siyuan.config.appearance = response.data;
|
window.siyuan.config.appearance = response.data;
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_THEME, response.data.modeOS ? "system" : (response.data.mode === 1 ? "dark" : "light"));
|
ipcRenderer.send(Constants.SIYUAN_CONFIG_THEME, response.data.modeOS ? "system" : (response.data.mode === 1 ? "dark" : "light"));
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSE, response.data.closeButtonBehavior);
|
|
||||||
/// #endif
|
/// #endif
|
||||||
loadAssets(response.data);
|
loadAssets(response.data);
|
||||||
document.querySelector("#barMode use").setAttribute("xlink:href", `#icon${window.siyuan.config.appearance.modeOS ? "Mode" : (window.siyuan.config.appearance.mode === 0 ? "Light" : "Dark")}`);
|
document.querySelector("#barMode use").setAttribute("xlink:href", `#icon${window.siyuan.config.appearance.modeOS ? "Mode" : (window.siyuan.config.appearance.mode === 0 ? "Light" : "Dark")}`);
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ export const fetchPost = (url: string, data?: any, cb?: (response: IWebSocketDat
|
||||||
if (url === "/api/system/exit" || url === "/api/system/setWorkspaceDir" || (
|
if (url === "/api/system/exit" || url === "/api/system/setWorkspaceDir" || (
|
||||||
["/api/system/setUILayout"].includes(url) && data.exit // 内核中断,点关闭处理
|
["/api/system/setUILayout"].includes(url) && data.exit // 内核中断,点关闭处理
|
||||||
)) {
|
)) {
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSETRAY);
|
|
||||||
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
ipcRenderer.send(Constants.SIYUAN_QUIT);
|
||||||
}
|
}
|
||||||
/// #endif
|
/// #endif
|
||||||
|
|
|
||||||
|
|
@ -126,14 +126,25 @@ export const onGetConfig = (isStart: boolean) => {
|
||||||
data: window.siyuan.config.keymap
|
data: window.siyuan.config.keymap
|
||||||
}, () => {
|
}, () => {
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_HOTKEY, hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom));
|
ipcRenderer.send(Constants.SIYUAN_HOTKEY, {
|
||||||
|
languages: window.siyuan.languages["_trayMenu"],
|
||||||
|
id: getCurrentWindow().id,
|
||||||
|
hotkey: hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom)
|
||||||
|
});
|
||||||
/// #endif
|
/// #endif
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/// #if !BROWSER
|
/// #if !BROWSER
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_CLOSE, window.siyuan.config.appearance.closeButtonBehavior);
|
ipcRenderer.send(Constants.SIYUAN_INIT, {
|
||||||
ipcRenderer.send(Constants.SIYUAN_INIT, window.siyuan.languages);
|
languages: window.siyuan.languages["_trayMenu"],
|
||||||
ipcRenderer.send(Constants.SIYUAN_HOTKEY, hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom));
|
workspaceDir: window.siyuan.config.system.workspaceDir,
|
||||||
|
id: getCurrentWindow().id,
|
||||||
|
});
|
||||||
|
ipcRenderer.send(Constants.SIYUAN_HOTKEY, {
|
||||||
|
languages: window.siyuan.languages["_trayMenu"],
|
||||||
|
id: getCurrentWindow().id,
|
||||||
|
hotkey: hotKey2Electron(window.siyuan.config.keymap.general.toggleWin.custom)
|
||||||
|
});
|
||||||
/// #endif
|
/// #endif
|
||||||
if (!window.siyuan.config.uiLayout || (window.siyuan.config.uiLayout && !window.siyuan.config.uiLayout.left)) {
|
if (!window.siyuan.config.uiLayout || (window.siyuan.config.uiLayout && !window.siyuan.config.uiLayout.left)) {
|
||||||
window.siyuan.config.uiLayout = Constants.SIYUAN_EMPTY_LAYOUT;
|
window.siyuan.config.uiLayout = Constants.SIYUAN_EMPTY_LAYOUT;
|
||||||
|
|
@ -332,7 +343,7 @@ const winOnClose = (currentWindow: Electron.BrowserWindow, close = false) => {
|
||||||
if (window.siyuan.config.appearance.closeButtonBehavior === 1 && !close) {
|
if (window.siyuan.config.appearance.closeButtonBehavior === 1 && !close) {
|
||||||
// 最小化
|
// 最小化
|
||||||
if ("windows" === window.siyuan.config.system.os) {
|
if ("windows" === window.siyuan.config.system.os) {
|
||||||
ipcRenderer.send(Constants.SIYUAN_CONFIG_TRAY);
|
ipcRenderer.send(Constants.SIYUAN_CONFIG_TRAY, getCurrentWindow().id);
|
||||||
} else {
|
} else {
|
||||||
if (currentWindow.isFullScreen()) {
|
if (currentWindow.isFullScreen()) {
|
||||||
currentWindow.once("leave-full-screen", () => currentWindow.hide());
|
currentWindow.once("leave-full-screen", () => currentWindow.hide());
|
||||||
|
|
@ -359,10 +370,16 @@ const initWindow = () => {
|
||||||
if (!/^siyuan:\/\/blocks\/\d{14}-\w{7}/.test(url)) {
|
if (!/^siyuan:\/\/blocks\/\d{14}-\w{7}/.test(url)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openFileById({
|
const id = url.substr(16, 22);
|
||||||
id: url.substr(16, 22),
|
fetchPost("/api/block/checkBlockExist", {id}, existResponse => {
|
||||||
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
|
if (existResponse.data) {
|
||||||
zoomIn: getSearch("focus", url) === "1"
|
openFileById({
|
||||||
|
id,
|
||||||
|
action: [Constants.CB_GET_FOCUS, Constants.CB_GET_CONTEXT],
|
||||||
|
zoomIn: getSearch("focus", url) === "1"
|
||||||
|
});
|
||||||
|
ipcRenderer.send(Constants.SIYUAN_SHOW, getCurrentWindow().id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ipcRenderer.on(Constants.SIYUAN_SAVE_CLOSE, (event, close) => {
|
ipcRenderer.on(Constants.SIYUAN_SAVE_CLOSE, (event, close) => {
|
||||||
|
|
|
||||||
|
|
@ -432,8 +432,8 @@
|
||||||
const exitApp = () => {
|
const exitApp = () => {
|
||||||
try {
|
try {
|
||||||
const {ipcRenderer} = require('electron')
|
const {ipcRenderer} = require('electron')
|
||||||
ipcRenderer.send('siyuan-config-closetray')
|
const {getCurrentWindow} = require('@electron/remote');
|
||||||
ipcRenderer.send('siyuan-quit')
|
ipcRenderer.send('siyuan-quit', getCurrentWindow().id)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if ((window.webkit && window.webkit.messageHandlers) || window.JSAndroid) {
|
if ((window.webkit && window.webkit.messageHandlers) || window.JSAndroid) {
|
||||||
window.location.href = 'siyuan://api/system/exit'
|
window.location.href = 'siyuan://api/system/exit'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue