使用的vscode版本 1.30.0
总纲
—- 主进程 —-
- src/main.js
- vs/code/electron-main/main.ts
- vs/code/electron-main/app.ts
- vs/code/electron-main/window.ts 启动渲染进程的关键
—- 渲染进程 —-
- vs/code/electron-browser/workbench/workbench.html 渲染进程的html
- vs/workbench/electron-browser/main.ts
- vs/workbench/electron-browser/shell.ts
- vs/workbench/electron-browser/workbench.ts 界面渲染逻辑的核心,重点关注的
- vs/workbench/browser/parts/titlebar/titlebarPart
src/main.js
electron-main/main.ts
做了那几件事情?
electron-main/app.ts
electron-main/window.ts
创建渲染进程的关键
CodeWindow
这个类
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage } from 'electron';
export class CodeWindow extends Disposable implements ICodeWindow {
private createBrowserWindow(config: IWindowCreationOptions): void {
this._win = new BrowserWindow(options);
}
load(config: IWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void {
this._win.loadURL(this.getUrl(configuration));
}
private doGetUrl(config: object): string {
// 通过url参数把配置传入workbench.html
return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;
}
}
workbench.html(渲染进程)
<!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src 'self' https: data: vscode-remote:; media-src 'none'; child-src 'self'; object-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self' https:; font-src 'self' https:;">
</head>
<body class="monaco-shell vs-dark" aria-label="">
</body>
<!-- Startup via workbench.js -->
<script src="workbench.js"></script>
</html>
workbench.js(渲染进程)
先加载了非常多前置的依赖,然后运行了主进程
// Load workbench main
// 要先加载三个文件
bootstrapWindow.load([
'vs/workbench/workbench.main',
'vs/nls!vs/workbench/workbench.main',
'vs/css!vs/workbench/workbench.main'
],
function (workbench, configuration) {
perf.mark('didLoadWorkbenchMain');
return process['lazyEnv'].then(function () {
perf.mark('main/startup');
// @ts-ignore
// 即运行下面的主进程
return require('vs/workbench/electron-browser/main').startup(configuration);
});
}, {
workbench.main
// Base
import 'vs/base/common/strings';
import 'vs/base/common/errors';
// Configuration
import 'vs/workbench/services/configuration/common/configurationExtensionPoint';
// Editor
import 'vs/editor/editor.all';
// Platform
import 'vs/platform/widget/browser/contextScopedHistoryWidget';
import 'vs/platform/label/electron-browser/label.contribution';
main (vs/workbench/electron-browser/main.ts)
openWorkbench -> WorkbenchShell.open
import * as browser from 'vs/base/browser/browser';
export function startup(configuration: IWindowConfiguration): Promise<void> {
// Massage configuration file URIs
revive(configuration);
// Setup perf
perf.importEntries(configuration.perfEntries);
// Configure emitter leak warning threshold
setGlobalLeakWarningThreshold(-1);
// Browser config
browser.setZoomFactor(webFrame.getZoomFactor()); // Ensure others can listen to zoom level changes
browser.setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */); // Can be trusted because we are not setting it ourselves (https://github.com/Microsoft/vscode/issues/26151)
browser.setFullscreen(!!configuration.fullscreen);
browser.setAccessibilitySupport(configuration.accessibilitySupport ? platform.AccessibilitySupport.Enabled : platform.AccessibilitySupport.Disabled);
// Keyboard support
KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged();
// Setup Intl for comparers
comparer.setFileNameComparer(new IdleValue(() => {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return {
collator: collator,
collatorIsNumeric: collator.resolvedOptions().numeric
};
}));
// Open workbench
return openWorkbench(configuration);
}
shell (vs/workbench/electron-browser/shell.ts)
open -> renderContents -> createWorkbench -> workbench.startup()
export class WorkbenchShell extends Disposable {
open(){
// Listen on unhandled rejection events
window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => {
// See https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
errors.onUnexpectedError(event.reason);
// Prevent the printing of this event to the console
event.preventDefault();
});
// Listen on unexpected errors
errors.setUnexpectedErrorHandler((error: any) => {
this.onUnexpectedError(error);
});
// Shell Class for CSS Scoping
addClass(this.container, 'monaco-shell');
// Create Contents
this.renderContents();
// Layout
this.layout();
// Listeners
this.registerListeners();
// Set lifecycle phase to `Ready`
this.lifecycleService.phase = LifecyclePhase.Ready;
}
private renderContents(): void {
// ARIA
aria.setARIAContainer(document.body);
// Instantiation service with services
const [instantiationService, serviceCollection] = this.initServiceCollection(this.container);
// Warm up font cache information before building up too many dom elements
restoreFontInfo(this.storageService);
readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), browser.getZoomLevel()));
this._register(this.storageService.onWillSaveState(() => {
saveFontInfo(this.storageService); // Keep font info for next startup around
}));
// Workbench
this.workbench = this.createWorkbench(instantiationService, serviceCollection, this.container);
// Window
this.workbench.getInstantiationService().createInstance(ElectronWindow);
// Handle case where workbench is not starting up properly
const timeoutHandle = setTimeout(() => {
this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.');
}, 10000);
this.lifecycleService.when(LifecyclePhase.Restored).then(() => {
clearTimeout(timeoutHandle);
});
}
}
workbench (vs/workbench/electron-browser/workbench.ts)
这个起什么作用?
- 初始化各种服务 dom容器,全局action,初始services,上下文按键,监听工作区变化和逻辑
- 渲染工作区
- 恢复之前打开的内容
export class Workbench extends Disposable implements IPartService {
startup(): Thenable<IWorkbenchStartedInfo> {
this.workbenchStarted = true;
// Create Workbench Container
this.createWorkbench();
// Install some global actions
this.createGlobalActions();
// Services
this.initServices();
// Context Keys
this.handleContextKeys();
// Register Listeners
this.registerListeners();
// Settings
this.initSettings();
// Create Workbench and Parts
this.renderWorkbench();
// Workbench Layout
this.createWorkbenchLayout();
// Driver
if (this.environmentService.driverHandle) {
registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService).then(disposable => this._register(disposable));
}
// Restore Parts
return this.restoreParts();
}
private renderWorkbench(): void {
// Apply sidebar state as CSS class
if (this.sideBarHidden) {
DOM.addClass(this.workbench, 'nosidebar');
}
if (this.panelHidden) {
DOM.addClass(this.workbench, 'nopanel');
}
if (this.statusBarHidden) {
DOM.addClass(this.workbench, 'nostatusbar');
}
// Apply font aliasing
this.setFontAliasing(this.fontAliasing);
// Apply fullscreen state
if (browser.isFullscreen()) {
DOM.addClass(this.workbench, 'fullscreen');
}
// Create Parts
this.createTitlebarPart();
this.createActivityBarPart();
this.createSidebarPart();
this.createEditorPart();
this.createPanelPart();
this.createStatusbarPart();
// Notification Handlers
this.createNotificationsHandlers();
// Menubar visibility changes
if ((isWindows || isLinux) && this.useCustomTitleBarStyle()) {
this.titlebarPart.onMenubarVisibilityChange()(e => this.onMenubarToggled(e));
}
// Add Workbench to DOM
this.container.appendChild(this.workbench);
}
private createTitlebarPart(): void {
const titlebarContainer = this.createPart(Identifiers.TITLEBAR_PART, ['part', 'titlebar'], 'contentinfo');
this.titlebarPart.create(titlebarContainer);
}
}