Compare commits

...

1 Commits

Author SHA1 Message Date
Samuel Maddock
55df89a374 fix: move windows above notifications for screen capture 2025-01-23 11:41:07 -05:00
4 changed files with 48 additions and 40 deletions

View File

@@ -90,6 +90,7 @@ describe('BrowserView module', () => {
w.show(); w.show();
w.setBounds(display.bounds); w.setBounds(display.bounds);
w.setBackgroundColor(WINDOW_BACKGROUND_COLOR); w.setBackgroundColor(WINDOW_BACKGROUND_COLOR);
ScreenCapture.setWindowOnTop(w);
await w.loadURL('about:blank'); await w.loadURL('about:blank');
view = new BrowserView(); view = new BrowserView();
@@ -109,6 +110,7 @@ describe('BrowserView module', () => {
w.show(); w.show();
w.setBounds(display.bounds); w.setBounds(display.bounds);
w.setBackgroundColor(WINDOW_BACKGROUND_COLOR); w.setBackgroundColor(WINDOW_BACKGROUND_COLOR);
ScreenCapture.setWindowOnTop(w);
await w.loadURL('about:blank'); await w.loadURL('about:blank');
view = new BrowserView(); view = new BrowserView();

View File

@@ -6647,29 +6647,24 @@ describe('BrowserWindow module', () => {
// FIXME(codebytere): figure out why these are failing on MAS arm64. // FIXME(codebytere): figure out why these are failing on MAS arm64.
ifit(hasCapturableScreen() && !(process.mas && process.arch === 'arm64'))('should not display a visible background', async () => { ifit(hasCapturableScreen() && !(process.mas && process.arch === 'arm64'))('should not display a visible background', async () => {
const display = screen.getPrimaryDisplay();
const backgroundWindow = new BrowserWindow({ const backgroundWindow = new BrowserWindow({
...display.bounds, ...ScreenCapture.getWindowOptions(),
frame: false, backgroundColor: HexColors.GREEN
backgroundColor: HexColors.GREEN,
hasShadow: false
}); });
ScreenCapture.setWindowOnTop(backgroundWindow);
await backgroundWindow.loadURL('about:blank'); await backgroundWindow.loadURL('about:blank');
const foregroundWindow = new BrowserWindow({ const foregroundWindow = new BrowserWindow({
...display.bounds, ...ScreenCapture.getWindowOptions(),
show: true, transparent: true
transparent: true,
frame: false,
hasShadow: false
}); });
ScreenCapture.setWindowOnTop(foregroundWindow);
const colorFile = path.join(__dirname, 'fixtures', 'pages', 'half-background-color.html'); const colorFile = path.join(__dirname, 'fixtures', 'pages', 'half-background-color.html');
await foregroundWindow.loadFile(colorFile); await foregroundWindow.loadFile(colorFile);
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
await screenCapture.expectColorAtPointOnDisplayMatches( await screenCapture.expectColorAtPointOnDisplayMatches(
HexColors.GREEN, HexColors.GREEN,
(size) => ({ (size) => ({
@@ -6688,48 +6683,43 @@ describe('BrowserWindow module', () => {
// FIXME(codebytere): figure out why these are failing on MAS arm64. // FIXME(codebytere): figure out why these are failing on MAS arm64.
ifit(hasCapturableScreen() && !(process.mas && process.arch === 'arm64'))('Allows setting a transparent window via CSS', async () => { ifit(hasCapturableScreen() && !(process.mas && process.arch === 'arm64'))('Allows setting a transparent window via CSS', async () => {
const display = screen.getPrimaryDisplay();
const backgroundWindow = new BrowserWindow({ const backgroundWindow = new BrowserWindow({
...display.bounds, ...ScreenCapture.getWindowOptions(),
frame: false, backgroundColor: HexColors.PURPLE
backgroundColor: HexColors.PURPLE,
hasShadow: false
}); });
ScreenCapture.setWindowOnTop(backgroundWindow);
await backgroundWindow.loadURL('about:blank'); await backgroundWindow.loadURL('about:blank');
const foregroundWindow = new BrowserWindow({ const foregroundWindow = new BrowserWindow({
...display.bounds, ...ScreenCapture.getWindowOptions(),
frame: false,
transparent: true, transparent: true,
hasShadow: false,
webPreferences: { webPreferences: {
contextIsolation: false, contextIsolation: false,
nodeIntegration: true nodeIntegration: true
} }
}); });
ScreenCapture.setWindowOnTop(foregroundWindow);
foregroundWindow.loadFile(path.join(__dirname, 'fixtures', 'pages', 'css-transparent.html')); foregroundWindow.loadFile(path.join(__dirname, 'fixtures', 'pages', 'css-transparent.html'));
await once(ipcMain, 'set-transparent'); await once(ipcMain, 'set-transparent');
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
await screenCapture.expectColorAtCenterMatches(HexColors.PURPLE); await screenCapture.expectColorAtCenterMatches(HexColors.PURPLE);
}); });
ifit(hasCapturableScreen())('should not make background transparent if falsy', async () => { ifit(hasCapturableScreen())('should not make background transparent if falsy', async () => {
const display = screen.getPrimaryDisplay();
for (const transparent of [false, undefined]) { for (const transparent of [false, undefined]) {
const window = new BrowserWindow({ const window = new BrowserWindow({
...display.bounds, ...ScreenCapture.getWindowOptions(),
transparent transparent
}); });
ScreenCapture.setWindowOnTop(window);
await once(window, 'show'); await once(window, 'show');
await window.webContents.loadURL('data:text/html,<head><meta name="color-scheme" content="dark"></head>'); await window.webContents.loadURL('data:text/html,<head><meta name="color-scheme" content="dark"></head>');
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
// color-scheme is set to dark so background should not be white // color-scheme is set to dark so background should not be white
await screenCapture.expectColorAtCenterDoesNotMatch(HexColors.WHITE); await screenCapture.expectColorAtCenterDoesNotMatch(HexColors.WHITE);
@@ -6742,18 +6732,16 @@ describe('BrowserWindow module', () => {
afterEach(closeAllWindows); afterEach(closeAllWindows);
ifit(hasCapturableScreen())('should display the set color', async () => { ifit(hasCapturableScreen())('should display the set color', async () => {
const display = screen.getPrimaryDisplay();
const w = new BrowserWindow({ const w = new BrowserWindow({
...display.bounds, ...ScreenCapture.getWindowOptions(),
show: true,
backgroundColor: HexColors.BLUE backgroundColor: HexColors.BLUE
}); });
ScreenCapture.setWindowOnTop(w);
w.loadURL('about:blank'); w.loadURL('about:blank');
await once(w, 'ready-to-show'); await once(w, 'ready-to-show');
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
await screenCapture.expectColorAtCenterMatches(HexColors.BLUE); await screenCapture.expectColorAtCenterMatches(HexColors.BLUE);
}); });
}); });

View File

@@ -287,13 +287,10 @@ describe('WebContentsView', () => {
display = screen.getPrimaryDisplay(); display = screen.getPrimaryDisplay();
w = new BaseWindow({ w = new BaseWindow({
...display.workArea, ...ScreenCapture.getWindowOptions(),
show: true, backgroundColor: HexColors.BLUE
frame: false,
hasShadow: false,
backgroundColor: HexColors.BLUE,
roundedCorners: false
}); });
ScreenCapture.setWindowOnTop(w);
v = new WebContentsView(); v = new WebContentsView();
w.setContentView(v); w.setContentView(v);
@@ -319,7 +316,7 @@ describe('WebContentsView', () => {
}); });
it('should render with cutout corners', async () => { it('should render with cutout corners', async () => {
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
for (const corner of corners) { for (const corner of corners) {
await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.BLUE, () => corner); await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.BLUE, () => corner);
@@ -334,7 +331,7 @@ describe('WebContentsView', () => {
v.setBorderRadius(0); v.setBorderRadius(0);
await nextFrameTime(); await nextFrameTime();
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.GREEN, () => corner); await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.GREEN, () => corner);
await screenCapture.expectColorAtCenterMatches(HexColors.GREEN); await screenCapture.expectColorAtCenterMatches(HexColors.GREEN);
}); });
@@ -350,7 +347,7 @@ describe('WebContentsView', () => {
await readyForCapture; await readyForCapture;
const corner = corners[0]; const corner = corners[0];
const screenCapture = new ScreenCapture(display); const screenCapture = new ScreenCapture();
await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.BLUE, () => corner); await screenCapture.expectColorAtPointOnDisplayMatches(HexColors.BLUE, () => corner);
await screenCapture.expectColorAtCenterMatches(HexColors.GREEN); await screenCapture.expectColorAtCenterMatches(HexColors.GREEN);
}); });

View File

@@ -103,6 +103,27 @@ export class ScreenCapture {
/** Timeout to wait for expected color to match. */ /** Timeout to wait for expected color to match. */
static TIMEOUT = 3000; static TIMEOUT = 3000;
/**
* Get window options which make it ideal to capture.
*/
static getWindowOptions () {
const display = screen.getPrimaryDisplay();
return {
...display.workArea,
frame: false,
hasShadow: false,
roundedCorners: false
};
}
/**
* Set window to appear above notifications on macOS.
*/
static setWindowOnTop (window: Electron.BaseWindow) {
const level = process.platform === 'darwin' ? 'screen-saver' : undefined;
window.setAlwaysOnTop(true, level);
}
constructor (display?: Electron.Display) { constructor (display?: Electron.Display) {
this.display = display || screen.getPrimaryDisplay(); this.display = display || screen.getPrimaryDisplay();
} }