diff --git a/docs/changelog.rst b/docs/changelog.rst index 76bb75143..79eca2514 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -179,6 +179,10 @@ Detailed list of changes - macOS: Workaround for bug in macOS Tahoe that caused closed OS Windows to remain as invisible rectangles that intercept mouse events (:iss:`8952`) +- macOS: Workaround for bug in macOS Tahoe that caused OS Windows that are + fullscreen on a monitor that is disconnected while macOS is asleep to crash kitty (:iss:`8983`) + + 0.42.2 [2025-07-16] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index f632e9d6f..7361725c1 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -521,6 +521,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; @interface GLFWWindowDelegate : NSObject { _GLFWwindow* window; + NSArray *_lastScreenStates; } - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow; @@ -533,12 +534,26 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow { self = [super init]; - if (self != nil) + if (self != nil) { window = initWindow; - + _lastScreenStates = [self captureScreenStates]; + } return self; } +- (NSArray *)captureScreenStates { + NSMutableArray *states = [NSMutableArray array]; + for (NSScreen *screen in [NSScreen screens]) { + // Use the screen's deviceDescription, which contains a stable ID. + [states addObject:screen.deviceDescription]; + } + return [states copy]; +} + +- (void)cleanup { + [_lastScreenStates release]; _lastScreenStates = nil; +} + - (BOOL)windowShouldClose:(id)sender { (void)sender; @@ -549,6 +564,16 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (void)windowDidResize:(NSNotification *)notification { (void)notification; + NSArray *currentScreenStates = [self captureScreenStates]; + const bool is_screen_change = ![_lastScreenStates isEqualToArray:currentScreenStates]; + debug_rendering("windowDidResize() called, is_screen_change: %d\n", is_screen_change); + if (is_screen_change) { + // This resize likely happened because a screen was added, removed, or changed resolution. + [_lastScreenStates release]; + _lastScreenStates = [currentScreenStates retain]; + } + [currentScreenStates release]; + if (window->context.client != GLFW_NO_API) [window->context.nsgl.object update]; @@ -580,7 +605,10 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; window->ns.height = (int)contentRect.size.height; _glfwInputWindowSize(window, (int)contentRect.size.width, (int)contentRect.size.height); } - if (window->ns.resizeCallback) window->ns.resizeCallback((GLFWwindow*)window); + // Because of a bug in macOS Tahoe we cannot redraw the window in response + // to a resize event that was caused by a screen change as the OpenGL + // context is not ready yet. See: https://github.com/kovidgoyal/kitty/issues/8983 + if (window->ns.resizeCallback && !is_screen_change) window->ns.resizeCallback((GLFWwindow*)window); } - (void)windowDidMove:(NSNotification *)notification @@ -1913,6 +1941,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) window->context.destroy(window); [window->ns.object setDelegate:nil]; + [window->ns.delegate cleanup]; [window->ns.delegate release]; window->ns.delegate = nil;