mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-08 11:56:36 +00:00
Enable opening the IDE from finder/explorer (#835)
* Enable opening the IDE from finder/explorer * Make opening windows from args a bit more lenient
This commit is contained in:
parent
d79f32efd7
commit
0207778373
@ -1,8 +1,8 @@
|
|||||||
import { inject, injectable } from 'inversify';
|
import { inject, injectable } from 'inversify';
|
||||||
import { app, BrowserWindow, BrowserWindowConstructorOptions, ipcMain, screen } from '@theia/core/electron-shared/electron';
|
import { app, BrowserWindow, BrowserWindowConstructorOptions, ipcMain, screen, Event as ElectronEvent } from '@theia/core/electron-shared/electron';
|
||||||
import { fork } from 'child_process';
|
import { fork } from 'child_process';
|
||||||
import { AddressInfo } from 'net';
|
import { AddressInfo } from 'net';
|
||||||
import { join } from 'path';
|
import { join, dirname } from 'path';
|
||||||
import * as fs from 'fs-extra';
|
import * as fs from 'fs-extra';
|
||||||
import { initSplashScreen } from '../splash/splash-screen';
|
import { initSplashScreen } from '../splash/splash-screen';
|
||||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||||
@ -16,6 +16,8 @@ import {
|
|||||||
import { SplashServiceImpl } from '../splash/splash-service-impl';
|
import { SplashServiceImpl } from '../splash/splash-service-impl';
|
||||||
import { URI } from '@theia/core/shared/vscode-uri';
|
import { URI } from '@theia/core/shared/vscode-uri';
|
||||||
import * as electronRemoteMain from '@theia/core/electron-shared/@electron/remote/main';
|
import * as electronRemoteMain from '@theia/core/electron-shared/@electron/remote/main';
|
||||||
|
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||||
|
import * as os from '@theia/core/lib/common/os';
|
||||||
|
|
||||||
app.commandLine.appendSwitch('disable-http-cache');
|
app.commandLine.appendSwitch('disable-http-cache');
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ const WORKSPACES = 'workspaces';
|
|||||||
export class ElectronMainApplication extends TheiaElectronMainApplication {
|
export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||||
protected _windows: BrowserWindow[] = [];
|
protected _windows: BrowserWindow[] = [];
|
||||||
protected startup = false;
|
protected startup = false;
|
||||||
|
protected openFilePromise = new Deferred();
|
||||||
|
|
||||||
@inject(SplashServiceImpl)
|
@inject(SplashServiceImpl)
|
||||||
protected readonly splashService: SplashServiceImpl;
|
protected readonly splashService: SplashServiceImpl;
|
||||||
@ -45,17 +48,52 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
|||||||
// See: https://github.com/electron-userland/electron-builder/issues/2468
|
// See: https://github.com/electron-userland/electron-builder/issues/2468
|
||||||
// Regression in Theia: https://github.com/eclipse-theia/theia/issues/8701
|
// Regression in Theia: https://github.com/eclipse-theia/theia/issues/8701
|
||||||
app.on('ready', () => app.setName(config.applicationName));
|
app.on('ready', () => app.setName(config.applicationName));
|
||||||
|
this.attachFileAssociations();
|
||||||
return super.start(config);
|
return super.start(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attachFileAssociations() {
|
||||||
|
// OSX: register open-file event
|
||||||
|
if (os.isOSX) {
|
||||||
|
app.on('open-file', async (event, uri) => {
|
||||||
|
event.preventDefault();
|
||||||
|
if (uri.endsWith('.ino') && await fs.pathExists(uri)) {
|
||||||
|
this.openFilePromise.reject();
|
||||||
|
await this.openSketch(dirname(uri));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setTimeout(() => this.openFilePromise.resolve(), 500);
|
||||||
|
} else {
|
||||||
|
this.openFilePromise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async isValidSketchPath(uri: string): Promise<boolean | undefined> {
|
||||||
|
return typeof uri === 'string' && await fs.pathExists(uri);
|
||||||
|
}
|
||||||
|
|
||||||
protected async launch(params: ElectronMainExecutionParams): Promise<void> {
|
protected async launch(params: ElectronMainExecutionParams): Promise<void> {
|
||||||
|
try {
|
||||||
|
// When running on MacOS, we either have to wait until
|
||||||
|
// 1. The `open-file` command has been received by the app, rejecting the promise
|
||||||
|
// 2. A short timeout resolves the promise automatically, falling back to the usual app launch
|
||||||
|
await this.openFilePromise.promise;
|
||||||
|
} catch {
|
||||||
|
// Application has received the `open-file` event and will skip the default application launch
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!os.isOSX && await this.launchFromArgs(params)) {
|
||||||
|
// Application has received a file in its arguments and will skip the default application launch
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.startup = true;
|
this.startup = true;
|
||||||
const workspaces: WorkspaceOptions[] | undefined = this.electronStore.get(WORKSPACES);
|
const workspaces: WorkspaceOptions[] | undefined = this.electronStore.get(WORKSPACES);
|
||||||
let useDefault = true;
|
let useDefault = true;
|
||||||
if (workspaces && workspaces.length > 0) {
|
if (workspaces && workspaces.length > 0) {
|
||||||
for (const workspace of workspaces) {
|
for (const workspace of workspaces) {
|
||||||
const file = workspace.file;
|
if (await this.isValidSketchPath(workspace.file)) {
|
||||||
if (typeof file === 'string' && await fs.pathExists(file)) {
|
|
||||||
useDefault = false;
|
useDefault = false;
|
||||||
await this.openSketch(workspace);
|
await this.openSketch(workspace);
|
||||||
}
|
}
|
||||||
@ -67,16 +105,39 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async openSketch(workspace: WorkspaceOptions): Promise<BrowserWindow> {
|
protected async launchFromArgs(params: ElectronMainExecutionParams): Promise<boolean> {
|
||||||
|
// Copy to prevent manipulation of original array
|
||||||
|
const argCopy = [...params.argv];
|
||||||
|
let uri: string | undefined;
|
||||||
|
for (const possibleUri of argCopy) {
|
||||||
|
if (possibleUri.endsWith('.ino') && await this.isValidSketchPath(possibleUri)) {
|
||||||
|
uri = possibleUri;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (uri) {
|
||||||
|
await this.openSketch(dirname(uri));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async openSketch(workspace: WorkspaceOptions | string): Promise<BrowserWindow> {
|
||||||
const options = await this.getLastWindowOptions();
|
const options = await this.getLastWindowOptions();
|
||||||
|
let file: string;
|
||||||
|
if (typeof workspace === 'object') {
|
||||||
options.x = workspace.x;
|
options.x = workspace.x;
|
||||||
options.y = workspace.y;
|
options.y = workspace.y;
|
||||||
options.width = workspace.width;
|
options.width = workspace.width;
|
||||||
options.height = workspace.height;
|
options.height = workspace.height;
|
||||||
options.isMaximized = workspace.isMaximized;
|
options.isMaximized = workspace.isMaximized;
|
||||||
options.isFullScreen = workspace.isFullScreen;
|
options.isFullScreen = workspace.isFullScreen;
|
||||||
|
file = workspace.file;
|
||||||
|
} else {
|
||||||
|
file = workspace;
|
||||||
|
}
|
||||||
const [uri, electronWindow] = await Promise.all([this.createWindowUri(), this.createWindow(options)]);
|
const [uri, electronWindow] = await Promise.all([this.createWindowUri(), this.createWindow(options)]);
|
||||||
electronWindow.loadURL(uri.withFragment(encodeURI(workspace.file)).toString(true));
|
electronWindow.loadURL(uri.withFragment(encodeURI(file)).toString(true));
|
||||||
return electronWindow;
|
return electronWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +162,14 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async onSecondInstance(event: ElectronEvent, argv: string[], cwd: string): Promise<void> {
|
||||||
|
if (!os.isOSX && await this.launchFromArgs({ cwd, argv, secondInstance: true })) {
|
||||||
|
// Application has received a file in its arguments
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.onSecondInstance(event, argv, cwd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use this rather than creating `BrowserWindow` instances from scratch, since some security parameters need to be set, this method will do it.
|
* Use this rather than creating `BrowserWindow` instances from scratch, since some security parameters need to be set, this method will do it.
|
||||||
*
|
*
|
||||||
|
@ -60,6 +60,12 @@
|
|||||||
"directories": {
|
"directories": {
|
||||||
"buildResources": "resources"
|
"buildResources": "resources"
|
||||||
},
|
},
|
||||||
|
"fileAssociations": [
|
||||||
|
{
|
||||||
|
"ext": "ino",
|
||||||
|
"role": "Editor"
|
||||||
|
}
|
||||||
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"src-gen",
|
"src-gen",
|
||||||
"lib",
|
"lib",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user