mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
update cursor on request from shell
This commit is contained in:
13
src/Grid.zig
13
src/Grid.zig
@ -47,10 +47,21 @@ foreground: terminal.color.RGB,
|
|||||||
|
|
||||||
/// Available cursor styles for drawing. The values represents the mode value
|
/// Available cursor styles for drawing. The values represents the mode value
|
||||||
/// in the shader.
|
/// in the shader.
|
||||||
const CursorStyle = enum(u8) {
|
pub const CursorStyle = enum(u8) {
|
||||||
box = 3,
|
box = 3,
|
||||||
box_hollow = 4,
|
box_hollow = 4,
|
||||||
bar = 5,
|
bar = 5,
|
||||||
|
|
||||||
|
/// Create a cursor style from the terminal style request.
|
||||||
|
pub fn fromTerminal(style: terminal.CursorStyle) ?CursorStyle {
|
||||||
|
return switch (style) {
|
||||||
|
.blinking_block, .steady_block => .box,
|
||||||
|
.blinking_bar, .steady_bar => .bar,
|
||||||
|
.blinking_underline, .steady_underline => null, // TODO
|
||||||
|
.default => .box,
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
||||||
|
@ -36,6 +36,9 @@ alloc: Allocator,
|
|||||||
/// The glfw window handle.
|
/// The glfw window handle.
|
||||||
window: glfw.Window,
|
window: glfw.Window,
|
||||||
|
|
||||||
|
/// Whether the window is currently focused
|
||||||
|
focused: bool,
|
||||||
|
|
||||||
/// The terminal grid attached to this window.
|
/// The terminal grid attached to this window.
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
|
||||||
@ -56,6 +59,7 @@ terminal_stream: terminal.Stream(*Window),
|
|||||||
|
|
||||||
/// Timer that blinks the cursor.
|
/// Timer that blinks the cursor.
|
||||||
cursor_timer: libuv.Timer,
|
cursor_timer: libuv.Timer,
|
||||||
|
cursor_style: terminal.CursorStyle,
|
||||||
|
|
||||||
/// Render at least 60fps.
|
/// Render at least 60fps.
|
||||||
render_timer: RenderTimer,
|
render_timer: RenderTimer,
|
||||||
@ -199,12 +203,14 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
self.* = .{
|
self.* = .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.window = window,
|
.window = window,
|
||||||
|
.focused = false,
|
||||||
.grid = grid,
|
.grid = grid,
|
||||||
.pty = pty,
|
.pty = pty,
|
||||||
.command = cmd,
|
.command = cmd,
|
||||||
.terminal = term,
|
.terminal = term,
|
||||||
.terminal_stream = .{ .handler = self },
|
.terminal_stream = .{ .handler = self },
|
||||||
.cursor_timer = timer,
|
.cursor_timer = timer,
|
||||||
|
.cursor_style = .blinking_block,
|
||||||
.render_timer = try RenderTimer.init(loop, self, 16, 96),
|
.render_timer = try RenderTimer.init(loop, self, 16, 96),
|
||||||
.pty_stream = stream,
|
.pty_stream = stream,
|
||||||
.config = config,
|
.config = config,
|
||||||
@ -285,6 +291,25 @@ fn queueWrite(self: *Window, data: []const u8) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates te style of the cursor.
|
||||||
|
fn updateCursorStyle(self: *Window, style: Grid.CursorStyle, blink: bool) !void {
|
||||||
|
self.grid.cursor_style = style;
|
||||||
|
self.grid.cursor_visible = !blink;
|
||||||
|
|
||||||
|
if (blink) {
|
||||||
|
try self.cursor_timer.start(
|
||||||
|
cursorTimerCallback,
|
||||||
|
0,
|
||||||
|
self.cursor_timer.getRepeat(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
try self.cursor_timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always schedule a render when we change cursors
|
||||||
|
try self.render_timer.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
@ -394,19 +419,25 @@ fn focusCallback(window: glfw.Window, focused: bool) void {
|
|||||||
|
|
||||||
const win = window.getUserPointer(Window) orelse return;
|
const win = window.getUserPointer(Window) orelse return;
|
||||||
|
|
||||||
|
// If we aren't changing focus state, do nothing. I don't think this
|
||||||
|
// can happen but it costs very little to check.
|
||||||
|
if (win.focused == focused) return;
|
||||||
|
|
||||||
// We have to schedule a render because no matter what we're changing
|
// We have to schedule a render because no matter what we're changing
|
||||||
// the cursor.
|
// the cursor.
|
||||||
win.render_timer.schedule() catch unreachable;
|
win.render_timer.schedule() catch unreachable;
|
||||||
|
|
||||||
|
// Set our focused state on the window.
|
||||||
|
win.focused = focused;
|
||||||
|
|
||||||
if (focused) {
|
if (focused) {
|
||||||
win.wakeup = true;
|
win.wakeup = true;
|
||||||
win.cursor_timer.start(cursorTimerCallback, 0, win.cursor_timer.getRepeat()) catch unreachable;
|
win.updateCursorStyle(
|
||||||
win.grid.cursor_style = .box;
|
Grid.CursorStyle.fromTerminal(win.cursor_style) orelse .box,
|
||||||
win.grid.cursor_visible = false;
|
win.cursor_style.blinking(),
|
||||||
|
) catch unreachable;
|
||||||
} else {
|
} else {
|
||||||
win.grid.cursor_visible = true;
|
win.updateCursorStyle(.box_hollow, false) catch unreachable;
|
||||||
win.grid.cursor_style = .box_hollow;
|
|
||||||
win.cursor_timer.stop() catch unreachable;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -676,7 +707,17 @@ pub fn setCursorStyle(
|
|||||||
) !void {
|
) !void {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
switch (style) {
|
// Get the style that we use in the renderer
|
||||||
else => log.warn("unimplemented cursor style: {}", .{style}),
|
const grid_style = Grid.CursorStyle.fromTerminal(style) orelse {
|
||||||
}
|
log.warn("unimplemented cursor style: {}", .{style});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set our style
|
||||||
|
self.cursor_style = style;
|
||||||
|
|
||||||
|
// If we're currently focused, we update our style, since our unfocused
|
||||||
|
// cursor is manually managed. If we're not focused, we ignore it because
|
||||||
|
// it'll be updated the next time the window comes into focus.
|
||||||
|
if (self.focused) try self.updateCursorStyle(grid_style, style.blinking());
|
||||||
}
|
}
|
||||||
|
@ -71,4 +71,12 @@ pub const CursorStyle = enum(u16) {
|
|||||||
|
|
||||||
// Non-exhaustive so that @intToEnum never fails for unsupported modes.
|
// Non-exhaustive so that @intToEnum never fails for unsupported modes.
|
||||||
_,
|
_,
|
||||||
|
|
||||||
|
/// True if the cursor should blink.
|
||||||
|
pub fn blinking(self: CursorStyle) bool {
|
||||||
|
return switch (self) {
|
||||||
|
.blinking_block, .blinking_underline, .blinking_bar => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user