implement cursor reset when data comes in pty

This commit is contained in:
Mitchell Hashimoto
2022-11-05 19:26:42 -07:00
parent aa98e3ca3a
commit 746858cea6
7 changed files with 37 additions and 15 deletions

View File

@ -367,6 +367,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
.config = config, .config = config,
.renderer_state = &self.renderer_state, .renderer_state = &self.renderer_state,
.renderer_wakeup = render_thread.wakeup, .renderer_wakeup = render_thread.wakeup,
.renderer_mailbox = render_thread.mailbox,
}); });
errdefer io.deinit(); errdefer io.deinit();

View File

@ -300,8 +300,8 @@ pub fn setFocus(self: *Metal, focus: bool) !void {
} }
/// Called to toggle the blink state of the cursor /// Called to toggle the blink state of the cursor
pub fn blinkCursor(self: *Metal) void { pub fn blinkCursor(self: *Metal, reset: bool) void {
self.cursor_visible = !self.cursor_visible; self.cursor_visible = reset or !self.cursor_visible;
} }
/// The primary render callback that is completely thread-safe. /// The primary render callback that is completely thread-safe.

View File

@ -442,8 +442,8 @@ pub fn setFocus(self: *OpenGL, focus: bool) !void {
} }
/// Called to toggle the blink state of the cursor /// Called to toggle the blink state of the cursor
pub fn blinkCursor(self: *OpenGL) void { pub fn blinkCursor(self: *OpenGL, reset: bool) void {
self.cursor_visible = !self.cursor_visible; self.cursor_visible = reset or !self.cursor_visible;
} }
/// The primary render callback that is completely thread-safe. /// The primary render callback that is completely thread-safe.

View File

@ -15,7 +15,7 @@ const log = std.log.scoped(.renderer_thread);
/// The type used for sending messages to the IO thread. For now this is /// The type used for sending messages to the IO thread. For now this is
/// hardcoded with a capacity. We can make this a comptime parameter in /// hardcoded with a capacity. We can make this a comptime parameter in
/// the future if we want it configurable. /// the future if we want it configurable.
const Mailbox = BlockingQueue(renderer.Message, 64); pub const Mailbox = BlockingQueue(renderer.Message, 64);
/// The main event loop for the application. The user data of this loop /// The main event loop for the application. The user data of this loop
/// is always the allocator used to create the loop. This is a convenience /// is always the allocator used to create the loop. This is a convenience
@ -227,14 +227,22 @@ fn drainMailbox(self: *Thread) !void {
// If we're focused, we immediately show the cursor again // If we're focused, we immediately show the cursor again
// and then restart the timer. // and then restart the timer.
if (!try self.cursor_h.isActive()) { if (!try self.cursor_h.isActive()) {
self.renderer.blinkCursor(true);
try self.cursor_h.start( try self.cursor_h.start(
cursorTimerCallback, cursorTimerCallback,
0, self.cursor_h.getRepeat(),
self.cursor_h.getRepeat(), self.cursor_h.getRepeat(),
); );
} }
} }
}, },
.reset_cursor_blink => {
self.renderer.blinkCursor(true);
if (try self.cursor_h.isActive()) {
_ = try self.cursor_h.again();
}
},
} }
} }
} }
@ -278,7 +286,7 @@ fn cursorTimerCallback(h: *libuv.Timer) void {
return; return;
}; };
t.renderer.blinkCursor(); t.renderer.blinkCursor(false);
t.wakeup.send() catch {}; t.wakeup.send() catch {};
} }

View File

@ -8,4 +8,8 @@ pub const Message = union(enum) {
/// rendering within. This is only sent when a change is detected so /// rendering within. This is only sent when a change is detected so
/// the renderer is expected to handle all of these. /// the renderer is expected to handle all of these.
focus: bool, focus: bool,
/// Reset the cursor blink by immediately showing the cursor then
/// restarting the timer.
reset_cursor_blink: void,
}; };

View File

@ -40,6 +40,9 @@ renderer_state: *renderer.State,
/// a repaint should happen. /// a repaint should happen.
renderer_wakeup: libuv.Async, renderer_wakeup: libuv.Async,
/// The mailbox for notifying the renderer of things.
renderer_mailbox: *renderer.Thread.Mailbox,
/// The cached grid size whenever a resize is called. /// The cached grid size whenever a resize is called.
grid_size: renderer.GridSize, grid_size: renderer.GridSize,
@ -103,6 +106,7 @@ pub fn init(alloc: Allocator, opts: termio.Options) !Exec {
.terminal_stream = undefined, .terminal_stream = undefined,
.renderer_state = opts.renderer_state, .renderer_state = opts.renderer_state,
.renderer_wakeup = opts.renderer_wakeup, .renderer_wakeup = opts.renderer_wakeup,
.renderer_mailbox = opts.renderer_mailbox,
.grid_size = opts.grid_size, .grid_size = opts.grid_size,
.data = null, .data = null,
}; };
@ -141,6 +145,7 @@ pub fn threadEnter(self: *Exec, loop: libuv.Loop) !ThreadData {
.read_arena = std.heap.ArenaAllocator.init(alloc), .read_arena = std.heap.ArenaAllocator.init(alloc),
.renderer_state = self.renderer_state, .renderer_state = self.renderer_state,
.renderer_wakeup = self.renderer_wakeup, .renderer_wakeup = self.renderer_wakeup,
.renderer_mailbox = self.renderer_mailbox,
.data_stream = stream, .data_stream = stream,
.terminal_stream = .{ .terminal_stream = .{
.handler = .{ .handler = .{
@ -238,6 +243,9 @@ const EventData = struct {
/// a repaint should happen. /// a repaint should happen.
renderer_wakeup: libuv.Async, renderer_wakeup: libuv.Async,
/// The mailbox for notifying the renderer of things.
renderer_mailbox: *renderer.Thread.Mailbox,
/// The data stream is the main IO for the pty. /// The data stream is the main IO for the pty.
data_stream: libuv.Tty, data_stream: libuv.Tty,
@ -334,18 +342,16 @@ fn ttyRead(t: *libuv.Tty, n: isize, buf: []const u8) void {
return; return;
}; };
// Whenever a character is typed, we ensure the cursor is in the
// non-blink state so it is rendered if visible.
_ = ev.renderer_mailbox.push(.{
.reset_cursor_blink = {},
}, .{ .forever = {} });
// We are modifying terminal state from here on out // We are modifying terminal state from here on out
ev.renderer_state.mutex.lock(); ev.renderer_state.mutex.lock();
defer ev.renderer_state.mutex.unlock(); defer ev.renderer_state.mutex.unlock();
// Whenever a character is typed, we ensure the cursor is in the
// non-blink state so it is rendered if visible.
//ev.renderer_state.cursor.blink = false;
// TODO
// if (win.terminal_cursor.timer.isActive() catch false) {
// _ = win.terminal_cursor.timer.again() catch null;
// }
// Schedule a render // Schedule a render
ev.queueRender() catch unreachable; ev.queueRender() catch unreachable;

View File

@ -22,3 +22,6 @@ renderer_state: *renderer.State,
/// A handle to wake up the renderer. This hints to the renderer that that /// A handle to wake up the renderer. This hints to the renderer that that
/// a repaint should happen. /// a repaint should happen.
renderer_wakeup: libuv.Async, renderer_wakeup: libuv.Async,
/// The mailbox for renderer messages.
renderer_mailbox: *renderer.Thread.Mailbox,