diff --git a/src/main/browser/popup-origin-bar-window.test.ts b/src/main/browser/popup-origin-bar-window.test.ts index fedcd4dfdd0..48d2e962eae 100644 --- a/src/main/browser/popup-origin-bar-window.test.ts +++ b/src/main/browser/popup-origin-bar-window.test.ts @@ -64,16 +64,31 @@ const { fakeElectron } = vi.hoisted(() => { } } + class FakeContentView { + private handlers = new Map() + addChildView = vi.fn() + on(event: string, handler: Handler): void { + this.handlers.set(event, [...(this.handlers.get(event) ?? []), handler]) + } + emit(event: string): void { + for (const handler of this.handlers.get(event) ?? []) { + handler() + } + } + } + class FakeBaseWindow { static instances: FakeBaseWindow[] = [] options: Record private handlers = new Map() - contentView = { addChildView: vi.fn() } + contentView = new FakeContentView() + contentSize: { width: number; height: number } setTitle = vi.fn() isDestroyed = vi.fn(() => false) close = vi.fn(() => this.emit('closed')) constructor(options: Record) { this.options = options + this.contentSize = { width: Number(options.width), height: Number(options.height) } FakeBaseWindow.instances.push(this) } on(event: string, handler: Handler): void { @@ -83,12 +98,7 @@ const { fakeElectron } = vi.hoisted(() => { this.on(event, handler) } getContentBounds(): { x: number; y: number; width: number; height: number } { - return { - x: 0, - y: 0, - width: this.options.width as number, - height: this.options.height as number - } + return { x: 0, y: 0, ...this.contentSize } } emit(event: string, ...args: unknown[]): void { for (const handler of this.handlers.get(event) ?? []) { @@ -203,7 +213,8 @@ describe('openPopupWithOriginBar', () => { expect(lastWindow().options).toMatchObject({ width: 500, - height: 400 + POPUP_ORIGIN_BAR_HEIGHT + height: 400 + POPUP_ORIGIN_BAR_HEIGHT, + autoHideMenuBar: true }) const { bar, content } = lastViews() expect(bar.setBounds).toHaveBeenCalledWith({ @@ -220,6 +231,24 @@ describe('openPopupWithOriginBar', () => { }) }) + it('re-lays out when the revealed menu bar shrinks the content area', () => { + openPopupWithOriginBar( + { webContents: createFakeWebContents() as never, width: 500, height: 400 }, + 'https://example.com/' + ) + const window = lastWindow() + const menuBarHeight = 25 + window.contentSize = { width: 500, height: 400 + POPUP_ORIGIN_BAR_HEIGHT - menuBarHeight } + window.contentView.emit('bounds-changed') + + expect(lastViews().content.setBounds).toHaveBeenLastCalledWith({ + x: 0, + y: POPUP_ORIGIN_BAR_HEIGHT, + width: 500, + height: 400 - menuBarHeight + }) + }) + it('keeps the origin bar isolated with locked-down webPreferences', () => { openPopupWithOriginBar( { webContents: createFakeWebContents() as never }, diff --git a/src/main/browser/popup-origin-bar-window.ts b/src/main/browser/popup-origin-bar-window.ts index cfbe3ef3d3b..0786f136c5b 100644 --- a/src/main/browser/popup-origin-bar-window.ts +++ b/src/main/browser/popup-origin-bar-window.ts @@ -155,7 +155,9 @@ export function openPopupWithOriginBar( : {}), minWidth: MIN_POPUP_CONTENT_WIDTH, minHeight: MIN_POPUP_CONTENT_HEIGHT + POPUP_ORIGIN_BAR_HEIGHT, - title: initialOrigin.label + title: initialOrigin.label, + // Why: Windows/Linux attach Orca's app menu to every window, including web popups. + autoHideMenuBar: true }) // Why: the origin bar renders only Orca's own data: URL and must stay @@ -184,6 +186,8 @@ export function openPopupWithOriginBar( }) } window.on('resize', layoutViews) + // Why: Alt-revealing the auto-hidden menu bar shrinks the content area without resizing the window. + window.contentView.on('bounds-changed', layoutViews) // Why: HTML5 fullscreen makes the whole window fullscreen. resize covers // this on macOS, but re-pin on the explicit events too so the origin bar // provably stays above fullscreen content on every platform.