diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index e6bf24bd1..1f4d8bf54 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -473,6 +473,7 @@ pub fn performAction( .toggle_tab_overview => self.toggleTabOverview(target), .toggle_window_decorations => self.toggleWindowDecorations(target), .quit_timer => self.quitTimer(value), + .color_change => try self.colorChange(target, value), // Unimplemented .close_all_windows, @@ -485,7 +486,6 @@ pub fn performAction( .key_sequence, .render_inspector, .renderer_health, - .color_change, => log.warn("unimplemented action={}", .{action}), } } @@ -797,6 +797,17 @@ fn showDesktopNotification( c.g_application_send_notification(g_app, n.body.ptr, notification); } +fn colorChange( + _: *App, + target: apprt.Target, + value: apprt.action.ColorChange, +) !void { + switch (target) { + .app => {}, + .surface => |v| try v.rt_surface.colorChange(value), + } +} + /// Reload the configuration. This should return the new configuration. /// The old value can be freed immediately at this point assuming a /// successful return. @@ -898,6 +909,25 @@ fn loadRuntimeCss( alloc: Allocator, config: *const Config, provider: *c.GtkCssProvider, +) Allocator.Error!void { + const headerbar_background = config.background; + const headerbar_foreground = config.foreground; + + return loadRuntimeCssRGB( + alloc, + config, + provider, + headerbar_background, + headerbar_foreground, + ); +} + +fn loadRuntimeCssRGB( + alloc: Allocator, + config: *const Config, + provider: *c.GtkCssProvider, + background_color: Config.Color, + foreground_color: Config.Color, ) Allocator.Error!void { var stack_alloc = std.heap.stackFallback(4096, alloc); var buf = std.ArrayList(u8).init(stack_alloc.get()); @@ -906,8 +936,8 @@ fn loadRuntimeCss( 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 headerbar_background = background_color; + const headerbar_foreground = foreground_color; try writer.print( \\widget.unfocused-split {{ @@ -972,6 +1002,28 @@ fn loadRuntimeCss( ); } +/// Call this anytime the color scheme changes. +pub fn syncColorChanges( + self: *App, + background_color: ?Config.Color, + foreground_color: ?Config.Color, +) !void { + // 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. + loadRuntimeCssRGB( + self.core_app.alloc, + &self.config, + self.css_provider, + background_color orelse self.config.background, + foreground_color orelse self.config.foreground, + ) catch |err| switch (err) { + error.OutOfMemory => log.warn( + "out of memory loading runtime CSS, no runtime CSS applied", + .{}, + ), + }; +} + /// Called by CoreApp to wake up the event loop. pub fn wakeup(self: App) void { _ = self; diff --git a/src/apprt/gtk/Surface.zig b/src/apprt/gtk/Surface.zig index 9c7a394f4..1a727db84 100644 --- a/src/apprt/gtk/Surface.zig +++ b/src/apprt/gtk/Surface.zig @@ -5,7 +5,7 @@ const Surface = @This(); const std = @import("std"); const Allocator = std.mem.Allocator; -const configpkg = @import("../../config.zig"); +const Config = @import("../../config.zig").Config; const apprt = @import("../../apprt.zig"); const font = @import("../../font/main.zig"); const input = @import("../../input.zig"); @@ -342,6 +342,12 @@ cursor: ?*c.GdkCursor = null, /// pass it to GTK. title_text: ?[:0]const u8 = null, +/// Local background color override. +background_color: ?Config.Color = null, + +/// Local foreground color override. +foreground_color: ?Config.Color = null, + /// The core surface backing this surface core_surface: CoreSurface, @@ -837,6 +843,32 @@ pub fn getTitle(self: *Surface) ?[:0]const u8 { return self.title_text; } +fn updateStyle(self: *Surface) !void { + // If we have no style, then we have nothing to update. + if (self.background_color == null and self.foreground_color == null) return; + + try self.app.syncColorChanges(self.background_color, self.foreground_color); +} + +pub fn colorChange(self: *Surface, value: apprt.action.ColorChange) !void { + const color: Config.Color = .{ + .r = value.r, + .g = value.g, + .b = value.b, + }; + switch (value.kind) { + .background => { + self.background_color = color; + try self.updateStyle(); + }, + .foreground => { + self.foreground_color = color; + try self.updateStyle(); + }, + else => {}, + } +} + pub fn setMouseShape( self: *Surface, shape: terminal.MouseShape,