ghostty/src/apprt/surface.zig
Mitchell Hashimoto 1c6adf4065 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
2024-11-22 13:14:12 -08:00

136 lines
4.2 KiB
Zig

const apprt = @import("../apprt.zig");
const App = @import("../App.zig");
const Surface = @import("../Surface.zig");
const renderer = @import("../renderer.zig");
const termio = @import("../termio.zig");
const terminal = @import("../terminal/main.zig");
const Config = @import("../config.zig").Config;
/// The message types that can be sent to a single surface.
pub const Message = union(enum) {
/// Represents a write request. Magic number comes from the max size
/// we want this union to be.
pub const WriteReq = termio.MessageData(u8, 255);
/// Set the title of the surface.
/// TODO: we should change this to a "WriteReq" style structure in
/// the termio message so that we can more efficiently send strings
/// of any length
set_title: [256]u8,
/// Report the window title back to the terminal
report_title: ReportTitleStyle,
/// Set the mouse shape.
set_mouse_shape: terminal.MouseShape,
/// Read the clipboard and write to the pty.
clipboard_read: apprt.Clipboard,
/// Write the clipboard contents.
clipboard_write: struct {
clipboard_type: apprt.Clipboard,
req: WriteReq,
},
/// Change the configuration to the given configuration. The pointer is
/// not valid after receiving this message so any config must be used
/// and derived immediately.
change_config: *const Config,
/// Close the surface. This will only close the current surface that
/// receives this, not the full application.
close: void,
/// The child process running in the surface has exited. This may trigger
/// a surface close, it may not.
child_exited: void,
/// Show a desktop notification.
desktop_notification: struct {
/// Desktop notification title.
title: [63:0]u8,
/// Desktop notification body.
body: [255:0]u8,
},
/// Health status change for the renderer.
renderer_health: renderer.Health,
/// 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.
present_surface: void,
/// Notifies the surface that password input has started within
/// the terminal. This should always be followed by a false value
/// unless the surface exits.
password_input: bool,
/// A terminal color was changed using OSC sequences.
color_change: struct {
kind: terminal.osc.Command.ColorKind,
color: terminal.color.RGB,
},
/// The terminal has reported a change in the working directory.
pwd_change: WriteReq,
pub const ReportTitleStyle = enum {
csi_21_t,
// This enum is a placeholder for future title styles.
};
};
/// A surface mailbox.
pub const Mailbox = struct {
surface: *Surface,
app: App.Mailbox,
/// Send a message to the surface.
pub fn push(
self: Mailbox,
msg: Message,
timeout: App.Mailbox.Queue.Timeout,
) App.Mailbox.Queue.Size {
// Surface message sending is actually implemented on the app
// thread, so we have to rewrap the message with our surface
// pointer and send it to the app thread.
return self.app.push(.{
.surface_message = .{
.surface = self.surface,
.message = msg,
},
}, timeout);
}
};
/// Returns a new config for a surface for the given app that should be
/// used for any new surfaces. The resulting config should be deinitialized
/// after the surface is initialized.
pub fn newConfig(app: *const App, config: *const Config) !Config {
// Create a shallow clone
var copy = config.shallowClone(app.alloc);
// Our allocator is our config's arena
const alloc = copy._arena.?.allocator();
// Get our previously focused surface for some inherited values.
const prev = app.focusedSurface();
if (prev) |p| {
if (config.@"window-inherit-working-directory") {
if (try p.pwd(alloc)) |pwd| {
copy.@"working-directory" = pwd;
}
}
}
return copy;
}