gtk: use CSS variables and color calcs introduced in 4.16

This takes advantage of CSS variables and color expressions to improve
the `window-theme=ghostty` support. The only visibile difference from
the previous implementation is that the header bar will darken if the
Ghostty window is in the background, which is standard for GTK apps.

This is conditional at runtime. If Ghostty detects that you're running
against GTK 4.16 or newer it will use the CSS variables and color calcs.
If you're running against older versions it will use CSS classes to
achieve nearly the same effect.
This commit is contained in:
Jeffrey C. Ollie
2024-10-14 18:24:05 -05:00
parent 9f50ed07a5
commit ca42b4ca1c
2 changed files with 60 additions and 31 deletions

View File

@ -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.

View File

@ -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");
}