Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/browserView/electron-main/browserViewMainService.ts
4776 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { session } from 'electron';
7
import { Disposable, DisposableMap } from '../../../base/common/lifecycle.js';
8
import { VSBuffer } from '../../../base/common/buffer.js';
9
import { IBrowserViewBounds, IBrowserViewKeyDownEvent, IBrowserViewState, IBrowserViewService, BrowserViewStorageScope, IBrowserViewCaptureScreenshotOptions } from '../common/browserView.js';
10
import { joinPath } from '../../../base/common/resources.js';
11
import { IEnvironmentMainService } from '../../environment/electron-main/environmentMainService.js';
12
import { createDecorator, IInstantiationService } from '../../instantiation/common/instantiation.js';
13
import { BrowserView } from './browserView.js';
14
import { generateUuid } from '../../../base/common/uuid.js';
15
16
export const IBrowserViewMainService = createDecorator<IBrowserViewMainService>('browserViewMainService');
17
18
export interface IBrowserViewMainService extends IBrowserViewService {
19
// Additional electron-specific methods can be added here if needed in the future
20
}
21
22
// Same as webviews
23
const allowedPermissions = new Set([
24
'pointerLock',
25
'notifications',
26
'clipboard-read',
27
'clipboard-sanitized-write'
28
]);
29
30
export class BrowserViewMainService extends Disposable implements IBrowserViewMainService {
31
declare readonly _serviceBrand: undefined;
32
33
/**
34
* Check if a webContents belongs to an integrated browser view
35
*/
36
private static readonly knownSessions = new WeakSet<Electron.Session>();
37
static isBrowserViewWebContents(contents: Electron.WebContents): boolean {
38
return BrowserViewMainService.knownSessions.has(contents.session);
39
}
40
41
private readonly browserViews = this._register(new DisposableMap<string, BrowserView>());
42
43
constructor(
44
@IEnvironmentMainService private readonly environmentMainService: IEnvironmentMainService,
45
@IInstantiationService private readonly instantiationService: IInstantiationService
46
) {
47
super();
48
}
49
50
/**
51
* Get the session for a browser view based on data storage setting and workspace
52
*/
53
private getSession(requestedScope: BrowserViewStorageScope, viewId?: string, workspaceId?: string): {
54
session: Electron.Session;
55
resolvedScope: BrowserViewStorageScope;
56
} {
57
switch (requestedScope) {
58
case 'global':
59
return { session: session.fromPartition('persist:vscode-browser'), resolvedScope: BrowserViewStorageScope.Global };
60
case 'workspace':
61
if (workspaceId) {
62
const storage = joinPath(this.environmentMainService.workspaceStorageHome, workspaceId, 'browserStorage');
63
return { session: session.fromPath(storage.fsPath), resolvedScope: BrowserViewStorageScope.Workspace };
64
}
65
// fallthrough
66
case 'ephemeral':
67
default:
68
return { session: session.fromPartition(`vscode-browser-${viewId ?? generateUuid()}`), resolvedScope: BrowserViewStorageScope.Ephemeral };
69
}
70
}
71
72
private configureSession(viewSession: Electron.Session): void {
73
viewSession.setPermissionRequestHandler((_webContents, permission, callback) => {
74
return callback(allowedPermissions.has(permission));
75
});
76
viewSession.setPermissionCheckHandler((_webContents, permission, _origin) => {
77
return allowedPermissions.has(permission);
78
});
79
}
80
81
async getOrCreateBrowserView(id: string, scope: BrowserViewStorageScope, workspaceId?: string): Promise<IBrowserViewState> {
82
if (this.browserViews.has(id)) {
83
// Note: scope will be ignored if the view already exists.
84
// Browser views cannot be moved between sessions after creation.
85
const view = this.browserViews.get(id)!;
86
return view.getState();
87
}
88
89
const { session, resolvedScope } = this.getSession(scope, id, workspaceId);
90
this.configureSession(session);
91
BrowserViewMainService.knownSessions.add(session);
92
93
const view = this.instantiationService.createInstance(BrowserView, session, resolvedScope);
94
this.browserViews.set(id, view);
95
96
return view.getState();
97
}
98
99
/**
100
* Get a browser view or throw if not found
101
*/
102
private _getBrowserView(id: string): BrowserView {
103
const view = this.browserViews.get(id);
104
if (!view) {
105
throw new Error(`Browser view ${id} not found`);
106
}
107
return view;
108
}
109
110
onDynamicDidNavigate(id: string) {
111
return this._getBrowserView(id).onDidNavigate;
112
}
113
114
onDynamicDidChangeLoadingState(id: string) {
115
return this._getBrowserView(id).onDidChangeLoadingState;
116
}
117
118
onDynamicDidChangeFocus(id: string) {
119
return this._getBrowserView(id).onDidChangeFocus;
120
}
121
122
onDynamicDidChangeDevToolsState(id: string) {
123
return this._getBrowserView(id).onDidChangeDevToolsState;
124
}
125
126
onDynamicDidKeyCommand(id: string) {
127
return this._getBrowserView(id).onDidKeyCommand;
128
}
129
130
onDynamicDidChangeTitle(id: string) {
131
return this._getBrowserView(id).onDidChangeTitle;
132
}
133
134
onDynamicDidChangeFavicon(id: string) {
135
return this._getBrowserView(id).onDidChangeFavicon;
136
}
137
138
onDynamicDidRequestNewPage(id: string) {
139
return this._getBrowserView(id).onDidRequestNewPage;
140
}
141
142
onDynamicDidClose(id: string) {
143
return this._getBrowserView(id).onDidClose;
144
}
145
146
async destroyBrowserView(id: string): Promise<void> {
147
this.browserViews.deleteAndDispose(id);
148
}
149
150
async layout(id: string, bounds: IBrowserViewBounds): Promise<void> {
151
return this._getBrowserView(id).layout(bounds);
152
}
153
154
async setVisible(id: string, visible: boolean): Promise<void> {
155
return this._getBrowserView(id).setVisible(visible);
156
}
157
158
async loadURL(id: string, url: string): Promise<void> {
159
return this._getBrowserView(id).loadURL(url);
160
}
161
162
async getURL(id: string): Promise<string> {
163
return this._getBrowserView(id).getURL();
164
}
165
166
async goBack(id: string): Promise<void> {
167
return this._getBrowserView(id).goBack();
168
}
169
170
async goForward(id: string): Promise<void> {
171
return this._getBrowserView(id).goForward();
172
}
173
174
async reload(id: string): Promise<void> {
175
return this._getBrowserView(id).reload();
176
}
177
178
async toggleDevTools(id: string): Promise<void> {
179
return this._getBrowserView(id).toggleDevTools();
180
}
181
182
async canGoBack(id: string): Promise<boolean> {
183
return this._getBrowserView(id).canGoBack();
184
}
185
186
async canGoForward(id: string): Promise<boolean> {
187
return this._getBrowserView(id).canGoForward();
188
}
189
190
async captureScreenshot(id: string, options?: IBrowserViewCaptureScreenshotOptions): Promise<VSBuffer> {
191
return this._getBrowserView(id).captureScreenshot(options);
192
}
193
194
async dispatchKeyEvent(id: string, keyEvent: IBrowserViewKeyDownEvent): Promise<void> {
195
return this._getBrowserView(id).dispatchKeyEvent(keyEvent);
196
}
197
198
async setZoomFactor(id: string, zoomFactor: number): Promise<void> {
199
return this._getBrowserView(id).setZoomFactor(zoomFactor);
200
}
201
202
async focus(id: string): Promise<void> {
203
return this._getBrowserView(id).focus();
204
}
205
206
async clearGlobalStorage(): Promise<void> {
207
const { session, resolvedScope } = this.getSession(BrowserViewStorageScope.Global);
208
if (resolvedScope !== BrowserViewStorageScope.Global) {
209
throw new Error('Failed to resolve global storage session');
210
}
211
await session.clearData();
212
}
213
214
async clearWorkspaceStorage(workspaceId: string): Promise<void> {
215
const { session, resolvedScope } = this.getSession(BrowserViewStorageScope.Workspace, undefined, workspaceId);
216
if (resolvedScope !== BrowserViewStorageScope.Workspace) {
217
throw new Error('Failed to resolve workspace storage session');
218
}
219
await session.clearData();
220
}
221
}
222
223