From 1c6adf4065ccc019aa803dbf53c732097cacff49 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 22 Nov 2024 13:10:32 -0800 Subject: [PATCH] mode 2031 should send updates on any color palette change Related #2755 From the mode 2031 spec[1]: > Send CSI ? 2031 h to the terminal to enable unsolicited DSR (device status > report) messages for color palette updates and CSI ? 2031 l respectively to > disable it again. > > The sent out DSR looks equivalent to the already above mentioned. This > notification is not just sent when dark/light mode has been changed by the > operating system / desktop, but also if the user explicitly changed color > scheme, e.g. by configuration. My reading of this paired with the original discussion is that this is meant to be sent out for anything that could possibly change terminal colors. Previous to this commit, we only sent out the DSR when the actual system light/dark mode changed. This commit changes it to send out the DSR on any operation that _may_ change the terminal colors. [1]: https://contour-terminal.org/vt-extensions/color-palette-update-notifications/#example-source-code --- src/Surface.zig | 58 +++++++++++++++++++++-------------- src/apprt/surface.zig | 6 ++-- src/termio/stream_handler.zig | 8 ++++- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index ee2fe1ac5..ae38b8ba2 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -820,21 +820,28 @@ pub fn handleMessage(self: *Surface, msg: Message) !void { }, .unlocked); }, - .color_change => |change| try self.rt_app.performAction( - .{ .surface = self }, - .color_change, - .{ - .kind = switch (change.kind) { - .background => .background, - .foreground => .foreground, - .cursor => .cursor, - .palette => |v| @enumFromInt(v), + .color_change => |change| { + // On any color change, we have to report for mode 2031 + // if it is enabled. + self.reportColorScheme(false); + + // Notify our apprt + try self.rt_app.performAction( + .{ .surface = self }, + .color_change, + .{ + .kind = switch (change.kind) { + .background => .background, + .foreground => .foreground, + .cursor => .cursor, + .palette => |v| @enumFromInt(v), + }, + .r = change.color.r, + .g = change.color.g, + .b = change.color.b, }, - .r = change.color.r, - .g = change.color.g, - .b = change.color.b, - }, - ), + ); + }, .set_mouse_shape => |shape| { log.debug("changing mouse shape: {}", .{shape}); @@ -898,7 +905,7 @@ pub fn handleMessage(self: *Surface, msg: Message) !void { .renderer_health => |health| self.updateRendererHealth(health), - .report_color_scheme => try self.reportColorScheme(), + .report_color_scheme => |force| self.reportColorScheme(force), .present_surface => try self.presentSurface(), @@ -935,8 +942,18 @@ fn passwordInput(self: *Surface, v: bool) !void { try self.queueRender(); } -/// Sends a DSR response for the current color scheme to the pty. -fn reportColorScheme(self: *Surface) !void { +/// Sends a DSR response for the current color scheme to the pty. If +/// force is false then we only send the response if the terminal mode +/// 2031 is enabled. +fn reportColorScheme(self: *Surface, force: bool) void { + if (!force) { + self.renderer_state.mutex.lock(); + defer self.renderer_state.mutex.unlock(); + if (!self.renderer_state.terminal.modes.get(.report_color_scheme)) { + return; + } + } + const output = switch (self.config_conditional_state.theme) { .light => "\x1B[?997;2n", .dark => "\x1B[?997;1n", @@ -3643,12 +3660,7 @@ pub fn colorSchemeCallback(self: *Surface, scheme: apprt.ColorScheme) !void { self.notifyConfigConditionalState(); // If mode 2031 is on, then we report the change live. - const report = report: { - self.renderer_state.mutex.lock(); - defer self.renderer_state.mutex.unlock(); - break :report self.renderer_state.terminal.modes.get(.report_color_scheme); - }; - if (report) try self.reportColorScheme(); + self.reportColorScheme(false); } pub fn posToViewport(self: Surface, xpos: f64, ypos: f64) terminal.point.Coordinate { diff --git a/src/apprt/surface.zig b/src/apprt/surface.zig index 58faa9633..f3fd71432 100644 --- a/src/apprt/surface.zig +++ b/src/apprt/surface.zig @@ -58,8 +58,10 @@ pub const Message = union(enum) { /// Health status change for the renderer. renderer_health: renderer.Health, - /// Report the color scheme - report_color_scheme: void, + /// Report the color scheme. The bool parameter is whether to force or not. + /// If force is true, the color scheme should be reported even if mode + /// 2031 is not set. + report_color_scheme: bool, /// Tell the surface to present itself to the user. This may require raising /// a window and switching tabs. diff --git a/src/termio/stream_handler.zig b/src/termio/stream_handler.zig index 37d176de3..4e82b5a19 100644 --- a/src/termio/stream_handler.zig +++ b/src/termio/stream_handler.zig @@ -126,6 +126,9 @@ pub const StreamHandler = struct { if (self.default_cursor) self.setCursorStyle(.default) catch |err| { log.warn("failed to set default cursor style: {}", .{err}); }; + + // The config could have changed any of our colors so update mode 2031 + self.surfaceMessageWriter(.{ .report_color_scheme = false }); } inline fn surfaceMessageWriter( @@ -767,7 +770,7 @@ pub const StreamHandler = struct { self.messageWriter(msg); }, - .color_scheme => self.surfaceMessageWriter(.{ .report_color_scheme = {} }), + .color_scheme => self.surfaceMessageWriter(.{ .report_color_scheme = true }), } } @@ -892,6 +895,9 @@ pub const StreamHandler = struct { ) !void { self.terminal.fullReset(); try self.setMouseShape(.text); + + // Reset resets our palette so we report it for mode 2031. + self.surfaceMessageWriter(.{ .report_color_scheme = false }); } pub fn queryKittyKeyboard(self: *StreamHandler) !void {