moving to electron 14+, jumping through hoops...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-01-26 22:19:42 +03:00
parent 0a85322798
commit 6f77e6116b
6 changed files with 2560 additions and 2181 deletions

View File

@ -302,6 +302,16 @@ button:hover {
color: red; color: red;
} }
.drag-bar {
position: absolute;
-webkit-app-region: drag;
height: 50px;
top: 0px;
left: 0px;
right: 0px;
}
/* /*
.full-screen-mode .title-bar { .full-screen-mode .title-bar {
display: none; display: none;
@ -313,6 +323,7 @@ button:hover {
display: block; display: block;
position: relative; position: relative;
float: left; float: left;
-webkit-app-region: no-drag;
size: 30px; size: 30px;

View File

@ -35,6 +35,7 @@ var VERSION = require('./version').version
var app = electron.app var app = electron.app
var BrowserWindow = electron.BrowserWindow var BrowserWindow = electron.BrowserWindow
var ipcMain = electron.ipcMain
// //
global.ELECTRON_PACKAGED = app.isPackaged global.ELECTRON_PACKAGED = app.isPackaged
@ -46,15 +47,17 @@ global.START_GUI = false
/*********************************************************************/ /*********************************************************************/
// XXX do we need multiwindow support???
// Splash window... // Splash window...
// //
// XXX might be nice to show load progress on splash... // XXX might be nice to show load progress on splash...
var SPLASH
function createSplash(){ function createSplash(){
// NOTE: this is done here as this does not depend on code loading, // NOTE: this is done here as this does not depend on code loading,
// thus showing the splash significantly faster... // thus showing the splash significantly faster...
var splash = global.splash = new BrowserWindow({ SPLASH = new BrowserWindow({
// let the window to get ready before we show it to the user... // let the window to get ready before we show it to the user...
show: false, show: false,
@ -74,31 +77,44 @@ function createSplash(){
autoHideMenuBar: true, autoHideMenuBar: true,
}) })
splash.loadURL(url.format({ SPLASH.loadURL(url.format({
pathname: path.join(__dirname, 'splash.html'), pathname: path.join(__dirname, 'splash.html'),
protocol: 'file:', protocol: 'file:',
slashes: true slashes: true
})) }))
splash.once('ready-to-show', function(){ SPLASH.once('ready-to-show', function(){
this.webContents this.webContents
// see if the splash screen is disabled... // see if the splash screen is disabled...
.executeJavaScript('localStorage.disableSplashScreen') .executeJavaScript('localStorage.disableSplashScreen')
.then(function(disabled){ .then(function(disabled){
// update version... // update version...
disabled disabled
|| splash.webContents || SPLASH.webContents
.executeJavaScript( .executeJavaScript(
`document.getElementById("version").innerText = "${VERSION}"`) `document.getElementById("version").innerText = "${VERSION}"`)
// show/destroy.. // show/destroy..
disabled ? disabled ?
splash.destroy() SPLASH.destroy()
: splash.show() }) }) : SPLASH.show() }) })
return splash } SPLASH.on('closed',
function(){
SPLASH = null
WIN
&& WIN.webContents.executeJavaScript('document.appSplashScreen = false') })
// handle main window state...
WIN
&& WIN.webContents.executeJavaScript('document.appSplashScreen = true')
return SPLASH }
// Create main window... // Create main window...
// //
// XXX get initial settings from config... // XXX get initial settings from config...
// XXX handle maximize corretly...
// ...currently it does not differ visually from fullscreen -- either
// make them the same or keep them separate visually...
var WIN var WIN
function createWindow(){ function createWindow(){
// Create the browser window. // Create the browser window.
@ -112,6 +128,7 @@ function createWindow(){
// let the window get ready before we show it to the user... // let the window get ready before we show it to the user...
show: false, show: false,
frame: false,
backgroundColor: '#333333', backgroundColor: '#333333',
@ -129,18 +146,39 @@ function createWindow(){
protocol: 'file:', protocol: 'file:',
slashes: true, slashes: true,
})) }))
// XXX HACK: pass this in a formal way... (???)
WIN.once('ready-to-show', WIN.once('ready-to-show',
function(){ global.readyToShow = true }) function(){
WIN.webContents.executeJavaScript(`
document.readyToShow = true
// XXX make these a prop...
document.appFullScreen = false
document.appDevTools = false
`)
// splash screen...
WIN.webContents.executeJavaScript(
SPLASH ?
'document.appSplashScreen = true'
: 'document.appSplashScreen = false') })
WIN.on('closed', WIN.on('closed',
function(){ WIN = null }) function(){ WIN = null })
// devtools...
WIN.on('devtools-opened',
function(){
WIN && WIN.webContents.executeJavaScript('document.appDevTools = true') })
WIN.on('devtools-closed',
function(){
WIN && WIN.webContents.executeJavaScript('document.appDevTools = false') })
// handle env...
// devtools for different windows... // devtools for different windows...
//process.env.IMAGEGRID_ROOT_DEBUG
// && WIN.openDevTools({mode: 'undocked'})
process.env.IMAGEGRID_DEBUG process.env.IMAGEGRID_DEBUG
&& WIN.openDevTools({mode: 'undocked'}) && WIN.openDevTools({mode: 'undocked'})
//&& WIN.webContents.openDevTools({mode: 'undocked'}) // Force show window...
process.env.IMAGEGRID_FORCE_SHOW
&& WIN.show()
return WIN } return WIN }
@ -163,9 +201,9 @@ function start(){
// On macOS it's common to re-create a window in the app when the // On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open. // dock icon is clicked and there are no other windows open.
// XXX test...
app.on('activate', function(){ app.on('activate', function(){
WIN === null WIN || createWindow() })
&& createWindow() })
// Quit when all windows are closed. // Quit when all windows are closed.
// On macOS it is common for applications and their menu bar // On macOS it is common for applications and their menu bar
@ -176,6 +214,49 @@ app.on('window-all-closed', function(){
//---------------------------------------------------------------------
// Window states...
ipcMain.on('show',
function(){ WIN && WIN.show() })
ipcMain.on('hide',
function(){ WIN && WIN.hide() })
ipcMain.on('minimize',
function(){ WIN && WIN.minimize() })
ipcMain.on('enterFullScreen',
function(){
if(WIN){
WIN.setFullScreen(true)
WIN.webContents.executeJavaScript('document.appFullScreen = true') } })
ipcMain.on('exitFullScreen',
function(){
if(WIN){
WIN.setFullScreen(false)
WIN.webContents.executeJavaScript('document.appFullScreen = false') } })
// Splash screen...
ipcMain.on('openSplashScreen',
function(){ SPLASH || createSplash() })
ipcMain.on('closeSplashScreen',
function(){ SPLASH && SPLASH.destroy() })
// devtools...
// XXX need to focus devtools here...
// see: webContents.getAllWebContents()
ipcMain.on('openDevTools',
function(){
WIN
&& WIN.openDevTools({
mode: 'undocked',
activate: true,
}) })
ipcMain.on('closeDevTools',
function(){ WIN && WIN.closeDevTools() })
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// start things up... // start things up...

View File

@ -212,8 +212,7 @@ var NWHostActions = actions.Actions({
function(action){ function(action){
if(action == '?'){ if(action == '?'){
// XXX get the devtools stage... // XXX get the devtools stage...
return false return false }
}
nw.Window.get().showDevTools && nw.Window.get().showDevTools &&
nw.Window.get().showDevTools() nw.Window.get().showDevTools()
}], }],
@ -257,46 +256,44 @@ var ElectronHostActions = actions.Actions({
// XXX should this be nested in a .window object??? // XXX should this be nested in a .window object???
// XXX should these be props or methods??? // XXX should these be props or methods???
get title(){ get title(){
return electron.remote.getCurrentWindow().getTitle() }, return document.title },
set title(value){ set title(value){
electron.remote.getCurrentWindow().setTitle(value) }, document.title = value },
get size(){ get size(){
return electron.remote.getCurrentWindow().getSize() }, return [window.outerWidth, window.outerHeight] },
set size(value){ set size(value){
value value
&& electron.remote.getCurrentWindow() && window.resizeTo(...value) },
.setSize(Math.round(value[0]), Math.round(value[1])) },
get position(){ get position(){
return electron.remote.getCurrentWindow().getPosition() }, return [window.screenX, window.screenY] },
set position(value){ set position(value){
value value
&& electron.remote.getCurrentWindow() && window.moveTo(...value) },
.setPosition(Math.round(value[0]), Math.round(value[1])) },
// XXX revise...
// XXX need to handle mazimize correctly -- see e.js...
// XXX do we need .hide(..) here???
show: ['- Window/', show: ['- Window/',
function(){ function(){
if(electron.remote.getGlobal('readyToShow')){ electron.ipcRenderer.send('show') }],
electron.remote.getCurrentWindow().show() // if(electron.remote.getGlobal('readyToShow')){
// electron.remote.getCurrentWindow().show()
} else { // } else {
var win = electron.remote.getCurrentWindow() // var win = electron.remote.getCurrentWindow()
win.once('ready-to-show', function(){ // win.once('ready-to-show',
win.show() // function(){ win.show() }) } }],
})
}
}],
minimize: ['Window/Minimize', minimize: ['Window/Minimize',
function(){ function(){
electron.remote.getCurrentWindow().minimize() }], electron.ipcRenderer.send('minimize') }],
toggleFullScreen: ['Window/Full screen mode', toggleFullScreen: ['Window/Full screen mode',
toggler.CSSClassToggler( toggler.CSSClassToggler(
function(){ return document.body }, function(){ return document.body },
'.full-screen-mode', '.full-screen-mode',
function(action){ function(action){
var that = this var that = this
var win = electron.remote.getCurrentWindow()
var state = win.isFullScreen() ? 'on' : 'off' // get current state...
var state = document.appFullScreen ? 'on' : 'off'
// change the state only if the target state is not the same // change the state only if the target state is not the same
// as the current state... // as the current state...
@ -306,10 +303,14 @@ var ElectronHostActions = actions.Actions({
// hide the viewer to hide any animation crimes... // hide the viewer to hide any animation crimes...
this.dom[0].style.visibility = 'hidden' this.dom[0].style.visibility = 'hidden'
// XXX async... // NOTE: electrons policy that developers can't trust
// ...this complicates things as we need to do the next // their own code making them jump through context
// bit AFTER the resize is done... // hoops all of the time instead of in the specific
win.setFullScreen(action == 'on' ? true : false) // contexts that need isolation is crap...
electron.ipcRenderer.send(
state == 'on' ?
'exitFullScreen'
: 'enterFullScreen')
setTimeout(function(){ setTimeout(function(){
that that
@ -317,32 +318,16 @@ var ElectronHostActions = actions.Actions({
.focusImage() .focusImage()
.ribbons .ribbons
.restoreTransitions() .restoreTransitions()
// show viewer after we are done...
that.dom[0].style.visibility = '' that.dom[0].style.visibility = '' }, 150) } })],
}, 100)
}
// NOTE: we delay this to account for window animation...
setTimeout(function(){
that.storeWindowGeometry()
}, 500)
})],
// XXX should this be a toggler??? // XXX should this be a toggler???
showDevTools: ['Interface|Development/Show Dev Tools', showDevTools: ['Interface|Development/Show Dev Tools',
{mode: 'advancedBrowseModeAction'}, {mode: 'advancedBrowseModeAction'},
function(action){ function(action){
var w = electron.remote.getCurrentWindow()
if(action == '?'){ if(action == '?'){
return w.isDevToolsOpened() return document.appDevTools }
} electron.ipcRenderer.send('openDevTools') }],
w.openDevTools()
// focus the devtools if its window is available...
w.devToolsWebContents
&& w.devToolsWebContents.focus()
}],
// XXX make this portable (osx, linux)... // XXX make this portable (osx, linux)...
showInFolder: ['File|Image/Show in $folder', showInFolder: ['File|Image/Show in $folder',
function(image){ function(image){
@ -363,60 +348,16 @@ var ElectronHostActions = actions.Actions({
toggleSplashScreen: ['Interface/', toggleSplashScreen: ['Interface/',
{mode: 'advancedBrowseModeAction'}, {mode: 'advancedBrowseModeAction'},
function(action){ function(action){
var splash = this.splash = (!this.splash || this.splash.isDestroyed()) ? var splash = document.appSplashScreen
electron.remote.getGlobal('splash')
: this.splash
if(action == '?'){ if(action == '?'){
return !splash || splash.isDestroyed() ? 'off' : 'on' return !splash ? 'off' : 'on' }
}
// XXX HACK: use real toggler protocol... if(action != 'off' && !splash){
if(action != 'off' && (!splash || splash.isDestroyed())){ electron.ipcRenderer.send('openSplashScreen')
var splash = this.splash =
// XXX move this to splash.js and use both here and in e.js...
new electron.remote.BrowserWindow({
// let the window to get ready before we show it to the user...
show: false,
transparent: true,
frame: false,
center: true,
width: 800,
height: 500,
alwaysOnTop: true,
resizable: false,
movable: false,
minimizable: false,
maximizable: false,
fullscreenable: false,
autoHideMenuBar: true,
})
splash.setMenu(null)
// and load the index.html of the app.
splash.loadURL(url.format({
// XXX unify this with index.html
pathname: pathlib.join(__dirname, 'splash.html'),
protocol: 'file:',
slashes: true
}))
splash.once('ready-to-show', function(){
splash.webContents
.executeJavaScript(
`document.getElementById("version").innerText = "${VERSION}"`)
splash.show()
})
} else if(action != 'on' && splash){ } else if(action != 'on' && splash){
splash.destroy() electron.ipcRenderer.send('closeSplashScreen') } }],
}
}],
// XXX should this support resizing??? // XXX should this support resizing???
copy: ['Image|Edit/Copy image', copy: ['Image|Edit/Copy image',
@ -669,7 +610,8 @@ var WindowedAppControlActions = actions.Actions({
// is defined... // is defined...
var cfg = this.config.window = this.config.window || {} var cfg = this.config.window = this.config.window || {}
cfg.fullscreen = true cfg.fullscreen = true
cfg.devtools = this.showDevTools('?') cfg.devtools = this.showDevTools
&& this.showDevTools('?')
} else { } else {
this.config.window = { this.config.window = {
@ -680,18 +622,15 @@ var WindowedAppControlActions = actions.Actions({
y: position[1], y: position[1],
fullscreen: false, fullscreen: false,
devtools: this.showDevTools('?'), devtools: this.showDevTools
} && this.showDevTools('?'),
} } } }],
}],
restoreWindowGeometry: ['- Window/Restore window state', restoreWindowGeometry: ['- Window/Restore window state',
function(){ function(){
var that = this var that = this
var cfg = this.config.window || {} var cfg = this.config.window || {}
var fullscreen = cfg.fullscreen || false if(cfg.fullscreen){
if(fullscreen){
that.toggleFullScreen('on') that.toggleFullScreen('on')
} else { } else {
@ -701,9 +640,7 @@ var WindowedAppControlActions = actions.Actions({
var y = cfg.y || (screen.height - h)/2 var y = cfg.y || (screen.height - h)/2
this.position = [x, y] this.position = [x, y]
this.size = [w, h] this.size = [w, h] } }],
}
}],
toggleSplashScreenShowing: ['Interface/Splash screen on start', toggleSplashScreenShowing: ['Interface/Splash screen on start',
{mode: 'advancedBrowseModeAction'}, {mode: 'advancedBrowseModeAction'},
@ -761,6 +698,9 @@ module.WindowedAppControl = core.ImageGridFeatures.Feature({
// NOTE: this will also set the size to which the OS will // NOTE: this will also set the size to which the OS will
// resize the window in state change... // resize the window in state change...
if(cfg){ if(cfg){
cfg.devtools
&& this.showDevTools()
var W = screen.width var W = screen.width
var H = screen.height var H = screen.height
var w = cfg.width || Math.max(0.8 * W, 600) var w = cfg.width || Math.max(0.8 * W, 600)
@ -769,18 +709,14 @@ module.WindowedAppControl = core.ImageGridFeatures.Feature({
var y = cfg.y || (H - h)/2 var y = cfg.y || (H - h)/2
this.position = [x, y] this.position = [x, y]
this.size = [w, h] this.size = [w, h] }
cfg.devtools
&& this.showDevTools() }
// restore actual window state... // restore actual window state...
this.restoreWindowGeometry() this.restoreWindowGeometry()
// declare we are ready when DOM is ready... // declare we are ready when DOM is ready...
$(function(){ $(function(){
that.declareReady('ui-windowed-app-control') }) that.declareReady('ui-windowed-app-control') }) }],
}],
// show window + hide splash screen... // show window + hide splash screen...
['ready', ['ready',

View File

@ -63,8 +63,7 @@ if(window.require){
// electron... // electron...
} else { } else {
try{ try{
require('electron').remote.getCurrentWindow() require('electron').ipcRenderer.send('openDevTools')
.openDevTools({mode: 'undocked'})
} catch(err){ } } } catch(err){ } }
}, STARTUP_DEVTOOLS_TIMEOUT) } }, STARTUP_DEVTOOLS_TIMEOUT) }
</script> </script>
@ -180,7 +179,9 @@ if(typeof(process) == 'undefined'){
<!-- The Viewer block (see: imagegrid/ribbons.js) --> <!-- The Viewer block (see: imagegrid/ribbons.js) -->
<div class="viewer gray marks-visible" tabindex="0"></div> <div class="viewer gray marks-visible" tabindex="0">
<div class="drag-bar"></div>
</div>
<!-- vim:set ts=4 sw=4 spell nowrap : --> <!-- vim:set ts=4 sw=4 spell nowrap : -->

4402
Viewer/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
"async-json": "0.0.2", "async-json": "0.0.2",
"cli-progress": "^3.9.0", "cli-progress": "^3.9.0",
"colors": "^1.4.0", "colors": "^1.4.0",
"electron": "^9.4.3", "electron": "*",
"exif-reader": "^1.0.3", "exif-reader": "^1.0.3",
"exifreader": "^2.6.0", "exifreader": "^2.6.0",
"exiftool": "^0.0.3", "exiftool": "^0.0.3",
@ -55,7 +55,7 @@
}, },
"devDependencies": { "devDependencies": {
"asar": "^3.0.1", "asar": "^3.0.1",
"electron-rebuild": "^1.11.0", "electron-rebuild": "*",
"less": "^3.13.1", "less": "^3.13.1",
"rcedit": "^3.0.0" "rcedit": "^3.0.0"
}, },