Reimplement offscreen window for more reliable WebContentsView visibility on load

This commit is contained in:
Max Goodhart
2025-07-04 18:58:46 -07:00
parent f22f04b3d6
commit 36640f2bf1
2 changed files with 27 additions and 8 deletions

View File

@@ -138,7 +138,10 @@ export default class StreamWindow extends EventEmitter<StreamWindowEventMap> {
}
createView() {
const { win } = this
const {
win,
config: { width, height },
} = this
assert(win != null, 'Window must be initialized')
const { backgroundColor } = this.config
const view = new WebContentsView({
@@ -159,11 +162,19 @@ export default class StreamWindow extends EventEmitter<StreamWindowEventMap> {
ev.preventDefault()
})
// Hidden window used for loading the BrowserView before it's positioned in the wall
const offscreenWin = new BrowserWindow({
width,
height,
show: false,
})
const actor = createActor(viewStateMachine, {
input: {
id: viewId,
view,
win,
offscreenWin,
},
})
@@ -277,9 +288,12 @@ export default class StreamWindow extends EventEmitter<StreamWindowEventMap> {
newViews.set(view.getSnapshot().context.id, view)
}
for (const view of unusedViews) {
const contentView = view.getSnapshot().context.view
view.stop()
const { view: contentView, offscreenWin } = view.getSnapshot().context
offscreenWin.contentView.removeChildView(contentView)
win.contentView.removeChildView(contentView)
contentView.webContents.close()
offscreenWin.destroy()
}
this.views = newViews
this.emitState()

View File

@@ -21,11 +21,13 @@ const viewStateMachine = setup({
id: number
view: WebContentsView
win: BrowserWindow
offscreenWin: BrowserWindow
},
context: {} as {
id: number
win: BrowserWindow
offscreenWin: BrowserWindow
view: WebContentsView
pos: ViewPos | null
content: ViewContent | null
@@ -83,20 +85,22 @@ const viewStateMachine = setup({
},
offscreenView: ({ context }) => {
const { view, win } = context
win.contentView.addChildView(view, 0) // Insert below background (so hidden by background)
const { width, height } = win.getBounds()
const { view, win, offscreenWin } = context
win.contentView.removeChildView(view)
offscreenWin.contentView.addChildView(view)
const { width, height } = offscreenWin.getBounds()
view.setBounds({ x: 0, y: 0, width, height })
},
positionView: ({ context }) => {
const { pos, view, win } = context
const { pos, view, win, offscreenWin } = context
if (!pos) {
return
}
win.contentView.addChildView(view, win.contentView.children.length - 2) // Insert below overlay but above background
offscreenWin.contentView.removeChildView(view)
win.contentView.addChildView(view, win.contentView.children.length - 1) // Insert below overlay but above background
view.setBounds(pos)
},
},
@@ -148,10 +152,11 @@ const viewStateMachine = setup({
}).createMachine({
id: 'view',
initial: 'empty',
context: ({ input: { id, view, win } }) => ({
context: ({ input: { id, view, win, offscreenWin } }) => ({
id,
view,
win,
offscreenWin,
pos: null,
content: null,
options: null,