libghostty: expose mouse_tracking terminal data option

#11706

Add a new GHOSTTY_TERMINAL_DATA_MOUSE_TRACKING option to the
ghostty_terminal_get API. This returns true if any mouse tracking
mode is active (X10, normal, button, or any-event), replacing the
need for consumers to loop over four separate mode queries.
This commit is contained in:
Mitchell Hashimoto
2026-03-21 20:09:29 -07:00
parent 1775c312ae
commit 47bfde3286
2 changed files with 66 additions and 1 deletions

View File

@@ -221,6 +221,16 @@ typedef enum {
* Output type: GhosttyStyle *
*/
GHOSTTY_TERMINAL_DATA_CURSOR_STYLE = 10,
/**
* Whether any mouse tracking mode is active.
*
* Returns true if any of the mouse tracking modes (X10, normal, button,
* or any-event) are enabled.
*
* Output type: bool *
*/
GHOSTTY_TERMINAL_DATA_MOUSE_TRACKING = 11,
} GhosttyTerminalData;
/**

View File

@@ -167,13 +167,14 @@ pub const TerminalData = enum(c_int) {
kitty_keyboard_flags = 8,
scrollbar = 9,
cursor_style = 10,
mouse_tracking = 11,
/// Output type expected for querying the data of the given kind.
pub fn OutType(comptime self: TerminalData) type {
return switch (self) {
.invalid => void,
.cols, .rows, .cursor_x, .cursor_y => size.CellCountInt,
.cursor_pending_wrap, .cursor_visible => bool,
.cursor_pending_wrap, .cursor_visible, .mouse_tracking => bool,
.active_screen => TerminalScreen,
.kitty_keyboard_flags => u8,
.scrollbar => TerminalScrollbar,
@@ -221,6 +222,10 @@ fn getTyped(
.kitty_keyboard_flags => out.* = @as(u8, t.screens.active.kitty_keyboard.current().int()),
.scrollbar => out.* = t.screens.active.pages.scrollbar().cval(),
.cursor_style => out.* = .fromStyle(t.screens.active.cursor.style),
.mouse_tracking => out.* = t.modes.get(.mouse_event_x10) or
t.modes.get(.mouse_event_normal) or
t.modes.get(.mouse_event_button) or
t.modes.get(.mouse_event_any),
}
return .success;
@@ -662,6 +667,56 @@ test "get kitty_keyboard_flags" {
try testing.expectEqual(3, flags);
}
test "get mouse_tracking" {
var t: Terminal = null;
try testing.expectEqual(Result.success, new(
&lib_alloc.test_allocator,
&t,
.{
.cols = 80,
.rows = 24,
.max_scrollback = 0,
},
));
defer free(t);
var tracking: bool = undefined;
try testing.expectEqual(Result.success, get(t, .mouse_tracking, @ptrCast(&tracking)));
try testing.expect(!tracking);
// Enable X10 mouse (DEC mode 9)
const x10_mode: modes.ModeTag.Backing = @bitCast(modes.ModeTag{ .value = 9, .ansi = false });
try testing.expectEqual(Result.success, mode_set(t, x10_mode, true));
try testing.expectEqual(Result.success, get(t, .mouse_tracking, @ptrCast(&tracking)));
try testing.expect(tracking);
// Disable X10, enable normal mouse (DEC mode 1000)
try testing.expectEqual(Result.success, mode_set(t, x10_mode, false));
const normal_mode: modes.ModeTag.Backing = @bitCast(modes.ModeTag{ .value = 1000, .ansi = false });
try testing.expectEqual(Result.success, mode_set(t, normal_mode, true));
try testing.expectEqual(Result.success, get(t, .mouse_tracking, @ptrCast(&tracking)));
try testing.expect(tracking);
// Disable normal, enable button mouse (DEC mode 1002)
try testing.expectEqual(Result.success, mode_set(t, normal_mode, false));
const button_mode: modes.ModeTag.Backing = @bitCast(modes.ModeTag{ .value = 1002, .ansi = false });
try testing.expectEqual(Result.success, mode_set(t, button_mode, true));
try testing.expectEqual(Result.success, get(t, .mouse_tracking, @ptrCast(&tracking)));
try testing.expect(tracking);
// Disable button, enable any mouse (DEC mode 1003)
try testing.expectEqual(Result.success, mode_set(t, button_mode, false));
const any_mode: modes.ModeTag.Backing = @bitCast(modes.ModeTag{ .value = 1003, .ansi = false });
try testing.expectEqual(Result.success, mode_set(t, any_mode, true));
try testing.expectEqual(Result.success, get(t, .mouse_tracking, @ptrCast(&tracking)));
try testing.expect(tracking);
// Disable all - should be false again
try testing.expectEqual(Result.success, mode_set(t, any_mode, false));
try testing.expectEqual(Result.success, get(t, .mouse_tracking, @ptrCast(&tracking)));
try testing.expect(!tracking);
}
test "get invalid" {
var t: Terminal = null;
try testing.expectEqual(Result.success, new(