Update to VS Code 1.52.1
This commit is contained in:
@@ -3,13 +3,13 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { app, ipcMain as ipc, systemPreferences, contentTracing, protocol, IpcMainEvent, BrowserWindow, dialog, session } from 'electron';
|
||||
import { IProcessEnvironment, isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { app, ipcMain, systemPreferences, contentTracing, protocol, BrowserWindow, dialog, session } from 'electron';
|
||||
import { IProcessEnvironment, isWindows, isMacintosh, isLinux } from 'vs/base/common/platform';
|
||||
import { WindowsMainService } from 'vs/platform/windows/electron-main/windowsMainService';
|
||||
import { IWindowOpenable } from 'vs/platform/windows/common/windows';
|
||||
import { OpenContext } from 'vs/platform/windows/node/window';
|
||||
import { ILifecycleMainService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { getShellEnvironment } from 'vs/code/node/shellEnv';
|
||||
import { resolveShellEnv } from 'vs/code/node/shellEnv';
|
||||
import { IUpdateService } from 'vs/platform/update/common/update';
|
||||
import { UpdateChannel } from 'vs/platform/update/electron-main/updateIpc';
|
||||
import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/electron-main/ipc.electron-main';
|
||||
@@ -24,7 +24,7 @@ import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IStateService } from 'vs/platform/state/node/state';
|
||||
import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/environmentMainService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { IOpenURLOptions, IURLService } from 'vs/platform/url/common/url';
|
||||
import { URLHandlerChannelClient, URLHandlerRouter } from 'vs/platform/url/common/urlIpc';
|
||||
import { ITelemetryService, machineIdKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
@@ -35,6 +35,7 @@ import { getDelayedChannel, StaticRouter, createChannelReceiver, createChannelSe
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { ProxyAuthHandler } from 'vs/code/electron-main/auth';
|
||||
import { ProxyAuthHandler2 } from 'vs/code/electron-main/auth2';
|
||||
import { FileProtocolHandler } from 'vs/code/electron-main/protocol';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -52,7 +53,7 @@ import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver';
|
||||
import { IMenubarMainService, MenubarMainService } from 'vs/platform/menubar/electron-main/menubarMainService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu';
|
||||
import { sep, posix } from 'vs/base/common/path';
|
||||
import { sep, posix, join, isAbsolute } from 'vs/base/common/path';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
@@ -72,7 +73,6 @@ import { INativeHostMainService, NativeHostMainService } from 'vs/platform/nativ
|
||||
import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService';
|
||||
import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels';
|
||||
import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService';
|
||||
import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService';
|
||||
@@ -82,6 +82,14 @@ import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { EncryptionMainService, IEncryptionMainService } from 'vs/platform/encryption/electron-main/encryptionMainService';
|
||||
import { ActiveWindowManager } from 'vs/platform/windows/common/windowTracker';
|
||||
import { IKeyboardLayoutMainService, KeyboardLayoutMainService } from 'vs/platform/keyboardLayout/electron-main/keyboardLayoutMainService';
|
||||
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
|
||||
import { DisplayMainService, IDisplayMainService } from 'vs/platform/display/electron-main/displayMainService';
|
||||
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
|
||||
import { isEqualOrParent } from 'vs/base/common/extpath';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IExtensionUrlTrustService } from 'vs/platform/extensionManagement/common/extensionUrlTrust';
|
||||
import { ExtensionUrlTrustService } from 'vs/platform/extensionManagement/node/extensionUrlTrustService';
|
||||
|
||||
export class CodeApplication extends Disposable {
|
||||
private windowsMainService: IWindowsMainService | undefined;
|
||||
@@ -96,7 +104,8 @@ export class CodeApplication extends Disposable {
|
||||
@IEnvironmentMainService private readonly environmentService: IEnvironmentMainService,
|
||||
@ILifecycleMainService private readonly lifecycleMainService: ILifecycleMainService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IStateService private readonly stateService: IStateService
|
||||
@IStateService private readonly stateService: IStateService,
|
||||
@IFileService private readonly fileService: IFileService
|
||||
) {
|
||||
super();
|
||||
|
||||
@@ -118,9 +127,7 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
// Accessibility change event
|
||||
app.on('accessibility-support-changed', (event, accessibilitySupportEnabled) => {
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.sendToAll('vscode:accessibilitySupportChanged', accessibilitySupportEnabled);
|
||||
}
|
||||
this.windowsMainService?.sendToAll('vscode:accessibilitySupportChanged', accessibilitySupportEnabled);
|
||||
});
|
||||
|
||||
// macOS dock activate
|
||||
@@ -128,8 +135,8 @@ export class CodeApplication extends Disposable {
|
||||
this.logService.trace('app#activate');
|
||||
|
||||
// Mac only event: open new window when we get activated
|
||||
if (!hasVisibleWindows && this.windowsMainService) {
|
||||
this.windowsMainService.openEmptyWindow({ context: OpenContext.DOCK });
|
||||
if (!hasVisibleWindows) {
|
||||
this.windowsMainService?.openEmptyWindow({ context: OpenContext.DOCK });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -214,9 +221,7 @@ export class CodeApplication extends Disposable {
|
||||
contents.on('new-window', (event, url) => {
|
||||
event.preventDefault(); // prevent code that wants to open links
|
||||
|
||||
if (this.nativeHostMainService) {
|
||||
this.nativeHostMainService.openExternal(undefined, url);
|
||||
}
|
||||
this.nativeHostMainService?.openExternal(undefined, url);
|
||||
});
|
||||
|
||||
session.defaultSession.setPermissionRequestHandler((webContents, permission /* 'media' | 'geolocation' | 'notifications' | 'midiSysex' | 'pointerLock' | 'fullscreen' | 'openExternal' */, callback) => {
|
||||
@@ -247,62 +252,119 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
// Handle paths delayed in case more are coming!
|
||||
runningTimeout = setTimeout(() => {
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.open({
|
||||
context: OpenContext.DOCK /* can also be opening from finder while app is running */,
|
||||
cli: this.environmentService.args,
|
||||
urisToOpen: macOpenFileURIs,
|
||||
gotoLineMode: false,
|
||||
preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */
|
||||
});
|
||||
this.windowsMainService?.open({
|
||||
context: OpenContext.DOCK /* can also be opening from finder while app is running */,
|
||||
cli: this.environmentService.args,
|
||||
urisToOpen: macOpenFileURIs,
|
||||
gotoLineMode: false,
|
||||
preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */
|
||||
});
|
||||
|
||||
macOpenFileURIs = [];
|
||||
runningTimeout = null;
|
||||
}
|
||||
macOpenFileURIs = [];
|
||||
runningTimeout = null;
|
||||
}, 100);
|
||||
});
|
||||
|
||||
app.on('new-window-for-tab', () => {
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.openEmptyWindow({ context: OpenContext.DESKTOP }); //macOS native tab "+" button
|
||||
}
|
||||
this.windowsMainService?.openEmptyWindow({ context: OpenContext.DESKTOP }); //macOS native tab "+" button
|
||||
});
|
||||
|
||||
ipc.on('vscode:fetchShellEnv', async (event: IpcMainEvent) => {
|
||||
//#region Bootstrap IPC Handlers
|
||||
|
||||
ipcMain.on('vscode:fetchShellEnv', async event => {
|
||||
const webContents = event.sender;
|
||||
const window = this.windowsMainService?.getWindowByWebContents(event.sender);
|
||||
|
||||
try {
|
||||
const shellEnv = await getShellEnvironment(this.logService, this.environmentService);
|
||||
let replied = false;
|
||||
|
||||
if (!webContents.isDestroyed()) {
|
||||
webContents.send('vscode:acceptShellEnv', shellEnv);
|
||||
function acceptShellEnv(env: NodeJS.ProcessEnv): void {
|
||||
clearTimeout(shellEnvSlowWarningHandle);
|
||||
clearTimeout(shellEnvTimeoutErrorHandle);
|
||||
|
||||
if (!replied) {
|
||||
replied = true;
|
||||
|
||||
if (!webContents.isDestroyed()) {
|
||||
webContents.send('vscode:acceptShellEnv', env);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (!webContents.isDestroyed()) {
|
||||
webContents.send('vscode:acceptShellEnv', {});
|
||||
}
|
||||
|
||||
this.logService.error('Error fetching shell env', error);
|
||||
}
|
||||
|
||||
// Handle slow shell environment resolve calls:
|
||||
// - a warning after 3s but continue to resolve
|
||||
// - an error after 10s and stop trying to resolve
|
||||
const cts = new CancellationTokenSource();
|
||||
const shellEnvSlowWarningHandle = setTimeout(() => window?.sendWhenReady('vscode:showShellEnvSlowWarning', cts.token), 3000);
|
||||
const shellEnvTimeoutErrorHandle = setTimeout(function () {
|
||||
cts.dispose(true);
|
||||
window?.sendWhenReady('vscode:showShellEnvTimeoutError', CancellationToken.None);
|
||||
acceptShellEnv({});
|
||||
}, 10000);
|
||||
|
||||
// Prefer to use the args and env from the target window
|
||||
// when resolving the shell env. It is possible that
|
||||
// a first window was opened from the UI but a second
|
||||
// from the CLI and that has implications for wether to
|
||||
// resolve the shell environment or not.
|
||||
let args: NativeParsedArgs;
|
||||
let env: NodeJS.ProcessEnv;
|
||||
if (window?.config) {
|
||||
args = window.config;
|
||||
env = { ...process.env, ...window.config.userEnv };
|
||||
} else {
|
||||
args = this.environmentService.args;
|
||||
env = process.env;
|
||||
}
|
||||
|
||||
// Resolve shell env
|
||||
const shellEnv = await resolveShellEnv(this.logService, args, env);
|
||||
acceptShellEnv(shellEnv);
|
||||
});
|
||||
|
||||
ipc.on('vscode:toggleDevTools', (event: IpcMainEvent) => event.sender.toggleDevTools());
|
||||
ipc.on('vscode:openDevTools', (event: IpcMainEvent) => event.sender.openDevTools());
|
||||
ipcMain.handle('vscode:writeNlsFile', (event, path: unknown, data: unknown) => {
|
||||
const uri = this.validateNlsPath([path]);
|
||||
if (!uri || typeof data !== 'string') {
|
||||
return Promise.reject('Invalid operation (vscode:writeNlsFile)');
|
||||
}
|
||||
|
||||
ipc.on('vscode:reloadWindow', (event: IpcMainEvent) => event.sender.reload());
|
||||
return this.fileService.writeFile(uri, VSBuffer.fromString(data));
|
||||
});
|
||||
|
||||
// Some listeners after window opened
|
||||
(async () => {
|
||||
await this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen);
|
||||
ipcMain.handle('vscode:readNlsFile', async (event, ...paths: unknown[]) => {
|
||||
const uri = this.validateNlsPath(paths);
|
||||
if (!uri) {
|
||||
return Promise.reject('Invalid operation (vscode:readNlsFile)');
|
||||
}
|
||||
|
||||
// Keyboard layout changes (after window opened)
|
||||
const nativeKeymap = await import('native-keymap');
|
||||
nativeKeymap.onDidChangeKeyboardLayout(() => {
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged');
|
||||
return (await this.fileService.readFile(uri)).value.toString();
|
||||
});
|
||||
|
||||
ipcMain.on('vscode:toggleDevTools', event => event.sender.toggleDevTools());
|
||||
ipcMain.on('vscode:openDevTools', event => event.sender.openDevTools());
|
||||
|
||||
ipcMain.on('vscode:reloadWindow', event => event.sender.reload());
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
private validateNlsPath(pathSegments: unknown[]): URI | undefined {
|
||||
let path: string | undefined = undefined;
|
||||
|
||||
for (const pathSegment of pathSegments) {
|
||||
if (typeof pathSegment === 'string') {
|
||||
if (typeof path !== 'string') {
|
||||
path = pathSegment;
|
||||
} else {
|
||||
path = join(path, pathSegment);
|
||||
}
|
||||
});
|
||||
})();
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof path !== 'string' || !isAbsolute(path) || !isEqualOrParent(path, this.environmentService.cachedLanguagesPath, !isLinux)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return URI.file(path);
|
||||
}
|
||||
|
||||
private onUnexpectedError(err: Error): void {
|
||||
@@ -315,9 +377,7 @@ export class CodeApplication extends Disposable {
|
||||
};
|
||||
|
||||
// handle on client side
|
||||
if (this.windowsMainService) {
|
||||
this.windowsMainService.sendToFocused('vscode:reportError', JSON.stringify(friendlyError));
|
||||
}
|
||||
this.windowsMainService?.sendToFocused('vscode:reportError', JSON.stringify(friendlyError));
|
||||
}
|
||||
|
||||
this.logService.error(`[uncaught exception in main]: ${err}`);
|
||||
@@ -354,6 +414,9 @@ export class CodeApplication extends Disposable {
|
||||
this.logService.error(error);
|
||||
}
|
||||
|
||||
// Setup Protocol Handler
|
||||
const fileProtocolHandler = this._register(this.instantiationService.createInstance(FileProtocolHandler));
|
||||
|
||||
// Create Electron IPC Server
|
||||
const electronIpcServer = new ElectronIPCServer();
|
||||
|
||||
@@ -376,7 +439,7 @@ export class CodeApplication extends Disposable {
|
||||
});
|
||||
this.lifecycleMainService.when(LifecycleMainPhase.AfterWindowOpen).then(() => {
|
||||
this._register(new RunOnceScheduler(async () => {
|
||||
sharedProcess.spawn(await getShellEnvironment(this.logService, this.environmentService));
|
||||
sharedProcess.spawn(await resolveShellEnv(this.logService, this.environmentService.args, process.env));
|
||||
}, 3000)).schedule();
|
||||
});
|
||||
|
||||
@@ -391,15 +454,15 @@ export class CodeApplication extends Disposable {
|
||||
this._register(server);
|
||||
}
|
||||
|
||||
// Setup Auth Handler
|
||||
if (this.configurationService.getValue('window.enableExperimentalProxyLoginDialog') !== true) {
|
||||
// Setup Auth Handler (TODO@ben remove old auth handler eventually)
|
||||
if (this.configurationService.getValue('window.enableExperimentalProxyLoginDialog') === false) {
|
||||
this._register(new ProxyAuthHandler());
|
||||
} else {
|
||||
this._register(appInstantiationService.createInstance(ProxyAuthHandler2));
|
||||
}
|
||||
|
||||
// Open Windows
|
||||
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient));
|
||||
const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient, fileProtocolHandler));
|
||||
|
||||
// Post Open Windows Tasks
|
||||
appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor));
|
||||
@@ -453,10 +516,13 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
services.set(IIssueMainService, new SyncDescriptor(IssueMainService, [machineId, this.userEnv]));
|
||||
services.set(IEncryptionMainService, new SyncDescriptor(EncryptionMainService, [machineId]));
|
||||
services.set(IKeyboardLayoutMainService, new SyncDescriptor(KeyboardLayoutMainService));
|
||||
services.set(IDisplayMainService, new SyncDescriptor(DisplayMainService));
|
||||
services.set(INativeHostMainService, new SyncDescriptor(NativeHostMainService));
|
||||
services.set(IWebviewManagerService, new SyncDescriptor(WebviewMainService));
|
||||
services.set(IWorkspacesService, new SyncDescriptor(WorkspacesService));
|
||||
services.set(IMenubarMainService, new SyncDescriptor(MenubarMainService));
|
||||
services.set(IExtensionUrlTrustService, new SyncDescriptor(ExtensionUrlTrustService));
|
||||
|
||||
const storageMainService = new StorageMainService(this.logService, this.environmentService);
|
||||
services.set(IStorageMainService, storageMainService);
|
||||
@@ -474,7 +540,7 @@ export class CodeApplication extends Disposable {
|
||||
const channel = getDelayedChannel(sharedProcessReady.then(client => client.getChannel('telemetryAppender')));
|
||||
const appender = new TelemetryAppenderClient(channel);
|
||||
const commonProperties = resolveCommonProperties(product.commit, product.version, machineId, product.msftInternalDomains, this.environmentService.installSourcePath);
|
||||
const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot];
|
||||
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
|
||||
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, sendErrorTelemetry: true };
|
||||
|
||||
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
|
||||
@@ -502,14 +568,12 @@ export class CodeApplication extends Disposable {
|
||||
const path = await contentTracing.stopRecording(joinPath(this.environmentService.userHome, `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`).fsPath);
|
||||
|
||||
if (!timeout) {
|
||||
if (this.dialogMainService) {
|
||||
this.dialogMainService.showMessageBox({
|
||||
type: 'info',
|
||||
message: localize('trace.message', "Successfully created trace."),
|
||||
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
|
||||
buttons: [localize('trace.ok', "OK")]
|
||||
}, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
|
||||
}
|
||||
this.dialogMainService?.showMessageBox({
|
||||
type: 'info',
|
||||
message: localize('trace.message', "Successfully created trace."),
|
||||
detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path),
|
||||
buttons: [localize('trace.ok', "OK")]
|
||||
}, withNullAsUndefined(BrowserWindow.getFocusedWindow()));
|
||||
} else {
|
||||
this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`);
|
||||
}
|
||||
@@ -525,7 +589,7 @@ export class CodeApplication extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise<Client<string>>): ICodeWindow[] {
|
||||
private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise<Client<string>>, fileProtocolHandler: FileProtocolHandler): ICodeWindow[] {
|
||||
|
||||
// Register more Main IPC services
|
||||
const launchMainService = accessor.get(ILaunchMainService);
|
||||
@@ -545,6 +609,14 @@ export class CodeApplication extends Disposable {
|
||||
const encryptionChannel = createChannelReceiver(encryptionMainService);
|
||||
electronIpcServer.registerChannel('encryption', encryptionChannel);
|
||||
|
||||
const keyboardLayoutMainService = accessor.get(IKeyboardLayoutMainService);
|
||||
const keyboardLayoutChannel = createChannelReceiver(keyboardLayoutMainService);
|
||||
electronIpcServer.registerChannel('keyboardLayout', keyboardLayoutChannel);
|
||||
|
||||
const displayMainService = accessor.get(IDisplayMainService);
|
||||
const displayChannel = createChannelReceiver(displayMainService);
|
||||
electronIpcServer.registerChannel('display', displayChannel);
|
||||
|
||||
const nativeHostMainService = this.nativeHostMainService = accessor.get(INativeHostMainService);
|
||||
const nativeHostChannel = createChannelReceiver(this.nativeHostMainService);
|
||||
electronIpcServer.registerChannel('nativeHost', nativeHostChannel);
|
||||
@@ -566,6 +638,10 @@ export class CodeApplication extends Disposable {
|
||||
const urlChannel = createChannelReceiver(urlService);
|
||||
electronIpcServer.registerChannel('url', urlChannel);
|
||||
|
||||
const extensionUrlTrustService = accessor.get(IExtensionUrlTrustService);
|
||||
const extensionUrlTrustChannel = createChannelReceiver(extensionUrlTrustService);
|
||||
electronIpcServer.registerChannel('extensionUrlTrust', extensionUrlTrustChannel);
|
||||
|
||||
const webviewManagerService = accessor.get(IWebviewManagerService);
|
||||
const webviewChannel = createChannelReceiver(webviewManagerService);
|
||||
electronIpcServer.registerChannel('webview', webviewChannel);
|
||||
@@ -579,8 +655,10 @@ export class CodeApplication extends Disposable {
|
||||
electronIpcServer.registerChannel('logger', loggerChannel);
|
||||
sharedProcessClient.then(client => client.registerChannel('logger', loggerChannel));
|
||||
|
||||
// ExtensionHost Debug broadcast service
|
||||
const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService);
|
||||
fileProtocolHandler.injectWindowsMainService(windowsMainService);
|
||||
|
||||
// ExtensionHost Debug broadcast service
|
||||
electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ElectronExtensionHostDebugBroadcastChannel(windowsMainService));
|
||||
|
||||
// Signal phase: ready (services set)
|
||||
@@ -591,29 +669,32 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
// Check for initial URLs to handle from protocol link invocations
|
||||
const pendingWindowOpenablesFromProtocolLinks: IWindowOpenable[] = [];
|
||||
const pendingProtocolLinksToHandle = coalesce([
|
||||
|
||||
const pendingProtocolLinksToHandle = [
|
||||
// Windows/Linux: protocol handler invokes CLI with --open-url
|
||||
...this.environmentService.args['open-url'] ? this.environmentService.args._urls || [] : [],
|
||||
|
||||
// macOS: open-url events
|
||||
...((<any>global).getOpenUrls() || []) as string[]
|
||||
].map(pendingUrlToHandle => {
|
||||
].map(url => {
|
||||
try {
|
||||
return URI.parse(pendingUrlToHandle);
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
return { uri: URI.parse(url), url };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})).filter(pendingUriToHandle => {
|
||||
// if URI should be blocked, filter it out
|
||||
if (this.shouldBlockURI(pendingUriToHandle)) {
|
||||
}).filter((obj): obj is { uri: URI, url: string } => {
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// filter out any protocol link that wants to open as window so that
|
||||
// If URI should be blocked, filter it out
|
||||
if (this.shouldBlockURI(obj.uri)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filter out any protocol link that wants to open as window so that
|
||||
// we open the right set of windows on startup and not restore the
|
||||
// previous workspace too.
|
||||
const windowOpenable = this.getWindowOpenableFromProtocolLink(pendingUriToHandle);
|
||||
const windowOpenable = this.getWindowOpenableFromProtocolLink(obj.uri);
|
||||
if (windowOpenable) {
|
||||
pendingWindowOpenablesFromProtocolLinks.push(windowOpenable);
|
||||
|
||||
@@ -627,8 +708,9 @@ export class CodeApplication extends Disposable {
|
||||
const app = this;
|
||||
const environmentService = this.environmentService;
|
||||
urlService.registerHandler({
|
||||
async handleURL(uri: URI): Promise<boolean> {
|
||||
// if URI should be blocked, behave as if it's handled
|
||||
async handleURL(uri: URI, options?: IOpenURLOptions): Promise<boolean> {
|
||||
|
||||
// If URI should be blocked, behave as if it's handled
|
||||
if (app.shouldBlockURI(uri)) {
|
||||
return true;
|
||||
}
|
||||
@@ -658,7 +740,7 @@ export class CodeApplication extends Disposable {
|
||||
|
||||
await window.ready();
|
||||
|
||||
return urlService.open(uri);
|
||||
return urlService.open(uri, options);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -666,11 +748,11 @@ export class CodeApplication extends Disposable {
|
||||
});
|
||||
|
||||
// Create a URL handler which forwards to the last active window
|
||||
const activeWindowManager = new ActiveWindowManager({
|
||||
const activeWindowManager = this._register(new ActiveWindowManager({
|
||||
onDidOpenWindow: nativeHostMainService.onDidOpenWindow,
|
||||
onDidFocusWindow: nativeHostMainService.onDidFocusWindow,
|
||||
getActiveWindowId: () => nativeHostMainService.getActiveWindowId(-1)
|
||||
});
|
||||
}));
|
||||
const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id));
|
||||
const urlHandlerRouter = new URLHandlerRouter(activeWindowRouter);
|
||||
const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', urlHandlerRouter);
|
||||
@@ -682,7 +764,7 @@ export class CodeApplication extends Disposable {
|
||||
// Open our first window
|
||||
const args = this.environmentService.args;
|
||||
const macOpenFiles: string[] = (<any>global).macOpenFiles;
|
||||
const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP;
|
||||
const context = isLaunchedFromCli(process.env) ? OpenContext.CLI : OpenContext.DESKTOP;
|
||||
const hasCliArgs = args._.length;
|
||||
const hasFolderURIs = !!args['folder-uri'];
|
||||
const hasFileURIs = !!args['file-uri'];
|
||||
@@ -828,12 +910,14 @@ export class CodeApplication extends Disposable {
|
||||
updateService.initialize();
|
||||
}
|
||||
|
||||
// Start to fetch shell environment (if needed) after window has opened
|
||||
resolveShellEnv(this.logService, this.environmentService.args, process.env);
|
||||
|
||||
// If enable-crash-reporter argv is undefined then this is a fresh start,
|
||||
// based on telemetry.enableCrashreporter settings, generate a UUID which
|
||||
// will be used as crash reporter id and also update the json file.
|
||||
try {
|
||||
const fileService = accessor.get(IFileService);
|
||||
const argvContent = await fileService.readFile(this.environmentService.argvResource);
|
||||
const argvContent = await this.fileService.readFile(this.environmentService.argvResource);
|
||||
const argvString = argvContent.value.toString();
|
||||
const argvJSON = JSON.parse(stripComments(argvString));
|
||||
if (argvJSON['enable-crash-reporter'] === undefined) {
|
||||
@@ -850,14 +934,11 @@ export class CodeApplication extends Disposable {
|
||||
'}'
|
||||
];
|
||||
const newArgvString = argvString.substring(0, argvString.length - 2).concat(',\n', additionalArgvContent.join('\n'));
|
||||
await fileService.writeFile(this.environmentService.argvResource, VSBuffer.fromString(newArgvString));
|
||||
await this.fileService.writeFile(this.environmentService.argvResource, VSBuffer.fromString(newArgvString));
|
||||
}
|
||||
} catch (error) {
|
||||
this.logService.error(error);
|
||||
}
|
||||
|
||||
// Start to fetch shell environment after window has opened
|
||||
getShellEnvironment(this.logService, this.environmentService);
|
||||
}
|
||||
|
||||
private handleRemoteAuthorities(): void {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeH
|
||||
import { IEncryptionMainService } from 'vs/platform/encryption/electron-main/encryptionMainService';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
interface ElectronAuthenticationResponseDetails extends AuthenticationResponseDetails {
|
||||
firstAuthAttempt?: boolean; // https://github.com/electron/electron/blob/84a42a050e7d45225e69df5bd2d2bf9f1037ea41/shell/browser/login_handler.cc#L70
|
||||
@@ -192,7 +193,7 @@ export class ProxyAuthHandler2 extends Disposable {
|
||||
password: this.sessionCredentials?.password ?? storedPassword, // prefer to show already used password (if any) over stored
|
||||
replyChannel: `vscode:proxyAuthResponse:${generateUuid()}`
|
||||
};
|
||||
window.sendWhenReady('vscode:openProxyAuthenticationDialog', payload);
|
||||
window.sendWhenReady('vscode:openProxyAuthenticationDialog', CancellationToken.None, payload);
|
||||
this.state = ProxyAuthState.LoginDialogShown;
|
||||
|
||||
// Handle reply
|
||||
|
||||
@@ -200,7 +200,7 @@ class CodeMain {
|
||||
VSCODE_IPC_HOOK: environmentService.mainIPCHandle
|
||||
};
|
||||
|
||||
['VSCODE_NLS_CONFIG', 'VSCODE_LOGS', 'VSCODE_PORTABLE'].forEach(key => {
|
||||
['VSCODE_NLS_CONFIG', 'VSCODE_PORTABLE'].forEach(key => {
|
||||
const value = process.env[key];
|
||||
if (typeof value === 'string') {
|
||||
instanceEnvironment[key] = value;
|
||||
@@ -343,15 +343,7 @@ class CodeMain {
|
||||
|
||||
private handleStartupDataDirError(environmentService: IEnvironmentMainService, error: NodeJS.ErrnoException): void {
|
||||
if (error.code === 'EACCES' || error.code === 'EPERM') {
|
||||
const directories = [environmentService.userDataPath];
|
||||
|
||||
if (environmentService.extensionsPath) {
|
||||
directories.push(environmentService.extensionsPath);
|
||||
}
|
||||
|
||||
if (XDG_RUNTIME_DIR) {
|
||||
directories.push(XDG_RUNTIME_DIR);
|
||||
}
|
||||
const directories = coalesce([environmentService.userDataPath, environmentService.extensionsPath, XDG_RUNTIME_DIR]);
|
||||
|
||||
this.showStartupWarningDialog(
|
||||
localize('startupDataDirError', "Unable to write program user data."),
|
||||
|
||||
108
lib/vscode/src/vs/code/electron-main/protocol.ts
Normal file
108
lib/vscode/src/vs/code/electron-main/protocol.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { FileAccess, Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { session } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
|
||||
type ProtocolCallback = { (result: string | Electron.FilePathWithHeaders | { error: number }): void };
|
||||
|
||||
export class FileProtocolHandler extends Disposable {
|
||||
|
||||
private readonly validRoots = TernarySearchTree.forUris<boolean>(() => !isLinux);
|
||||
|
||||
constructor(
|
||||
@INativeEnvironmentService environmentService: INativeEnvironmentService,
|
||||
@ILogService private readonly logService: ILogService
|
||||
) {
|
||||
super();
|
||||
|
||||
const { defaultSession } = session;
|
||||
|
||||
// Define an initial set of roots we allow loading from
|
||||
// - appRoot : all files installed as part of the app
|
||||
// - extensions : all files shipped from extensions
|
||||
this.validRoots.set(URI.file(environmentService.appRoot), true);
|
||||
this.validRoots.set(URI.file(environmentService.extensionsPath), true);
|
||||
|
||||
// Register vscode-file:// handler
|
||||
defaultSession.protocol.registerFileProtocol(Schemas.vscodeFileResource, (request, callback) => this.handleResourceRequest(request, callback as unknown as ProtocolCallback));
|
||||
|
||||
// Block any file:// access (sandbox only)
|
||||
if (environmentService.args.__sandbox) {
|
||||
defaultSession.protocol.interceptFileProtocol(Schemas.file, (request, callback) => this.handleFileRequest(request, callback as unknown as ProtocolCallback));
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
this._register(toDisposable(() => {
|
||||
defaultSession.protocol.unregisterProtocol(Schemas.vscodeFileResource);
|
||||
if (environmentService.args.__sandbox) {
|
||||
defaultSession.protocol.uninterceptProtocol(Schemas.file);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
injectWindowsMainService(windowsMainService: IWindowsMainService): void {
|
||||
this._register(windowsMainService.onWindowReady(window => {
|
||||
if (window.config?.extensionDevelopmentPath || window.config?.extensionTestsPath) {
|
||||
const disposables = new DisposableStore();
|
||||
disposables.add(Event.any(window.onClose, window.onDestroy)(() => disposables.dispose()));
|
||||
|
||||
// Allow access to extension development path
|
||||
if (window.config.extensionDevelopmentPath) {
|
||||
for (const extensionDevelopmentPath of window.config.extensionDevelopmentPath) {
|
||||
disposables.add(this.addValidRoot(URI.file(extensionDevelopmentPath)));
|
||||
}
|
||||
}
|
||||
|
||||
// Allow access to extension tests path
|
||||
if (window.config.extensionTestsPath) {
|
||||
disposables.add(this.addValidRoot(URI.file(window.config.extensionTestsPath)));
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private addValidRoot(root: URI): IDisposable {
|
||||
if (!this.validRoots.get(root)) {
|
||||
this.validRoots.set(root, true);
|
||||
|
||||
return toDisposable(() => this.validRoots.delete(root));
|
||||
}
|
||||
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
private async handleFileRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback) {
|
||||
const uri = URI.parse(request.url);
|
||||
|
||||
this.logService.error(`Refused to load resource ${uri.fsPath} from ${Schemas.file}: protocol`);
|
||||
callback({ error: -3 /* ABORTED */ });
|
||||
}
|
||||
|
||||
private async handleResourceRequest(request: Electron.ProtocolRequest, callback: ProtocolCallback) {
|
||||
const uri = URI.parse(request.url);
|
||||
|
||||
// Restore the `vscode-file` URI to a `file` URI so that we can
|
||||
// ensure the root is valid and properly tell Chrome where the
|
||||
// resource is at.
|
||||
const fileUri = FileAccess.asFileUri(uri);
|
||||
if (this.validRoots.findSubstr(fileUri)) {
|
||||
return callback({
|
||||
path: fileUri.fsPath
|
||||
});
|
||||
}
|
||||
|
||||
this.logService.error(`${Schemas.vscodeFileResource}: Refused to load resource ${fileUri.fsPath}}`);
|
||||
callback({ error: -3 /* ABORTED */ });
|
||||
}
|
||||
}
|
||||
@@ -60,8 +60,9 @@ export class SharedProcess implements ISharedProcess {
|
||||
windowId: this.window.id
|
||||
};
|
||||
|
||||
const windowUrl = FileAccess
|
||||
.asBrowserUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require)
|
||||
const windowUrl = (this.environmentService.sandbox ?
|
||||
FileAccess._asCodeFileUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require) :
|
||||
FileAccess.asBrowserUri('vs/code/electron-browser/sharedProcess/sharedProcess.html', require))
|
||||
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` });
|
||||
this.window.loadURL(windowUrl.toString(true));
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as os from 'os';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as nls from 'vs/nls';
|
||||
import * as perf from 'vs/base/common/performance';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display, TouchBarSegmentedControl, NativeImage, BrowserWindowConstructorOptions, SegmentedControlSegment, nativeTheme, Event, Details } from 'electron';
|
||||
@@ -23,7 +24,6 @@ import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IWorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
|
||||
import { IBackupMainService } from 'vs/platform/backup/electron-main/backup';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import * as perf from 'vs/base/common/performance';
|
||||
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
@@ -33,8 +33,10 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
|
||||
import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService';
|
||||
import { IStorageMainService } from 'vs/platform/storage/node/storageMainService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ByteSize, IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileAccess, Schemas } from 'vs/base/common/network';
|
||||
import { isLaunchedFromCli } from 'vs/platform/environment/node/argvHelper';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
export interface IWindowCreationOptions {
|
||||
state: IWindowState;
|
||||
@@ -84,7 +86,7 @@ const enum ReadyState {
|
||||
|
||||
export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
private static readonly MAX_URL_LENGTH = 2 * 1024 * 1024; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32
|
||||
private static readonly MAX_URL_LENGTH = 2 * ByteSize.MB; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32
|
||||
|
||||
private readonly _onLoad = this._register(new Emitter<void>());
|
||||
readonly onLoad = this._onLoad.event;
|
||||
@@ -110,8 +112,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
private readonly whenReadyCallbacks: { (window: ICodeWindow): void }[];
|
||||
|
||||
private pendingLoadConfig?: INativeWindowConfiguration;
|
||||
|
||||
private marketplaceHeadersPromise: Promise<object>;
|
||||
|
||||
private readonly touchBarGroups: TouchBarSegmentedControl[];
|
||||
@@ -150,7 +150,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
// in case we are maximized or fullscreen, only show later after the call to maximize/fullscreen (see below)
|
||||
const isFullscreenOrMaximized = (this.windowState.mode === WindowMode.Maximized || this.windowState.mode === WindowMode.Fullscreen);
|
||||
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
|
||||
|
||||
const options: BrowserWindowConstructorOptions = {
|
||||
width: this.windowState.width,
|
||||
@@ -211,7 +211,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
options.tabbingIdentifier = product.nameShort; // this opts in to sierra tabs
|
||||
}
|
||||
|
||||
const useCustomTitleStyle = getTitleBarStyle(this.configurationService, this.environmentService, !!config.extensionDevelopmentPath) === 'custom';
|
||||
const useCustomTitleStyle = getTitleBarStyle(this.configurationService) === 'custom';
|
||||
if (useCustomTitleStyle) {
|
||||
options.titleBarStyle = 'hidden';
|
||||
this.hiddenTitleBarStyle = true;
|
||||
@@ -285,6 +285,8 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private pendingLoadConfig: INativeWindowConfiguration | undefined;
|
||||
|
||||
private currentConfig: INativeWindowConfiguration | undefined;
|
||||
get config(): INativeWindowConfiguration | undefined { return this.currentConfig; }
|
||||
|
||||
@@ -296,11 +298,11 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
get hasHiddenTitleBarStyle(): boolean { return !!this.hiddenTitleBarStyle; }
|
||||
|
||||
get isExtensionDevelopmentHost(): boolean { return !!(this.config && this.config.extensionDevelopmentPath); }
|
||||
get isExtensionDevelopmentHost(): boolean { return !!(this.currentConfig?.extensionDevelopmentPath); }
|
||||
|
||||
get isExtensionTestHost(): boolean { return !!(this.config && this.config.extensionTestsPath); }
|
||||
get isExtensionTestHost(): boolean { return !!(this.currentConfig?.extensionTestsPath); }
|
||||
|
||||
get isExtensionDevelopmentTestFromCli(): boolean { return this.isExtensionDevelopmentHost && this.isExtensionTestHost && !this.config?.debugId; }
|
||||
get isExtensionDevelopmentTestFromCli(): boolean { return this.isExtensionDevelopmentHost && this.isExtensionTestHost && !this.currentConfig?.debugId; }
|
||||
|
||||
setRepresentedFilename(filename: string): void {
|
||||
if (isMacintosh) {
|
||||
@@ -468,9 +470,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
return; // disposed
|
||||
}
|
||||
|
||||
// Notify renderers about displays changed
|
||||
this.sendWhenReady('vscode:displayChanged');
|
||||
|
||||
// Simple fullscreen doesn't resize automatically when the resolution changes so as a workaround
|
||||
// we need to detect when display metrics change or displays are added/removed and toggle the
|
||||
// fullscreen manually.
|
||||
@@ -520,11 +519,11 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
// Window Fullscreen
|
||||
this._win.on('enter-full-screen', () => {
|
||||
this.sendWhenReady('vscode:enterFullScreen');
|
||||
this.sendWhenReady('vscode:enterFullScreen', CancellationToken.None);
|
||||
});
|
||||
|
||||
this._win.on('leave-full-screen', () => {
|
||||
this.sendWhenReady('vscode:leaveFullScreen');
|
||||
this.sendWhenReady('vscode:leaveFullScreen', CancellationToken.None);
|
||||
});
|
||||
|
||||
// Window Failed to load
|
||||
@@ -680,6 +679,16 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
|
||||
load(config: INativeWindowConfiguration, isReload?: boolean, disableExtensions?: boolean): void {
|
||||
|
||||
// If this window was loaded before from the command line
|
||||
// (as indicated by VSCODE_CLI environment), make sure to
|
||||
// preserve that user environment in subsequent loads,
|
||||
// unless the new configuration context was also a CLI
|
||||
// (for https://github.com/microsoft/vscode/issues/108571)
|
||||
const currentUserEnv = (this.currentConfig ?? this.pendingLoadConfig)?.userEnv;
|
||||
if (currentUserEnv && isLaunchedFromCli(currentUserEnv) && !isLaunchedFromCli(config.userEnv)) {
|
||||
config.userEnv = { ...currentUserEnv, ...config.userEnv }; // still allow to override certain environment as passed in
|
||||
}
|
||||
|
||||
// If this is the first time the window is loaded, we associate the paths
|
||||
// directly with the window because we assume the loading will just work
|
||||
if (this._readyState === ReadyState.NONE) {
|
||||
@@ -738,10 +747,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
this._onLoad.fire();
|
||||
}
|
||||
|
||||
reload(configurationIn?: INativeWindowConfiguration, cli?: NativeParsedArgs): void {
|
||||
reload(cli?: NativeParsedArgs): void {
|
||||
|
||||
// If config is not provided, copy our current one
|
||||
const configuration = configurationIn ? configurationIn : objects.mixin({}, this.currentConfig);
|
||||
// Copy our current config for reuse
|
||||
const configuration = Object.assign({}, this.currentConfig);
|
||||
|
||||
// Delete some properties we do not want during reload
|
||||
delete configuration.filesToOpenOrCreate;
|
||||
@@ -773,7 +782,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
windowConfiguration.logLevel = this.logService.getLevel();
|
||||
|
||||
// Set zoomlevel
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
|
||||
const zoomLevel = windowConfig?.zoomLevel;
|
||||
if (typeof zoomLevel === 'number') {
|
||||
windowConfiguration.zoomLevel = zoomLevel;
|
||||
@@ -799,6 +808,11 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
// Parts splash
|
||||
windowConfiguration.partsSplashPath = path.join(this.environmentService.userDataPath, 'rapid_render.json');
|
||||
|
||||
// OS Info
|
||||
windowConfiguration.os = {
|
||||
release: os.release()
|
||||
};
|
||||
|
||||
// Config (combination of process.argv and window configuration)
|
||||
const environment = parseArgs(process.argv, OPTIONS);
|
||||
const config = Object.assign(environment, windowConfiguration) as unknown as { [key: string]: unknown };
|
||||
@@ -814,10 +828,9 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
// large depending on user configuration, so we can only remove it in that case.
|
||||
let configUrl = this.doGetUrl(config);
|
||||
if (configUrl.length > CodeWindow.MAX_URL_LENGTH) {
|
||||
delete config.userEnv;
|
||||
this.logService.warn('Application URL exceeds maximum of 2MB and was shortened.');
|
||||
|
||||
configUrl = this.doGetUrl(config);
|
||||
configUrl = this.doGetUrl({ ...config, userEnv: undefined });
|
||||
|
||||
if (configUrl.length > CodeWindow.MAX_URL_LENGTH) {
|
||||
this.logService.error('Application URL exceeds maximum of 2MB and cannot be loaded.');
|
||||
@@ -835,10 +848,10 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
workbench = 'vs/code/electron-browser/workbench/workbench.html';
|
||||
}
|
||||
|
||||
return FileAccess
|
||||
.asBrowserUri(workbench, require)
|
||||
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` })
|
||||
.toString(true);
|
||||
return (this.environmentService.sandbox ?
|
||||
FileAccess._asCodeFileUri(workbench, require) :
|
||||
FileAccess.asBrowserUri(workbench, require))
|
||||
.with({ query: `config=${encodeURIComponent(JSON.stringify(config))}` }).toString(true);
|
||||
}
|
||||
|
||||
serializeWindowState(): IWindowState {
|
||||
@@ -1088,7 +1101,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
// Events
|
||||
this.sendWhenReady(fullscreen ? 'vscode:enterFullScreen' : 'vscode:leaveFullScreen');
|
||||
this.sendWhenReady(fullscreen ? 'vscode:enterFullScreen' : 'vscode:leaveFullScreen', CancellationToken.None);
|
||||
|
||||
// Respect configured menu bar visibility or default to toggle if not set
|
||||
if (this.currentMenuBarVisibility) {
|
||||
@@ -1116,7 +1129,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
private useNativeFullScreen(): boolean {
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
|
||||
const windowConfig = this.configurationService.getValue<IWindowSettings | undefined>('window');
|
||||
if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') {
|
||||
return true; // default
|
||||
}
|
||||
@@ -1133,7 +1146,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
|
||||
private getMenuBarVisibility(): MenuBarVisibility {
|
||||
let menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService, !!this.config?.extensionDevelopmentPath);
|
||||
let menuBarVisibility = getMenuBarVisibility(this.configurationService);
|
||||
if (['visible', 'toggle', 'hidden'].indexOf(menuBarVisibility) < 0) {
|
||||
menuBarVisibility = 'default';
|
||||
}
|
||||
@@ -1229,11 +1242,15 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
}
|
||||
}
|
||||
|
||||
sendWhenReady(channel: string, ...args: any[]): void {
|
||||
sendWhenReady(channel: string, token: CancellationToken, ...args: any[]): void {
|
||||
if (this.isReady) {
|
||||
this.send(channel, ...args);
|
||||
} else {
|
||||
this.ready().then(() => this.send(channel, ...args));
|
||||
this.ready().then(() => {
|
||||
if (!token.isCancellationRequested) {
|
||||
this.send(channel, ...args);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,7 +1300,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
||||
mode: 'buttons',
|
||||
segmentStyle: 'automatic',
|
||||
change: (selectedIndex) => {
|
||||
this.sendWhenReady('vscode:runAction', { id: (control.segments[selectedIndex] as ITouchBarSegment).id, from: 'touchbar' });
|
||||
this.sendWhenReady('vscode:runAction', CancellationToken.None, { id: (control.segments[selectedIndex] as ITouchBarSegment).id, from: 'touchbar' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user