Merge pull request #2440 from jcollie/window-theme-ghostty-4-16

gtk: use CSS variables and color calcs introduced in 4.16
This commit is contained in:
Mitchell Hashimoto
2024-10-16 06:24:19 -07:00
committed by GitHub
2 changed files with 74 additions and 28 deletions

View File

@ -12,6 +12,7 @@ const App = @This();
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const builtin = @import("builtin");
const apprt = @import("../../apprt.zig");
const configpkg = @import("../../config.zig");
@ -390,7 +391,12 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
@ptrCast(css_provider),
c.GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 3,
);
try loadRuntimeCss(&config, css_provider);
loadRuntimeCss(core_app.alloc, &config, css_provider) catch |err| switch (err) {
error.OutOfMemory => log.warn(
"out of memory loading runtime CSS, no runtime CSS applied",
.{},
),
};
return .{
.core_app = core_app,
@ -793,7 +799,15 @@ pub fn reloadConfig(self: *App) !?*const Config {
fn syncConfigChanges(self: *App) !void {
try self.updateConfigErrors();
try self.syncActionAccelerators();
try loadRuntimeCss(&self.config, self.css_provider);
// Load our runtime CSS. If this fails then our window is just stuck
// with the old CSS but we don't want to fail the entire sync operation.
loadRuntimeCss(self.core_app.alloc, &self.config, self.css_provider) catch |err| switch (err) {
error.OutOfMemory => log.warn(
"out of memory loading runtime CSS, no runtime CSS applied",
.{},
),
};
}
/// This should be called whenever the configuration changes to update
@ -851,46 +865,75 @@ fn syncActionAccelerator(
);
}
fn loadRuntimeCss(config: *const Config, provider: *c.GtkCssProvider) !void {
fn loadRuntimeCss(
alloc: Allocator,
config: *const Config,
provider: *c.GtkCssProvider,
) Allocator.Error!void {
var stack_alloc = std.heap.stackFallback(4096, alloc);
var buf = std.ArrayList(u8).init(stack_alloc.get());
defer buf.deinit();
const writer = buf.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,
});
const css = try std.fmt.bufPrintZ(
&css_buf,
fmt,
.{
1.0 - config.@"unfocused-split-opacity",
unfocused_fill.r,
unfocused_fill.g,
unfocused_fill.b,
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,
},
);
});
}
// 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,
buf.items.ptr,
@intCast(buf.items.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,10 @@ 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. The conditional is because above 4.16
// we use GTK CSS color variables.
if (!version.atLeast(4, 16, 0) and app.config.@"window-theme" == .ghostty) {
c.gtk_widget_add_css_class(@ptrCast(gtk_window), "window-theme-ghostty");
}