update cursor on request from shell

This commit is contained in:
Mitchell Hashimoto
2022-05-20 13:51:18 -07:00
parent 75c3dc4386
commit 3538e6782b
3 changed files with 70 additions and 10 deletions

View File

@ -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.

View File

@ -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());
} }

View File

@ -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,
};
}
}; };