From 6beded7b49264c509514bf2cc3b751e9b112b86e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 18 Aug 2025 14:45:18 +0530 Subject: [PATCH] Cleanup previous PR --- docs/changelog.rst | 4 +++ glfw/cocoa_window.m | 64 +++++++++++++++++++++++++++++++-------------- kitty/state.c | 1 + 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 54a81bf22..aee54b795 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -122,6 +122,10 @@ Detailed list of changes - New support for creating and switching to :doc:`sessions` easily, allowing users to define and use sessions/projects efficiently +- macOS: Allow the window title bar to be semi-transparent when + :opt:`background_opacity` is less than one and :opt:`macos_titlebar_color` is + set to ``background`` (:pull:`8906`) + - A new :opt:`cursor_trail_color` setting to independently control the color of cursor trails (:pull:`8830`) diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index d27ec2706..bd606d739 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -3168,34 +3168,60 @@ GLFWAPI GLFWcocoarenderframefun glfwCocoaSetWindowResizeCallback(GLFWwindow *w, return current; } -static void setTitlebarBackgroundColor(NSWindow *window, NSColor *backgroundColor) { - if (!window) return; +@implementation NSView (FindByIdentifier) - NSView *contentView = window.contentView; - NSView *titlebarContainer = contentView.superview; +- (NSArray *)viewsWithIdentifier:(NSUserInterfaceItemIdentifier)identifier { + NSMutableArray *result = [NSMutableArray array]; + if ([self.identifier isEqual:identifier]) { + [result addObject:self]; + } + for (NSView *sub in self.subviews) { + [result addObjectsFromArray:[sub viewsWithIdentifier:identifier]]; + } + return result; +} + +@end + +static CGFloat +title_bar_and_tool_bar_height(NSWindow *window) { + NSRect frame = window.frame; + NSRect content = [window contentRectForFrameRect:frame]; + return NSHeight(frame) - NSHeight(content); +} + +static +void clear_title_bar_background_views(NSWindow *window) { +#define tag @"kitty-for-transparent-titlebar" + 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) { + NSView *contentView = window.contentView, *titlebarContainer = contentView ? contentView.superview : nil; if (!titlebarContainer) return; + for (NSView *subview in [titlebarContainer viewsWithIdentifier:tag]) [subview removeFromSuperview]; + if (!backgroundColor) return; - NSMutableArray *toRemove = [NSMutableArray array]; - for (NSView *subview in titlebarContainer.subviews) { - if ([subview isKindOfClass:NSClassFromString(@"NSVisualEffectView")]) { - [toRemove addObject:subview]; - } - } - for (NSView *subview in toRemove) { - [subview removeFromSuperview]; - } - - NSView *bgView = - [[NSView alloc] initWithFrame:NSMakeRect(0, titlebarContainer.bounds.size.height - 28, - titlebarContainer.bounds.size.width, 28)]; + const CGFloat height = title_bar_and_tool_bar_height(window); + NSView *bgView = [[NSView alloc] initWithFrame:NSMakeRect( + 0, titlebarContainer.bounds.size.height - height, titlebarContainer.bounds.size.width, height)]; bgView.autoresizingMask = NSViewWidthSizable | NSViewMinYMargin; bgView.wantsLayer = YES; bgView.layer.backgroundColor = backgroundColor.CGColor; + bgView.identifier = tag; NSView *containerView = [[NSView alloc] initWithFrame:window.contentView.bounds]; containerView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + containerView.identifier = tag; [containerView addSubview:bgView]; + [bgView release]; [window.contentView addSubview:containerView]; + [containerView release]; +#undef tag } GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool use_system_color, unsigned int system_color, int background_blur, unsigned int hide_window_decorations, bool show_text_in_titlebar, int color_space, float background_opacity, bool resizable) { @autoreleasepool { @@ -3291,8 +3317,8 @@ GLFWAPI void glfwCocoaSetWindowChrome(GLFWwindow *w, unsigned int color, bool us [[window->ns.object standardWindowButton: NSWindowMiniaturizeButton] setHidden:hide_titlebar_buttons]; [[window->ns.object standardWindowButton: NSWindowZoomButton] setHidden:hide_titlebar_buttons]; if (background_opacity < 1.0 && !window->ns.titlebar_hidden && window->decorated) { - setTitlebarBackgroundColor(window->ns.object, [background colorUsingColorSpace:cs]); - } + set_title_bar_background(window->ns.object, [background colorUsingColorSpace:(cs ? cs : [NSColorSpace deviceRGBColorSpace])]); + } else clear_title_bar_background_views(window->ns.object); // Apple throws a hissy fit if one attempts to clear the value of NSWindowStyleMaskFullScreen outside of a full screen transition // event. See https://github.com/kovidgoyal/kitty/issues/7106 NSWindowStyleMask fsmask = current_style_mask & NSWindowStyleMaskFullScreen; diff --git a/kitty/state.c b/kitty/state.c index 34c86a200..690d46011 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -960,6 +960,7 @@ PYWRAP1(change_background_opacity) { WITH_OS_WINDOW(os_window_id) os_window->background_opacity = opacity; if (!os_window->redraw_count) os_window->redraw_count++; + set_os_window_chrome(os_window); // on macOS titlebar opacity can depend on background_opacity Py_RETURN_TRUE; END_WITH_OS_WINDOW Py_RETURN_FALSE;