From eef9664ef831c8fb3a0b259a2325cef01a774e23 Mon Sep 17 00:00:00 2001 From: Gregory Anders Date: Thu, 26 Dec 2024 18:51:59 -0600 Subject: [PATCH] renderer: track if fg/bg/cursor color is explicitly set by an OSC The renderer must track if the foreground, background, and cursor colors are explicitly set by an OSC so that changes are not overridden when the config file is reloaded. --- src/renderer/Metal.zig | 104 ++++++++++++++++++++++------------ src/renderer/OpenGL.zig | 104 ++++++++++++++++++++++------------ src/renderer/message.zig | 10 ++-- src/termio/stream_handler.zig | 12 ++-- 4 files changed, 148 insertions(+), 82 deletions(-) diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 3f24c3d2d..f45e93b32 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -76,18 +76,30 @@ size: renderer.Size, /// True if the window is focused focused: bool, -/// The actual foreground color. May differ from the config foreground color if -/// changed by a terminal application -foreground_color: terminal.color.RGB, +/// The foreground color set by an OSC 10 sequence. If unset then +/// default_foreground_color is used. +foreground_color: ?terminal.color.RGB, -/// The actual background color. May differ from the config background color if -/// changed by a terminal application -background_color: terminal.color.RGB, +/// Foreground color set in the user's config file. +default_foreground_color: terminal.color.RGB, -/// The actual cursor color. May differ from the config cursor color if changed -/// by a terminal application +/// The background color set by an OSC 11 sequence. If unset then +/// default_background_color is used. +background_color: ?terminal.color.RGB, + +/// Background color set in the user's config file. +default_background_color: terminal.color.RGB, + +/// The cursor color set by an OSC 12 sequence. If unset then +/// default_cursor_color is used. cursor_color: ?terminal.color.RGB, +/// Default cursor color when no color is set explicitly by an OSC 12 command. +/// This is cursor color as set in the user's config, if any. If no cursor color +/// is set in the user's config, then the cursor color is determined by the +/// current foreground color. +default_cursor_color: ?terminal.color.RGB, + /// When `cursor_color` is null, swap the foreground and background colors of /// the cell under the cursor for the cursor color. Otherwise, use the default /// foreground color as the cursor color. @@ -629,9 +641,12 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal { .grid_metrics = font_critical.metrics, .size = options.size, .focused = true, - .foreground_color = options.config.foreground, - .background_color = options.config.background, - .cursor_color = options.config.cursor_color, + .foreground_color = null, + .default_foreground_color = options.config.foreground, + .background_color = null, + .default_background_color = options.config.background, + .cursor_color = null, + .default_cursor_color = options.config.cursor_color, .cursor_invert = options.config.cursor_invert, .current_background_color = options.config.background, @@ -919,15 +934,34 @@ pub fn updateFrame( } // Swap bg/fg if the terminal is reversed - const bg = self.background_color; - const fg = self.foreground_color; + const bg = self.background_color orelse self.default_background_color; + const fg = self.foreground_color orelse self.default_foreground_color; defer { - self.background_color = bg; - self.foreground_color = fg; + if (self.background_color) |*c| { + c.* = bg; + } else { + self.default_background_color = bg; + } + + if (self.foreground_color) |*c| { + c.* = fg; + } else { + self.default_foreground_color = fg; + } } + if (state.terminal.modes.get(.reverse_colors)) { - self.background_color = fg; - self.foreground_color = bg; + if (self.background_color) |*c| { + c.* = fg; + } else { + self.default_background_color = fg; + } + + if (self.foreground_color) |*c| { + c.* = bg; + } else { + self.default_foreground_color = bg; + } } // If our terminal screen size doesn't match our expected renderer @@ -1029,7 +1063,7 @@ pub fn updateFrame( } break :critical .{ - .bg = self.background_color, + .bg = self.background_color orelse self.default_background_color, .screen = screen_copy, .screen_type = state.terminal.active_screen, .mouse = state.mouse, @@ -1957,10 +1991,10 @@ pub fn changeConfig(self: *Metal, config: *DerivedConfig) !void { self.uniforms.min_contrast = config.min_contrast; // Set our new colors - self.background_color = config.background; - self.foreground_color = config.foreground; + self.default_background_color = config.background; + self.default_foreground_color = config.foreground; + self.default_cursor_color = if (!config.cursor_invert) config.cursor_color else null; self.cursor_invert = config.cursor_invert; - self.cursor_color = if (!config.cursor_invert) config.cursor_color else null; self.config.deinit(); self.config = config.*; @@ -2246,12 +2280,12 @@ fn rebuildCells( .extend => if (y == 0) { self.uniforms.padding_extend.up = !row.neverExtendBg( color_palette, - self.background_color, + self.background_color orelse self.default_background_color, ); } else if (y == self.cells.size.rows - 1) { self.uniforms.padding_extend.down = !row.neverExtendBg( color_palette, - self.background_color, + self.background_color orelse self.default_background_color, ); }, } @@ -2360,7 +2394,7 @@ fn rebuildCells( false; const bg_style = style.bg(cell, color_palette); - const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color; + const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color; // The final background color for the cell. const bg = bg: { @@ -2380,7 +2414,7 @@ fn rebuildCells( // If we don't have invert selection fg/bg set then we // just use the selection background if set, otherwise // the default fg color. - break :bg self.config.selection_background orelse self.foreground_color; + break :bg self.config.selection_background orelse self.foreground_color orelse self.default_foreground_color; } // Not selected @@ -2402,7 +2436,7 @@ fn rebuildCells( // If we don't have invert selection fg/bg set // then we just use the selection foreground if // set, otherwise the default bg color. - break :fg self.config.selection_foreground orelse self.background_color; + break :fg self.config.selection_foreground orelse self.background_color orelse self.default_background_color; } // Whether we need to use the bg color as our fg color: @@ -2411,7 +2445,7 @@ fn rebuildCells( // Note: if selected then invert sel fg / bg must be // false since we separately handle it if true above. break :fg if (style.flags.inverse != selected) - bg_style orelse self.background_color + bg_style orelse self.background_color orelse self.default_background_color else fg_style; }; @@ -2438,7 +2472,7 @@ fn rebuildCells( // If we have a background and its not the default background // then we apply background opacity - if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color)) { + if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color orelse self.default_background_color)) { break :bg_alpha default; } @@ -2601,12 +2635,12 @@ fn rebuildCells( // Prepare the cursor cell contents. const style = cursor_style_ orelse break :cursor; - const cursor_color = self.cursor_color orelse color: { + const cursor_color = self.cursor_color orelse self.default_cursor_color orelse color: { if (self.cursor_invert) { const sty = screen.cursor.page_pin.style(screen.cursor.page_cell); - break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color; + break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color; } else { - break :color self.foreground_color; + break :color self.foreground_color orelse self.default_foreground_color; } }; @@ -2634,11 +2668,11 @@ fn rebuildCells( const uniform_color = if (self.cursor_invert) blk: { const sty = screen.cursor.page_pin.style(screen.cursor.page_cell); - break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color; + break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color; } else if (self.config.cursor_text) |txt| txt else - self.background_color; + self.background_color orelse self.default_background_color; self.uniforms.cursor_color = .{ uniform_color.r, @@ -2928,8 +2962,8 @@ fn addPreeditCell( coord: terminal.Coordinate, ) !void { // Preedit is rendered inverted - const bg = self.foreground_color; - const fg = self.background_color; + const bg = self.foreground_color orelse self.default_foreground_color; + const fg = self.background_color orelse self.default_background_color; // Render the glyph for our preedit text const render_ = self.font_grid.renderCodepoint( diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 19843062c..ccd8b33da 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -89,18 +89,30 @@ texture_color_resized: usize = 0, /// True if the window is focused focused: bool, -/// The actual foreground color. May differ from the config foreground color if -/// changed by a terminal application -foreground_color: terminal.color.RGB, +/// The foreground color set by an OSC 10 sequence. If unset then the default +/// value from the config file is used. +foreground_color: ?terminal.color.RGB, -/// The actual background color. May differ from the config background color if -/// changed by a terminal application -background_color: terminal.color.RGB, +/// Foreground color set in the user's config file. +default_foreground_color: terminal.color.RGB, -/// The actual cursor color. May differ from the config cursor color if changed -/// by a terminal application +/// The background color set by an OSC 11 sequence. If unset then the default +/// value from the config file is used. +background_color: ?terminal.color.RGB, + +/// Background color set in the user's config file. +default_background_color: terminal.color.RGB, + +/// The cursor color set by an OSC 12 sequence. If unset then +/// default_cursor_color is used. cursor_color: ?terminal.color.RGB, +/// Default cursor color when no color is set explicitly by an OSC 12 command. +/// This is cursor color as set in the user's config, if any. If no cursor color +/// is set in the user's config, then the cursor color is determined by the +/// current foreground color. +default_cursor_color: ?terminal.color.RGB, + /// When `cursor_color` is null, swap the foreground and background colors of /// the cell under the cursor for the cursor color. Otherwise, use the default /// foreground color as the cursor color. @@ -386,9 +398,12 @@ pub fn init(alloc: Allocator, options: renderer.Options) !OpenGL { .font_shaper_cache = font.ShaperCache.init(), .draw_background = options.config.background, .focused = true, - .foreground_color = options.config.foreground, - .background_color = options.config.background, - .cursor_color = options.config.cursor_color, + .foreground_color = null, + .default_foreground_color = options.config.foreground, + .background_color = null, + .default_background_color = options.config.background, + .cursor_color = null, + .default_cursor_color = options.config.cursor_color, .cursor_invert = options.config.cursor_invert, .surface_mailbox = options.surface_mailbox, .deferred_font_size = .{ .metrics = grid.metrics }, @@ -701,15 +716,34 @@ pub fn updateFrame( } // Swap bg/fg if the terminal is reversed - const bg = self.background_color; - const fg = self.foreground_color; + const bg = self.background_color orelse self.default_background_color; + const fg = self.foreground_color orelse self.default_foreground_color; defer { - self.background_color = bg; - self.foreground_color = fg; + if (self.background_color) |*c| { + c.* = bg; + } else { + self.default_background_color = bg; + } + + if (self.foreground_color) |*c| { + c.* = fg; + } else { + self.default_foreground_color = fg; + } } + if (state.terminal.modes.get(.reverse_colors)) { - self.background_color = fg; - self.foreground_color = bg; + if (self.background_color) |*c| { + c.* = fg; + } else { + self.default_background_color = fg; + } + + if (self.foreground_color) |*c| { + c.* = bg; + } else { + self.default_foreground_color = bg; + } } // If our terminal screen size doesn't match our expected renderer @@ -820,7 +854,7 @@ pub fn updateFrame( break :critical .{ .full_rebuild = full_rebuild, - .gl_bg = self.background_color, + .gl_bg = self.background_color orelse self.default_background_color, .screen = screen_copy, .screen_type = state.terminal.active_screen, .mouse = state.mouse, @@ -1298,12 +1332,12 @@ pub fn rebuildCells( .extend => if (y == 0) { self.padding_extend_top = !row.neverExtendBg( color_palette, - self.background_color, + self.background_color orelse self.default_background_color, ); } else if (y == self.size.grid().rows - 1) { self.padding_extend_bottom = !row.neverExtendBg( color_palette, - self.background_color, + self.background_color orelse self.default_background_color, ); }, } @@ -1412,7 +1446,7 @@ pub fn rebuildCells( false; const bg_style = style.bg(cell, color_palette); - const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color; + const fg_style = style.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color; // The final background color for the cell. const bg = bg: { @@ -1432,7 +1466,7 @@ pub fn rebuildCells( // If we don't have invert selection fg/bg set then we // just use the selection background if set, otherwise // the default fg color. - break :bg self.config.selection_background orelse self.foreground_color; + break :bg self.config.selection_background orelse self.foreground_color orelse self.default_foreground_color; } // Not selected @@ -1454,7 +1488,7 @@ pub fn rebuildCells( // If we don't have invert selection fg/bg set // then we just use the selection foreground if // set, otherwise the default bg color. - break :fg self.config.selection_foreground orelse self.background_color; + break :fg self.config.selection_foreground orelse self.background_color orelse self.default_background_color; } // Whether we need to use the bg color as our fg color: @@ -1463,7 +1497,7 @@ pub fn rebuildCells( // Note: if selected then invert sel fg / bg must be // false since we separately handle it if true above. break :fg if (style.flags.inverse != selected) - bg_style orelse self.background_color + bg_style orelse self.background_color orelse self.default_background_color else fg_style; }; @@ -1490,7 +1524,7 @@ pub fn rebuildCells( // If we have a background and its not the default background // then we apply background opacity - if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color)) { + if (style.bg(cell, color_palette) != null and !rgb.eql(self.background_color orelse self.default_background_color)) { break :bg_alpha default; } @@ -1699,12 +1733,12 @@ pub fn rebuildCells( break :cursor_style; } - const cursor_color = self.cursor_color orelse color: { + const cursor_color = self.cursor_color orelse self.default_cursor_color orelse color: { if (self.cursor_invert) { const sty = screen.cursor.page_pin.style(screen.cursor.page_cell); - break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color; + break :color sty.fg(color_palette, self.config.bold_is_bright) orelse self.foreground_color orelse self.default_foreground_color; } else { - break :color self.foreground_color; + break :color self.foreground_color orelse self.default_foreground_color; } }; @@ -1713,11 +1747,11 @@ pub fn rebuildCells( if (cell.mode.isFg() and cell.mode != .fg_color) { const cell_color = if (self.cursor_invert) blk: { const sty = screen.cursor.page_pin.style(screen.cursor.page_cell); - break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color; + break :blk sty.bg(screen.cursor.page_cell, color_palette) orelse self.background_color orelse self.default_background_color; } else if (self.config.cursor_text) |txt| txt else - self.background_color; + self.background_color orelse self.default_background_color; cell.r = cell_color.r; cell.g = cell_color.g; @@ -1742,8 +1776,8 @@ fn addPreeditCell( y: usize, ) !void { // Preedit is rendered inverted - const bg = self.foreground_color; - const fg = self.background_color; + const bg = self.foreground_color orelse self.default_foreground_color; + const fg = self.background_color orelse self.default_background_color; // Render the glyph for our preedit text const render_ = self.font_grid.renderCodepoint( @@ -2122,10 +2156,10 @@ pub fn changeConfig(self: *OpenGL, config: *DerivedConfig) !void { self.font_shaper_cache = font_shaper_cache; // Set our new colors - self.background_color = config.background; - self.foreground_color = config.foreground; + self.default_background_color = config.background; + self.default_foreground_color = config.foreground; + self.default_cursor_color = if (!config.cursor_invert) config.cursor_color else null; self.cursor_invert = config.cursor_invert; - self.cursor_color = if (!config.cursor_invert) config.cursor_color else null; // Update our uniforms self.deferred_config = .{}; diff --git a/src/renderer/message.zig b/src/renderer/message.zig index b420e554e..d6255661f 100644 --- a/src/renderer/message.zig +++ b/src/renderer/message.zig @@ -42,13 +42,11 @@ pub const Message = union(enum) { old_key: font.SharedGridSet.Key, }, - /// Change the foreground color. This can be done separately from changing - /// the config file in response to an OSC 10 command. - foreground_color: terminal.color.RGB, + /// Change the foreground color as set by an OSC 10 command, if any. + foreground_color: ?terminal.color.RGB, - /// Change the background color. This can be done separately from changing - /// the config file in response to an OSC 11 command. - background_color: terminal.color.RGB, + /// Change the background color as set by an OSC 11 command, if any. + background_color: ?terminal.color.RGB, /// Change the cursor color. This can be done separately from changing the /// config file in response to an OSC 12 command. diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 64915f704..849e5c107 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -1347,7 +1347,7 @@ pub const StreamHandler = struct { .foreground => { self.foreground_color = null; _ = self.renderer_mailbox.push(.{ - .foreground_color = self.default_foreground_color, + .foreground_color = self.foreground_color, }, .{ .forever = {} }); self.surfaceMessageWriter(.{ .color_change = .{ @@ -1358,7 +1358,7 @@ pub const StreamHandler = struct { .background => { self.background_color = null; _ = self.renderer_mailbox.push(.{ - .background_color = self.default_background_color, + .background_color = self.background_color, }, .{ .forever = {} }); self.surfaceMessageWriter(.{ .color_change = .{ @@ -1370,7 +1370,7 @@ pub const StreamHandler = struct { self.cursor_color = null; _ = self.renderer_mailbox.push(.{ - .cursor_color = self.default_cursor_color, + .cursor_color = self.cursor_color, }, .{ .forever = {} }); if (self.default_cursor_color) |color| { @@ -1490,15 +1490,15 @@ pub const StreamHandler = struct { const msg: renderer.Message = switch (special) { .foreground => msg: { self.foreground_color = null; - break :msg .{ .foreground_color = self.default_foreground_color }; + break :msg .{ .foreground_color = self.foreground_color }; }, .background => msg: { self.background_color = null; - break :msg .{ .background_color = self.default_background_color }; + break :msg .{ .background_color = self.background_color }; }, .cursor => msg: { self.cursor_color = null; - break :msg .{ .cursor_color = self.default_cursor_color }; + break :msg .{ .cursor_color = self.cursor_color }; }, else => { log.warn(