mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-09 10:28:32 +00:00
Replaced the splash screen with a preload.
Added a bare minimum example. Closes #193 Closes #324 Closes #327 Closes #717 Closes #851 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
@@ -6,10 +6,6 @@ import {
|
||||
ElectronMainWindowServiceExt,
|
||||
electronMainWindowServiceExtPath,
|
||||
} from '../../../electron-common/electron-main-window-service-ext';
|
||||
import {
|
||||
SplashService,
|
||||
splashServicePath,
|
||||
} from '../../../electron-common/splash-service';
|
||||
import { ElectronWindowService } from './electron-window-service';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
@@ -24,9 +20,4 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
bind(SplashService)
|
||||
.toDynamicValue(({ container }) =>
|
||||
ElectronIpcConnectionProvider.createProxy(container, splashServicePath)
|
||||
)
|
||||
.inSingletonScope();
|
||||
});
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
import * as remote from '@theia/core/electron-shared/@electron/remote';
|
||||
import {
|
||||
ConnectionStatus,
|
||||
ConnectionStatusService,
|
||||
} from '@theia/core/lib/browser/connection-status-service';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
import { ElectronWindowService as TheiaElectronWindowService } from '@theia/core/lib/electron-browser/window/electron-window-service';
|
||||
import {
|
||||
inject,
|
||||
injectable,
|
||||
postConstruct,
|
||||
} from '@theia/core/shared/inversify';
|
||||
import * as remote from '@theia/core/electron-shared/@electron/remote';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import {
|
||||
ConnectionStatus,
|
||||
ConnectionStatusService,
|
||||
} from '@theia/core/lib/browser/connection-status-service';
|
||||
import { ElectronWindowService as TheiaElectronWindowService } from '@theia/core/lib/electron-browser/window/electron-window-service';
|
||||
import { SplashService } from '../../../electron-common/splash-service';
|
||||
import { nls } from '@theia/core/lib/common';
|
||||
import { WindowServiceExt } from '../../../browser/theia/core/window-service-ext';
|
||||
import { ElectronMainWindowServiceExt } from '../../../electron-common/electron-main-window-service-ext';
|
||||
|
||||
@@ -23,20 +21,14 @@ export class ElectronWindowService
|
||||
@inject(ConnectionStatusService)
|
||||
private readonly connectionStatusService: ConnectionStatusService;
|
||||
|
||||
@inject(SplashService)
|
||||
private readonly splashService: SplashService;
|
||||
|
||||
@inject(FrontendApplicationStateService)
|
||||
private readonly appStateService: FrontendApplicationStateService;
|
||||
|
||||
@inject(ElectronMainWindowServiceExt)
|
||||
private readonly mainWindowServiceExt: ElectronMainWindowServiceExt;
|
||||
|
||||
@postConstruct()
|
||||
protected override init(): void {
|
||||
this.appStateService
|
||||
.reachedAnyState('initialized_layout')
|
||||
.then(() => this.splashService.requestClose());
|
||||
// NOOP
|
||||
// Does not listen on Theia's `window.zoomLevel` changes.
|
||||
// TODO: IDE2 must switch to the Theia preferences and drop the custom one.
|
||||
}
|
||||
|
||||
protected shouldUnload(): boolean {
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export const splashServicePath = '/services/splash-service';
|
||||
export const SplashService = Symbol('SplashService');
|
||||
export interface SplashService {
|
||||
requestClose(): Promise<void>;
|
||||
}
|
||||
@@ -16,13 +16,8 @@ import {
|
||||
ElectronMainWindowServiceExt,
|
||||
electronMainWindowServiceExtPath,
|
||||
} from '../electron-common/electron-main-window-service-ext';
|
||||
import {
|
||||
SplashService,
|
||||
splashServicePath,
|
||||
} from '../electron-common/splash-service';
|
||||
import { ElectronMainWindowServiceExtImpl } from './electron-main-window-service-ext-impl';
|
||||
import { IDEUpdaterImpl } from './ide-updater/ide-updater-impl';
|
||||
import { SplashServiceImpl } from './splash/splash-service-impl';
|
||||
import { ElectronMainApplication } from './theia/electron-main-application';
|
||||
import { ElectronMainWindowServiceImpl } from './theia/electron-main-window-service';
|
||||
import { TheiaElectronWindow } from './theia/theia-electron-window';
|
||||
@@ -34,17 +29,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ElectronMainWindowServiceImpl).toSelf().inSingletonScope();
|
||||
rebind(ElectronMainWindowService).toService(ElectronMainWindowServiceImpl);
|
||||
|
||||
bind(SplashServiceImpl).toSelf().inSingletonScope();
|
||||
bind(SplashService).toService(SplashServiceImpl);
|
||||
bind(ElectronConnectionHandler)
|
||||
.toDynamicValue(
|
||||
(context) =>
|
||||
new JsonRpcConnectionHandler(splashServicePath, () =>
|
||||
context.container.get(SplashService)
|
||||
)
|
||||
)
|
||||
.inSingletonScope();
|
||||
|
||||
// IDE updater bindings
|
||||
bind(IDEUpdaterImpl).toSelf().inSingletonScope();
|
||||
bind(IDEUpdater).toService(IDEUpdaterImpl);
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Troy McKinnon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
// Copied from https://raw.githubusercontent.com/trodi/electron-splashscreen/2f5052a133be021cbf9a438d0ef4719cd1796b75/index.ts
|
||||
|
||||
/**
|
||||
* Module handles configurable splashscreen to show while app is loading.
|
||||
*/
|
||||
|
||||
import { Event } from '@theia/core/lib/common/event';
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
/**
|
||||
* When splashscreen was shown.
|
||||
* @ignore
|
||||
*/
|
||||
let splashScreenTimestamp = 0;
|
||||
/**
|
||||
* Splashscreen is loaded and ready to show.
|
||||
* @ignore
|
||||
*/
|
||||
let splashScreenReady = false;
|
||||
/**
|
||||
* Main window has been loading for a min amount of time.
|
||||
* @ignore
|
||||
*/
|
||||
let slowStartup = false;
|
||||
/**
|
||||
* True when expected work is complete and we've closed splashscreen, else user prematurely closed splashscreen.
|
||||
* @ignore
|
||||
*/
|
||||
let done = false;
|
||||
/**
|
||||
* Show splashscreen if criteria are met.
|
||||
* @ignore
|
||||
*/
|
||||
const showSplash = () => {
|
||||
if (splashScreen && splashScreenReady && slowStartup) {
|
||||
splashScreen.show();
|
||||
splashScreenTimestamp = Date.now();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Close splashscreen / show main screen. Ensure screen is visible for a min amount of time.
|
||||
* @ignore
|
||||
*/
|
||||
const closeSplashScreen = (main: Electron.BrowserWindow, min: number): void => {
|
||||
if (splashScreen) {
|
||||
const timeout = min - (Date.now() - splashScreenTimestamp);
|
||||
setTimeout(() => {
|
||||
done = true;
|
||||
if (splashScreen) {
|
||||
splashScreen.isDestroyed() || splashScreen.close(); // Avoid `Error: Object has been destroyed` (#19)
|
||||
splashScreen = null;
|
||||
}
|
||||
if (!main.isDestroyed()) {
|
||||
main.show();
|
||||
}
|
||||
}, timeout);
|
||||
}
|
||||
};
|
||||
/** `electron-splashscreen` config object. */
|
||||
export interface Config {
|
||||
/** Options for the window that is loading and having a splashscreen tied to. */
|
||||
windowOpts: Electron.BrowserWindowConstructorOptions;
|
||||
/**
|
||||
* URL to the splashscreen template. This is the path to an `HTML` or `SVG` file.
|
||||
* If you want to simply show a `PNG`, wrap it in an `HTML` file.
|
||||
*/
|
||||
templateUrl: string;
|
||||
|
||||
/**
|
||||
* Full set of browser window options for the splashscreen. We override key attributes to
|
||||
* make it look & feel like a splashscreen; the rest is up to you!
|
||||
*/
|
||||
splashScreenOpts: Electron.BrowserWindowConstructorOptions;
|
||||
/** Number of ms the window will load before splashscreen appears (default: 500ms). */
|
||||
delay?: number;
|
||||
/** Minimum ms the splashscreen will be visible (default: 500ms). */
|
||||
minVisible?: number;
|
||||
/** Close window that is loading if splashscreen is closed by user (default: true). */
|
||||
closeWindow?: boolean;
|
||||
}
|
||||
/**
|
||||
* The actual splashscreen browser window.
|
||||
* @ignore
|
||||
*/
|
||||
let splashScreen: Electron.BrowserWindow | null;
|
||||
/**
|
||||
* Initializes a splashscreen that will show/hide smartly (and handle show/hiding of main window).
|
||||
* @param config - Configures splashscreen
|
||||
* @returns {BrowserWindow} the main browser window ready for loading
|
||||
*/
|
||||
export const initSplashScreen = async (
|
||||
config: Config,
|
||||
windowFactory: (
|
||||
options: Electron.BrowserViewConstructorOptions
|
||||
) => Promise<BrowserWindow>,
|
||||
onCloseRequested?: Event<void>
|
||||
): Promise<BrowserWindow> => {
|
||||
const xConfig: Required<Config> = {
|
||||
windowOpts: config.windowOpts,
|
||||
templateUrl: config.templateUrl,
|
||||
splashScreenOpts: config.splashScreenOpts,
|
||||
delay: config.delay ?? 500,
|
||||
minVisible: config.minVisible ?? 500,
|
||||
closeWindow: config.closeWindow ?? true,
|
||||
};
|
||||
xConfig.splashScreenOpts.center = true;
|
||||
xConfig.splashScreenOpts.frame = false;
|
||||
xConfig.windowOpts.show = false;
|
||||
const window = await windowFactory(xConfig.windowOpts);
|
||||
splashScreen = new BrowserWindow(xConfig.splashScreenOpts);
|
||||
splashScreen.loadURL(`file://${xConfig.templateUrl}`);
|
||||
xConfig.closeWindow &&
|
||||
splashScreen.on('close', () => {
|
||||
done || window.close();
|
||||
});
|
||||
// Splashscreen is fully loaded and ready to view.
|
||||
splashScreen.webContents.on('did-finish-load', () => {
|
||||
splashScreenReady = true;
|
||||
showSplash();
|
||||
});
|
||||
// Startup is taking enough time to show a splashscreen.
|
||||
setTimeout(() => {
|
||||
slowStartup = true;
|
||||
showSplash();
|
||||
}, xConfig.delay);
|
||||
if (onCloseRequested) {
|
||||
onCloseRequested(() => closeSplashScreen(window, xConfig.minVisible));
|
||||
} else {
|
||||
window.webContents.on('did-finish-load', () => {
|
||||
closeSplashScreen(window, xConfig.minVisible);
|
||||
});
|
||||
}
|
||||
window.on('closed', () => closeSplashScreen(window, 0)); // XXX: close splash when main window is closed
|
||||
return window;
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { SplashService } from '../../electron-common/splash-service';
|
||||
|
||||
@injectable()
|
||||
export class SplashServiceImpl implements SplashService {
|
||||
protected requested = false;
|
||||
protected readonly onCloseRequestedEmitter = new Emitter<void>();
|
||||
|
||||
get onCloseRequested(): Event<void> {
|
||||
return this.onCloseRequestedEmitter.event;
|
||||
}
|
||||
|
||||
async requestClose(): Promise<void> {
|
||||
if (!this.requested) {
|
||||
this.requested = true;
|
||||
this.onCloseRequestedEmitter.fire();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<style>
|
||||
.container {
|
||||
width: auto;
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 95%;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<p><img src="splash.png"></p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB |
@@ -1,18 +1,15 @@
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { injectable } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
BrowserWindowConstructorOptions,
|
||||
contentTracing,
|
||||
ipcMain,
|
||||
screen,
|
||||
Event as ElectronEvent,
|
||||
} from '@theia/core/electron-shared/electron';
|
||||
import { fork } from 'child_process';
|
||||
import { AddressInfo } from 'net';
|
||||
import { join, dirname } from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import { initSplashScreen } from '../splash/splash-screen';
|
||||
import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { ElectronSecurityToken } from '@theia/core/lib/electron-common/electron-token';
|
||||
import { FrontendApplicationConfig } from '@theia/application-package/lib/application-props';
|
||||
@@ -20,7 +17,6 @@ import {
|
||||
ElectronMainApplication as TheiaElectronMainApplication,
|
||||
ElectronMainExecutionParams,
|
||||
} from '@theia/core/lib/electron-main/electron-main-application';
|
||||
import { SplashServiceImpl } from '../splash/splash-service-impl';
|
||||
import { URI } from '@theia/core/shared/vscode-uri';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import * as os from '@theia/core/lib/common/os';
|
||||
@@ -42,14 +38,6 @@ interface WorkspaceOptions {
|
||||
|
||||
const WORKSPACES = 'workspaces';
|
||||
|
||||
/**
|
||||
* Purely a dev thing. If you start the app with the `--nosplash` argument,
|
||||
* then you won't have the splash screen (which is always on top :confused:) and can debug the app at startup.
|
||||
* Note: if you start the app from VS Code with the `App (Electron)` config, the splash screen will be disabled.
|
||||
*/
|
||||
const APP_STARTED_WITH_NOSPLASH =
|
||||
typeof process !== 'undefined' && process.argv.indexOf('--nosplash') !== -1;
|
||||
|
||||
/**
|
||||
* If the app is started with `--open-devtools` argument, the `Dev Tools` will be opened.
|
||||
*/
|
||||
@@ -70,9 +58,6 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
private _firstWindowId: number | undefined;
|
||||
private openFilePromise = new Deferred();
|
||||
|
||||
@inject(SplashServiceImpl)
|
||||
private readonly splashService: SplashServiceImpl;
|
||||
|
||||
override async start(config: FrontendApplicationConfig): Promise<void> {
|
||||
// Explicitly set the app name to have better menu items on macOS. ("About", "Hide", and "Quit")
|
||||
// See: https://github.com/electron-userland/electron-builder/issues/2468
|
||||
@@ -289,69 +274,10 @@ export class ElectronMainApplication extends TheiaElectronMainApplication {
|
||||
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.
|
||||
*
|
||||
* @param options
|
||||
*/
|
||||
override async createWindow(
|
||||
asyncOptions: MaybePromise<TheiaBrowserWindowOptions> = this.getDefaultTheiaWindowOptions()
|
||||
): Promise<BrowserWindow> {
|
||||
let options = await asyncOptions;
|
||||
options = this.avoidOverlap(options);
|
||||
let electronWindow: BrowserWindow | undefined;
|
||||
if (this.windows.size || APP_STARTED_WITH_NOSPLASH) {
|
||||
electronWindow = await this.doCreateWindow(options);
|
||||
} else {
|
||||
const { bounds } = screen.getDisplayNearestPoint(
|
||||
screen.getCursorScreenPoint()
|
||||
);
|
||||
const splashHeight = 450;
|
||||
const splashWidth = 600;
|
||||
const splashY = Math.floor(bounds.y + (bounds.height - splashHeight) / 2);
|
||||
const splashX = Math.floor(bounds.x + (bounds.width - splashWidth) / 2);
|
||||
const splashScreenOpts: BrowserWindowConstructorOptions = {
|
||||
height: splashHeight,
|
||||
width: splashWidth,
|
||||
x: splashX,
|
||||
y: splashY,
|
||||
transparent: true,
|
||||
alwaysOnTop: true,
|
||||
focusable: false,
|
||||
minimizable: false,
|
||||
maximizable: false,
|
||||
hasShadow: false,
|
||||
resizable: false,
|
||||
};
|
||||
electronWindow = await initSplashScreen(
|
||||
{
|
||||
windowOpts: options,
|
||||
templateUrl: join(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'src',
|
||||
'electron-main',
|
||||
'splash',
|
||||
'static',
|
||||
'splash.html'
|
||||
),
|
||||
delay: 0,
|
||||
minVisible: 2000,
|
||||
splashScreenOpts,
|
||||
},
|
||||
(windowOptions) => this.doCreateWindow(windowOptions),
|
||||
this.splashService.onCloseRequested
|
||||
);
|
||||
}
|
||||
return electronWindow;
|
||||
}
|
||||
|
||||
private async doCreateWindow(
|
||||
options: TheiaBrowserWindowOptions
|
||||
): Promise<BrowserWindow> {
|
||||
const electronWindow = await super.createWindow(options);
|
||||
const electronWindow = await super.createWindow(asyncOptions);
|
||||
if (APP_STARTED_WITH_DEV_TOOLS) {
|
||||
electronWindow.webContents.openDevTools();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user