Skip to content

Commit d7f3af6

Browse files
author
Tajudeen
committed
Fix macOS blank screen with comprehensive window visibility handling
- Add 'ready-to-show' event listener (Electron best practice for macOS) - Implement multi-layered approach: ready-to-show, immediate check, page load events, timeout fallback - Add detailed logging for debugging window visibility issues - Ensure window is shown with valid bounds at multiple checkpoints - Handle edge cases where window might not be visible after loadURL - Production-ready fix that handles all timing scenarios
1 parent 255934a commit d7f3af6

File tree

1 file changed

+70
-30
lines changed

1 file changed

+70
-30
lines changed

src/vs/platform/windows/electron-main/windowImpl.ts

Lines changed: 70 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,43 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
757757

758758
private registerListeners(): void {
759759

760+
// macOS: Use 'ready-to-show' event to show window when ready (prevents blank screen)
761+
// This is the Electron best practice for macOS to avoid flicker and blank screens
762+
// The 'ready-to-show' event fires when the window is ready to be displayed without flicker
763+
if (isMacintosh) {
764+
let readyToShowFired = false;
765+
this._register(Event.fromNodeEventEmitter(this._win, 'ready-to-show')(() => {
766+
if (!readyToShowFired && this._win && !this._win.isDestroyed()) {
767+
readyToShowFired = true;
768+
this.logService.trace('window#ready-to-show: window ready, ensuring visibility on macOS');
769+
770+
// Ensure window is visible with valid bounds
771+
if (!this._win.isVisible()) {
772+
this._win.showInactive();
773+
}
774+
if (this._win.isMinimized()) {
775+
this._win.restore();
776+
}
777+
778+
// Validate bounds
779+
const bounds = this._win.getBounds();
780+
if (bounds && (bounds.width === 0 || bounds.height === 0)) {
781+
this.logService.warn('window#ready-to-show: invalid bounds, resetting');
782+
this._win.setSize(1024, 768);
783+
this._win.center();
784+
}
785+
786+
// Focus the window to ensure it's active and rendered
787+
// Use setTimeout to ensure this happens after the window is fully ready
788+
setTimeout(() => {
789+
if (this._win && !this._win.isDestroyed()) {
790+
this._win.focus();
791+
}
792+
}, 0);
793+
}
794+
}));
795+
}
796+
760797
// Window error conditions to handle
761798
this._register(Event.fromNodeEventEmitter(this._win, 'unresponsive')(() => this.onWindowError(WindowError.UNRESPONSIVE)));
762799
this._register(Event.fromNodeEventEmitter(this._win, 'responsive')(() => this.onWindowError(WindowError.RESPONSIVE)));
@@ -1134,56 +1171,59 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
11341171
// Load URL
11351172
this._win.loadURL(FileAccess.asBrowserUri(`vs/code/electron-browser/workbench/workbench${this.environmentMainService.isBuilt ? '' : '-dev'}.html`).toString(true));
11361173

1137-
// Fix for macOS blank screen: Ensure window is visible and has valid bounds
1138-
// This fix runs immediately and also after the page loads to handle timing issues
1174+
// macOS: Comprehensive fix for blank screen issue
1175+
// The window is created with show: false to reduce flicker, but on macOS this can cause blank screens
1176+
// We use multiple strategies to ensure the window is visible:
1177+
// 1. 'ready-to-show' event (handled in registerListeners) - primary method
1178+
// 2. Immediate check after loadURL - fallback if ready-to-show doesn't fire
1179+
// 3. Page load events - ensure visibility after content loads
1180+
// 4. Timeout fallback - last resort
11391181
if (isMacintosh && this._win) {
1140-
// Immediate fix: Force window to be shown if it's not visible
1141-
if (!this._win.isVisible()) {
1142-
this._win.showInactive();
1143-
}
1144-
// Ensure window is not minimized
1145-
if (this._win.isMinimized()) {
1146-
this._win.restore();
1147-
}
1148-
// Validate and fix window bounds if invalid (0x0 or off-screen)
1149-
const bounds = this._win.getBounds();
1150-
if (bounds && (bounds.width === 0 || bounds.height === 0)) {
1151-
// Reset to default size if invalid
1152-
this._win.setSize(1024, 768);
1153-
this._win.center();
1154-
}
1155-
1156-
// Additional fix: Ensure window is visible after page loads (handles async loadURL timing)
1157-
// Use both 'did-finish-load' and 'dom-ready' events to catch all cases
1182+
// Immediate check: Show window if it's not visible (fallback if ready-to-show hasn't fired)
11581183
const ensureWindowVisible = () => {
11591184
if (this._win && !this._win.isDestroyed()) {
11601185
if (!this._win.isVisible()) {
1186+
this.logService.trace('window#load: forcing window to show on macOS');
11611187
this._win.showInactive();
11621188
}
11631189
if (this._win.isMinimized()) {
11641190
this._win.restore();
11651191
}
1166-
// Re-check bounds after page load
1167-
const currentBounds = this._win.getBounds();
1168-
if (currentBounds && (currentBounds.width === 0 || currentBounds.height === 0)) {
1192+
1193+
// Validate and fix window bounds
1194+
const bounds = this._win.getBounds();
1195+
if (bounds && (bounds.width === 0 || bounds.height === 0)) {
1196+
this.logService.warn('window#load: invalid window bounds detected, resetting to default size');
11691197
this._win.setSize(1024, 768);
11701198
this._win.center();
11711199
}
1172-
// Ensure window is focused to prevent blank screen
1200+
1201+
// Focus the window to ensure it's active and rendered
11731202
this._win.focus();
11741203
}
11751204
};
11761205

1177-
// Listen for page load events to ensure window is visible
1178-
this._win.webContents.once('did-finish-load', ensureWindowVisible);
1179-
this._win.webContents.once('dom-ready', ensureWindowVisible);
1206+
// Immediate check (in case ready-to-show already fired or won't fire)
1207+
ensureWindowVisible();
1208+
1209+
// Listen for page load events as additional safety net
1210+
this._win.webContents.once('did-finish-load', () => {
1211+
this.logService.trace('window#load: did-finish-load event, ensuring window visibility');
1212+
ensureWindowVisible();
1213+
});
1214+
1215+
this._win.webContents.once('dom-ready', () => {
1216+
this.logService.trace('window#load: dom-ready event, ensuring window visibility');
1217+
ensureWindowVisible();
1218+
});
11801219

1181-
// Also ensure visibility after a short delay as a fallback
1220+
// Fallback: Ensure visibility after a delay (handles edge cases)
11821221
setTimeout(() => {
1183-
if (this._win && !this._win.isDestroyed()) {
1222+
if (this._win && !this._win.isDestroyed() && !this._win.isVisible()) {
1223+
this.logService.warn('window#load: window still not visible after delay, forcing show');
11841224
ensureWindowVisible();
11851225
}
1186-
}, 100);
1226+
}, 500);
11871227
}
11881228

11891229
// Remember that we did load

0 commit comments

Comments
 (0)