diff --git a/docs/changelog.rst b/docs/changelog.rst index dd0b5a945..2d70dc99c 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -134,6 +134,13 @@ consumption to do the same tasks. Detailed list of changes ------------------------------------- +0.43.1 [future] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- macOS: Fix a big where the color of a transparent titlebar was off when + running in the release build versus the build from source. Also fix using a + transparent titlebar causing the background opacity to be darkened. + 0.43.0 [2025-09-28] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index b484be022..395b5125c 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -3280,19 +3280,20 @@ title_bar_and_tool_bar_height(NSWindow *window) { static void clear_title_bar_background_views(NSWindow *window) { #define tag @"kitty-for-transparent-titlebar" - NSView *contentView = window.contentView; - if (contentView) { - for (NSView *subview in [contentView viewsWithIdentifier:tag]) [subview removeFromSuperview]; + NSView *contentView = window.contentView, *titlebarContainer = contentView ? contentView.superview : nil; + if (titlebarContainer) { + for (NSView *subview in [titlebarContainer viewsWithIdentifier:tag]) [subview removeFromSuperview]; } } static void set_title_bar_background(NSWindow *window, NSColor *backgroundColor) { + // add an extra view that just renders the background color under the transparent titlebar NSView *contentView = window.contentView, *titlebarContainer = contentView ? contentView.superview : nil; if (!titlebarContainer) return; - for (NSView *subview in [contentView viewsWithIdentifier:tag]) [subview removeFromSuperview]; + contentView.identifier = @"kitty-content-view"; + for (NSView *subview in [titlebarContainer viewsWithIdentifier:tag]) [subview removeFromSuperview]; if (!backgroundColor) return; - const CGFloat height = title_bar_and_tool_bar_height(window); debug_rendering("titlebar_height used for translucent titlebar view: %f\n", height); NSView *bgView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, titlebarContainer.bounds.size.width, height)]; @@ -3300,7 +3301,9 @@ set_title_bar_background(NSWindow *window, NSColor *backgroundColor) { bgView.wantsLayer = YES; bgView.layer.backgroundColor = backgroundColor.CGColor; bgView.identifier = tag; - [contentView addSubview:bgView]; + // position the background view above the content view but below the titlebar view + [titlebarContainer addSubview:bgView positioned:NSWindowAbove relativeTo:contentView]; + // for (NSView *subview in titlebarContainer.subviews) NSLog(@"sv: %@", subview.identifier); [NSLayoutConstraint activateConstraints:@[ // Pin to the top of the content view. [bgView.topAnchor constraintEqualToAnchor:titlebarContainer.topAnchor], @@ -3320,18 +3323,20 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us if (window->ns.layer_shell.is_active) return; const bool is_transparent = _glfwPlatformFramebufferTransparent(window); if (!is_transparent) { background_opacity = 1.0; background_blur = 0; } - NSColor *background = nil; + NSColor *window_background = [NSColor windowBackgroundColor]; + if (background_opacity < 1.0) { + // use a clear color (fully transparent) so that the final color is just the color from the surface. + // prevent blurring of shadows at window corners with desktop background by setting a low alpha background + window_background = background_blur > 0 ? [NSColor colorWithWhite: 0 alpha: 0.001f] : [NSColor clearColor]; + } NSAppearance *appearance = nil; bool titlebar_transparent = false; + NSColor *titlebar_color = nil; const NSWindowStyleMask current_style_mask = [window->ns.object styleMask]; const bool in_fullscreen = ((current_style_mask & NSWindowStyleMaskFullScreen) != 0) || window->ns.in_traditional_fullscreen; NSAppearance *light_appearance = is_transparent ? [NSAppearance appearanceNamed:NSAppearanceNameVibrantLight] : [NSAppearance appearanceNamed:NSAppearanceNameAqua]; NSAppearance *dark_appearance = is_transparent ? [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark] : [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]; if (use_system_color) { - if (is_transparent) { - // prevent blurring of shadows at window corners with desktop background by setting a low alpha background - background = background_blur > 0 ? [NSColor colorWithWhite: 0 alpha: 0.001f] : [NSColor clearColor]; - } else background = [NSColor windowBackgroundColor]; switch (system_color) { case 1: appearance = light_appearance; break; @@ -3339,17 +3344,15 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us appearance = dark_appearance; break; } } else { - // set a background color and make the title bar transparent so the background color is visible double red = ((color >> 16) & 0xFF) / 255.0; double green = ((color >> 8) & 0xFF) / 255.0; double blue = (color & 0xFF) / 255.0; double luma = 0.2126 * red + 0.7152 * green + 0.0722 * blue; - CGFloat alpha = background_opacity < 1.0 ? background_opacity : 1.0; - background = [NSColor colorWithSRGBRed:red green:green blue:blue alpha:alpha]; appearance = luma < 0.5 ? dark_appearance : light_appearance; + titlebar_color = [NSColor colorWithSRGBRed:red green:green blue:blue alpha:background_opacity]; titlebar_transparent = true; } - [window->ns.object setBackgroundColor:background]; + [window->ns.object setBackgroundColor:window_background]; [window->ns.object setAppearance:appearance]; _glfwPlatformSetWindowBlur(window, background_blur); bool has_shadow = false; @@ -3395,12 +3398,13 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us debug( "Window Chrome state:\n\tbackground: %s\n\tappearance: %s color_space: %s\n\t" "blur: %d has_shadow: %d resizable: %d decorations: %s (%d)\n\t" - "titlebar_transparent: %d title_visibility: %d hidden: %d buttons_hidden: %d" + "titlebar_transparent: %d titlebar_color: %s title_visibility: %d hidden: %d buttons_hidden: %d" "\n", - background ? [background.description UTF8String] : "", + window_background ? [window_background.description UTF8String] : "", appearance ? [appearance.name UTF8String] : "", cs ? (cs.localizedName ? [cs.localizedName UTF8String] : [cs.description UTF8String]) : "", background_blur, has_shadow, resizable, decorations_desc, window->decorated, titlebar_transparent, + titlebar_color ? [titlebar_color.description UTF8String] : "", show_text_in_titlebar, window->ns.titlebar_hidden, hide_titlebar_buttons ); [window->ns.object setColorSpace:cs]; @@ -3416,8 +3420,8 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us } else { [window->ns.object setStyleMask:window->ns.pre_full_screen_style_mask | fsmask]; } - if (background_opacity < 1.0 && !window->ns.titlebar_hidden && window->decorated) { - set_title_bar_background(window->ns.object, [background colorUsingColorSpace:(cs ? cs : [NSColorSpace deviceRGBColorSpace])]); + if (background_opacity < 1.0 && !window->ns.titlebar_hidden && window->decorated && titlebar_color != nil) { + set_title_bar_background(window->ns.object, titlebar_color); } else clear_title_bar_background_views(window->ns.object); // HACK: Changing the style mask can cause the first responder to be cleared [window->ns.object makeFirstResponder:window->ns.view];