1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
/*
* Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com>
*
* This file is part of Sophie.
*
* Sophie is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import type { BrowserViewBounds } from '@sophie/shared';
import { BrowserView } from 'electron';
import type Service from '../../../stores/Service';
import type Resources from '../../resources/Resources';
import type { ServiceView } from '../types';
import ElectronPartition from './ElectronPartition';
import type ElectronViewFactory from './ElectronViewFactory';
export default class ElectronServiceView implements ServiceView {
readonly id: string;
readonly partitionId: string;
readonly browserView: BrowserView;
constructor(
service: Service,
resources: Resources,
partition: ElectronPartition,
private readonly parent: ElectronViewFactory,
) {
this.id = service.id;
this.partitionId = partition.id;
this.browserView = new BrowserView({
webPreferences: {
sandbox: true,
nodeIntegrationInSubFrames: true,
preload: resources.getPath('service-preload', 'index.cjs'),
session: partition.session,
},
});
const { webContents } = this.browserView;
function setLocation(url: string) {
service.setLocation({
url,
canGoBack: webContents.canGoBack(),
canGoForward: webContents.canGoForward(),
});
}
webContents.on('did-navigate', (_event, url) => {
setLocation(url);
});
webContents.on('did-navigate-in-page', (_event, url, isMainFrame) => {
if (isMainFrame) {
setLocation(url);
}
});
webContents.on('page-title-updated', (_event, title) => {
service.setTitle(title);
});
webContents.on('did-start-loading', () => {
service.startedLoading();
});
webContents.on('did-finish-load', () => {
service.finishedLoading();
});
webContents.on('render-process-gone', () => {
service.crashed();
});
}
get webContentsId(): number {
return this.browserView.webContents.id;
}
loadURL(url: string): Promise<void> {
return this.browserView.webContents.loadURL(url);
}
goBack(): void {
this.browserView.webContents.goBack();
}
goForward(): void {
this.browserView.webContents.goForward();
}
setBounds(bounds: BrowserViewBounds): void {
this.browserView.setBounds(bounds);
}
dispose(): void {
this.parent.unregisterServiceView(this.webContentsId);
setImmediate(() => {
// Undocumented electron API, see e.g., https://github.com/electron/electron/issues/29626
(
this.browserView.webContents as unknown as { destroy(): void }
).destroy();
});
}
}
|