From 66950a4a537d1c21fe63a7c53d3c254bbe83679a Mon Sep 17 00:00:00 2001 From: Riccardo Mazzarini Date: Tue, 2 Jun 2026 18:03:45 +0200 Subject: [PATCH] libghostty: add option to set default cursor blink Adds an option to `libghostty-vt` to configure whether the default cursor displayed when an app sends a DECSCUSR reset sequence should blink. --- include/ghostty/vt/terminal.h | 10 ++++++++++ src/terminal/c/terminal.zig | 9 +++++++++ src/terminal/stream_terminal.zig | 5 ++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/ghostty/vt/terminal.h b/include/ghostty/vt/terminal.h index 9ddc2b54b..9b573c36a 100644 --- a/include/ghostty/vt/terminal.h +++ b/include/ghostty/vt/terminal.h @@ -637,6 +637,16 @@ typedef enum GHOSTTY_ENUM_TYPED { * Input type: GhosttyTerminalCursorStyle* */ GHOSTTY_TERMINAL_OPT_DEFAULT_CURSOR_STYLE = 22, + + /** + * Set whether the default cursor should blink when reset by DECSCUSR + * (CSI 0 q). + * + * A NULL value pointer resets to the built-in default of not blinking. + * + * Input type: bool* + */ + GHOSTTY_TERMINAL_OPT_DEFAULT_CURSOR_BLINK = 23, GHOSTTY_TERMINAL_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE, } GhosttyTerminalOption; diff --git a/src/terminal/c/terminal.zig b/src/terminal/c/terminal.zig index 59fac7e70..6d5ca4c5c 100644 --- a/src/terminal/c/terminal.zig +++ b/src/terminal/c/terminal.zig @@ -328,6 +328,7 @@ pub const Option = enum(c_int) { apc_max_bytes_kitty = 20, selection = 21, default_cursor_style = 22, + default_cursor_blink = 23, /// Input type expected for setting the option. pub fn InType(comptime self: Option) type { @@ -352,6 +353,7 @@ pub const Option = enum(c_int) { .apc_max_bytes, .apc_max_bytes_kitty => ?*const usize, .selection => ?*const selection_c.CSelection, .default_cursor_style => ?*const TerminalCursorStyle, + .default_cursor_blink => ?*const bool, }; } }; @@ -474,6 +476,13 @@ fn setTyped( wrapper.terminal.screens.active.cursor.cursor_style = style; } }, + .default_cursor_blink => { + const blink = if (value) |ptr| ptr.* else false; + wrapper.stream.handler.default_cursor_blink = blink; + if (wrapper.stream.handler.default_cursor) { + wrapper.terminal.modes.set(.cursor_blinking, blink); + } + }, } return .success; } diff --git a/src/terminal/stream_terminal.zig b/src/terminal/stream_terminal.zig index 560e12c2a..113521072 100644 --- a/src/terminal/stream_terminal.zig +++ b/src/terminal/stream_terminal.zig @@ -46,6 +46,7 @@ pub const Handler = struct { /// Default cursor style used by DECSCUSR reset (CSI 0 q). default_cursor: bool = true, default_cursor_style: Screen.CursorStyle = .block, + default_cursor_blink: bool = false, pub const Effects = struct { /// Called when the terminal needs to write data back to the pty, @@ -159,7 +160,8 @@ pub const Handler = struct { self.default_cursor = false; const blink = switch (value) { - .default, .steady_block, .steady_bar, .steady_underline => false, + .default => self.default_cursor_blink, + .steady_block, .steady_bar, .steady_underline => false, .blinking_block, .blinking_bar, .blinking_underline => true, }; const style: Screen.CursorStyle = switch (value) { @@ -241,6 +243,7 @@ pub const Handler = struct { .full_reset => { self.terminal.fullReset(); self.default_cursor = true; + self.terminal.modes.set(.cursor_blinking, self.default_cursor_blink); self.terminal.screens.active.cursor.cursor_style = self.default_cursor_style; }, .start_hyperlink => try self.terminal.screens.active.startHyperlink(value.uri, value.id),