1
0
mirror of https://github.com/mifi/lossless-cut.git synced 2024-11-22 10:22:31 +01:00

Only allow a single running instance

Can be overridden by `--allow-multiple-instances` CLI argument
closes #1265
closes #527
This commit is contained in:
Mikael Finstad 2022-10-14 22:31:01 +02:00
parent f3fd5df45b
commit f09369ee17
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26
2 changed files with 101 additions and 74 deletions

View File

@ -221,6 +221,10 @@ See [available settings](https://github.com/mifi/lossless-cut/blob/master/public
LosslessCut --settings-json '{captureFormat:"jpeg", "keyframeCut":true}' LosslessCut --settings-json '{captureFormat:"jpeg", "keyframeCut":true}'
``` ```
### Multiple instances
By default, only a single running instance of LosslessCut is allowed. If you start a new LosslessCut instance from the command line, it will instead pass the list of files onto the already running instance. You can override this behavior by passing `--allow-multiple-instances` via the command line. Running multiple instances is experimental.
## Developing ## Developing
See the [developer notes](developer-notes.md). See the [developer notes](developer-notes.md).

View File

@ -121,100 +121,123 @@ function updateMenu() {
menu(app, mainWindow, newVersion); menu(app, mainWindow, newVersion);
} }
function openFilesEventually(paths) {
if (rendererReady) openFiles(paths);
else filesToOpen = paths;
}
// https://github.com/electron/electron/issues/3657 // https://github.com/electron/electron/issues/3657
// https://github.com/mifi/lossless-cut/issues/357 // https://github.com/mifi/lossless-cut/issues/357
// https://github.com/mifi/lossless-cut/issues/639 // https://github.com/mifi/lossless-cut/issues/639
// https://github.com/mifi/lossless-cut/issues/591 // https://github.com/mifi/lossless-cut/issues/591
function parseCliArgs() { function parseCliArgs(rawArgv = process.argv) {
const ignoreFirstArgs = isDev ? 2 : 1; const ignoreFirstArgs = isDev ? 2 : 1;
// production: First arg is the LosslessCut executable // production: First arg is the LosslessCut executable
// dev: First 2 args are electron and the electron.js // dev: First 2 args are electron and the electron.js
const argsWithoutAppName = process.argv.length > ignoreFirstArgs ? process.argv.slice(ignoreFirstArgs) : []; const argsWithoutAppName = rawArgv.length > ignoreFirstArgs ? rawArgv.slice(ignoreFirstArgs) : [];
return yargsParser(argsWithoutAppName); return yargsParser(argsWithoutAppName);
} }
// This method will be called when Electron has finished const argv = parseCliArgs();
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
// https://github.com/electron/electron/issues/23757
// https://github.com/electron/electron/pull/28489
// TODO I think this can be removed when we are on electron 12 or 14
if (isDev) {
electron.protocol.registerFileProtocol('file', (request, callback) => {
const pathname = decodeURIComponent(request.url.replace('file:///', ''));
callback(pathname);
});
}
await configStore.init(); if (!argv.allowMultipleInstances && !app.requestSingleInstanceLock()) {
const argv = parseCliArgs();
logger.info('CLI arguments', argv);
// Only if no files to open already (open-file might have already added some files)
if (filesToOpen.length === 0) filesToOpen = argv._;
const { settingsJson } = argv;
if (settingsJson != null) {
logger.info('initializing settings', settingsJson);
Object.entries(JSON5.parse(settingsJson)).forEach(([key, value]) => {
configStore.set(key, value);
});
}
if (isDev) {
const { default: installExtension, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer'); // eslint-disable-line global-require,import/no-extraneous-dependencies
installExtension(REACT_DEVELOPER_TOOLS)
.then(name => logger.info('Added Extension', name))
.catch(err => logger.error('Failed to add extension', err));
}
createWindow();
updateMenu();
if (!process.windowsStore && !process.mas) {
newVersion = await checkNewVersion();
// newVersion = '1.2.3';
if (newVersion) updateMenu();
}
});
// Quit when all windows are closed.
app.on('window-all-closed', () => {
app.quit(); app.quit();
}); } else {
// On macOS, the system enforces single instance automatically when users try to open a second instance of your app in Finder, and the open-file and open-url events will be emitted for that.
// However when users start your app in command line, the system's single instance mechanism will be bypassed, and you have to use this method to ensure single instance.
// This can be tested with one terminal: npx electron .
// and another terminal: npx electron . path/to/file.mp4
app.on('second-instance', (event, commandLine) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore();
mainWindow.focus();
}
const argv2 = parseCliArgs(commandLine);
if (argv2._) openFilesEventually(argv2._);
});
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', async () => {
// https://github.com/electron/electron/issues/23757
// https://github.com/electron/electron/pull/28489
// TODO I think this can be removed when we are on electron 12 or 14
if (isDev) {
electron.protocol.registerFileProtocol('file', (request, callback) => {
const pathname = decodeURIComponent(request.url.replace('file:///', ''));
callback(pathname);
});
}
await configStore.init();
logger.info('CLI arguments', argv);
// Only if no files to open already (open-file might have already added some files)
if (filesToOpen.length === 0) filesToOpen = argv._;
const { settingsJson } = argv;
if (settingsJson != null) {
logger.info('initializing settings', settingsJson);
Object.entries(JSON5.parse(settingsJson)).forEach(([key, value]) => {
configStore.set(key, value);
});
}
if (isDev) {
const { default: installExtension, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer'); // eslint-disable-line global-require,import/no-extraneous-dependencies
installExtension(REACT_DEVELOPER_TOOLS)
.then(name => logger.info('Added Extension', name))
.catch(err => logger.error('Failed to add extension', err));
}
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow(); createWindow();
} updateMenu();
});
ipcMain.on('renderer-ready', () => { if (!process.windowsStore && !process.mas) {
rendererReady = true; newVersion = await checkNewVersion();
if (filesToOpen.length > 0) openFiles(filesToOpen); // newVersion = '1.2.3';
}); if (newVersion) updateMenu();
}
});
// Mac OS open with LosslessCut // Quit when all windows are closed.
// Emitted when the user wants to open a file with the application. The open-file event is usually emitted when the application is already open and the OS wants to reuse the application to open the file. app.on('window-all-closed', () => {
app.on('open-file', (event, path) => { app.quit();
if (rendererReady) openFiles([path]); });
else filesToOpen = [path];
event.preventDefault(); // recommended in docs https://www.electronjs.org/docs/latest/api/app#event-open-file-macos
});
ipcMain.on('setAskBeforeClose', (e, val) => { app.on('activate', () => {
askBeforeClose = val; // On OS X it's common to re-create a window in the app when the
}); // dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
ipcMain.on('setLanguage', (e, language) => { ipcMain.on('renderer-ready', () => {
i18n.changeLanguage(language).then(() => updateMenu()).catch((err) => logger.error('Failed to set language', err)); rendererReady = true;
}); if (filesToOpen.length > 0) openFiles(filesToOpen);
});
// Mac OS open with LosslessCut
// Emitted when the user wants to open a file with the application. The open-file event is usually emitted when the application is already open and the OS wants to reuse the application to open the file.
app.on('open-file', (event, path) => {
openFilesEventually([path]);
event.preventDefault(); // recommended in docs https://www.electronjs.org/docs/latest/api/app#event-open-file-macos
});
ipcMain.on('setAskBeforeClose', (e, val) => {
askBeforeClose = val;
});
ipcMain.on('setLanguage', (e, language) => {
i18n.changeLanguage(language).then(() => updateMenu()).catch((err) => logger.error('Failed to set language', err));
});
}
function focusWindow() { function focusWindow() {
try { try {