diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index 155702296..16febf779 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -852,45 +852,72 @@ fn syncActionAccelerator( } fn loadRuntimeCss(config: *const Config, provider: *c.GtkCssProvider) !void { + var buf: [4096]u8 = undefined; + var fbs = std.io.fixedBufferStream(&buf); + const writer = fbs.writer(); + + const window_theme = config.@"window-theme"; const unfocused_fill: Config.Color = config.@"unfocused-split-fill" orelse config.background; const headerbar_background = config.background; const headerbar_foreground = config.foreground; - const fmt = + try writer.print( \\widget.unfocused-split {{ \\ opacity: {d:.2}; \\ background-color: rgb({d},{d},{d}); \\}} - \\window.window-theme-ghostty .top-bar, - \\window.window-theme-ghostty .bottom-bar, - \\window.window-theme-ghostty box > tabbar {{ - \\ background-color: rgb({d},{d},{d}); - \\ color: rgb({d},{d},{d}); - \\}} - ; - // The length required is always less than the length of the pre-formatted string: - // -> '{d:.2}' gets replaced with max 4 bytes (0.00) - // -> each {d} could be replaced with max 3 bytes - var css_buf: [fmt.len]u8 = undefined; + , .{ + 1.0 - config.@"unfocused-split-opacity", + unfocused_fill.r, + unfocused_fill.g, + unfocused_fill.b, + }); + + // this is specifically a runtime-only check + if (version.atLeast(4, 16, 0)) { + switch (window_theme) { + .ghostty => try writer.print( + \\:root {{ + \\ --headerbar-fg-color: rgb({d},{d},{d}); + \\ --headerbar-bg-color: rgb({d},{d},{d}); + \\ --headerbar-backdrop-color: oklab(from var(--headerbar-bg-color) calc(l * 0.9) a b / alpha); + \\}} + , + .{ + headerbar_foreground.r, + headerbar_foreground.g, + headerbar_foreground.b, + headerbar_background.r, + headerbar_background.g, + headerbar_background.b, + }, + ), + else => {}, + } + } else { + try writer.print( + \\window.window-theme-ghostty .top-bar, + \\window.window-theme-ghostty .bottom-bar, + \\window.window-theme-ghostty box > tabbar {{ + \\ background-color: rgb({d},{d},{d}); + \\ color: rgb({d},{d},{d}); + \\}} + , + .{ + headerbar_background.r, + headerbar_background.g, + headerbar_background.b, + headerbar_foreground.r, + headerbar_foreground.g, + headerbar_foreground.b, + }, + ); + } + + const css = fbs.getWritten(); - const css = try std.fmt.bufPrintZ( - &css_buf, - fmt, - .{ - 1.0 - config.@"unfocused-split-opacity", - unfocused_fill.r, - unfocused_fill.g, - unfocused_fill.b, - headerbar_background.r, - headerbar_background.g, - headerbar_background.b, - headerbar_foreground.r, - headerbar_foreground.g, - headerbar_foreground.b, - }, - ); // Clears any previously loaded CSS from this provider - c.gtk_css_provider_load_from_data(provider, css, @intCast(css.len)); + c.gtk_css_provider_load_from_data(provider, css.ptr, @intCast(css.len)); } /// Called by CoreApp to wake up the event loop. diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 9f5bc0bad..14bb68b8e 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -23,6 +23,7 @@ const c = @import("c.zig").c; const adwaita = @import("adwaita.zig"); const gtk_key = @import("key.zig"); const Notebook = @import("notebook.zig").Notebook; +const version = @import("version.zig"); const log = std.log.scoped(.gtk); @@ -108,8 +109,9 @@ pub fn init(self: *Window, app: *App) !void { c.gtk_window_set_icon_name(gtk_window, "com.mitchellh.ghostty"); - // Apply class to color headerbar if window-theme is set to `ghostty`. - if (app.config.@"window-theme" == .ghostty) { + // Apply class to color headerbar if window-theme is set to `ghostty` and + // GTK version is before 4.16. + if (!version.atLeast(4, 16, 0) and app.config.@"window-theme" == .ghostty) { c.gtk_widget_add_css_class(@ptrCast(gtk_window), "window-theme-ghostty"); }