Move cursor timer to renderer

This commit is contained in:
Mitchell Hashimoto
2022-11-05 19:18:22 -07:00
parent e2d8ffc3c1
commit aa98e3ca3a
6 changed files with 68 additions and 36 deletions

View File

@ -70,10 +70,6 @@ mouse: Mouse,
io: termio.Impl,
io_thread: termio.Thread,
io_thr: std.Thread,
/// Cursor state.
terminal_cursor: Cursor,
/// The dimensions of the grid in rows and columns.
grid_size: renderer.GridSize,
@ -137,6 +133,7 @@ const Mouse = struct {
/// need a stable pointer for user data callbacks. Therefore, a stack-only
/// initialization is not currently possible.
pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Window {
_ = loop;
var self = try alloc.create(Window);
errdefer alloc.destroy(self);
@ -344,13 +341,6 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
.height = @floatToInt(u32, renderer_impl.cell_size.height * 4),
}, .{ .width = null, .height = null });
// Setup a timer for blinking the cursor
var timer = try libuv.Timer.init(alloc, loop);
errdefer timer.deinit(alloc);
errdefer timer.close(null);
timer.setData(self);
try timer.start(cursorTimerCallback, 600, 600);
// Create the cursor
const cursor = try glfw.Cursor.createStandard(.ibeam);
errdefer cursor.destroy();
@ -398,7 +388,6 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
.cursor = .{
.style = .blinking_block,
.visible = true,
.blink = false,
},
.terminal = &self.io.terminal,
.devmode = if (!DevMode.enabled) null else &DevMode.instance,
@ -408,7 +397,6 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
.io = io,
.io_thread = io_thread,
.io_thr = undefined,
.terminal_cursor = .{ .timer = timer },
.grid_size = grid_size,
.config = config,
@ -516,13 +504,6 @@ pub fn destroy(self: *Window) void {
self.window.destroy();
self.terminal_cursor.timer.close((struct {
fn callback(t: *libuv.Timer) void {
const alloc = t.loop().getData(Allocator).?.*;
t.deinit(alloc);
}
}).callback);
// We can destroy the cursor right away. glfw will just revert any
// windows using it to the default.
self.cursor.destroy();
@ -921,15 +902,8 @@ fn focusCallback(window: glfw.Window, focused: bool) void {
.focus = focused,
}, .{ .forever = {} });
// We have to schedule a render because no matter what we're changing
// the cursor. If we're focused its reappearing, if we're not then
// its changing to hollow and not blinking.
// Schedule render which also drains our mailbox
win.queueRender() catch unreachable;
if (focused)
win.terminal_cursor.startTimer() catch unreachable
else
win.terminal_cursor.stopTimer() catch unreachable;
}
fn refreshCallback(window: glfw.Window) void {

View File

@ -299,6 +299,11 @@ pub fn setFocus(self: *Metal, focus: bool) !void {
self.focused = focus;
}
/// Called to toggle the blink state of the cursor
pub fn blinkCursor(self: *Metal) void {
self.cursor_visible = !self.cursor_visible;
}
/// The primary render callback that is completely thread-safe.
pub fn render(
self: *Metal,
@ -325,7 +330,7 @@ pub fn render(
// Setup our cursor state
if (self.focused) {
self.cursor_visible = state.cursor.visible and !state.cursor.blink;
self.cursor_visible = self.cursor_visible and state.cursor.visible;
self.cursor_style = renderer.CursorStyle.fromTerminal(state.cursor.style) orelse .box;
} else {
self.cursor_visible = true;

View File

@ -441,6 +441,11 @@ pub fn setFocus(self: *OpenGL, focus: bool) !void {
self.focused = focus;
}
/// Called to toggle the blink state of the cursor
pub fn blinkCursor(self: *OpenGL) void {
self.cursor_visible = !self.cursor_visible;
}
/// The primary render callback that is completely thread-safe.
pub fn render(
self: *OpenGL,
@ -465,7 +470,7 @@ pub fn render(
// Setup our cursor state
if (self.focused) {
self.cursor_visible = state.cursor.visible and !state.cursor.blink;
self.cursor_visible = self.cursor_visible and state.cursor.visible;
self.cursor_style = renderer.CursorStyle.fromTerminal(state.cursor.style) orelse .box;
} else {
self.cursor_visible = true;

View File

@ -33,8 +33,4 @@ pub const Cursor = struct {
/// "blink" settings, see "blink" for that. This is used to turn the
/// cursor ON or OFF.
visible: bool = true,
/// Whether the cursor is currently blinking. If it is blinking, then
/// the cursor will not be rendered.
blink: bool = false,
};

View File

@ -32,6 +32,9 @@ stop: libuv.Async,
/// The timer used for rendering
render_h: libuv.Timer,
/// The timer used for cursor blinking
cursor_h: libuv.Timer,
/// The windo we're rendering to.
window: glfw.Window,
@ -92,6 +95,15 @@ pub fn init(
}
}).callback);
// Setup a timer for blinking the cursor
var cursor_timer = try libuv.Timer.init(alloc, loop);
errdefer cursor_timer.close((struct {
fn callback(t: *libuv.Timer) void {
const alloc_h = t.loop().getData(Allocator).?.*;
t.deinit(alloc_h);
}
}).callback);
// The mailbox for messaging this thread
var mailbox = try Mailbox.create(alloc);
errdefer mailbox.destroy(alloc);
@ -101,6 +113,7 @@ pub fn init(
.wakeup = wakeup_h,
.stop = stop_h,
.render_h = render_h,
.cursor_h = cursor_timer,
.window = window,
.renderer = renderer_impl,
.state = state,
@ -134,6 +147,12 @@ pub fn deinit(self: *Thread) void {
h.deinit(handle_alloc);
}
}).callback);
self.cursor_h.close((struct {
fn callback(h: *libuv.Timer) void {
const handle_alloc = h.loop().getData(Allocator).?.*;
h.deinit(handle_alloc);
}
}).callback);
// Run the loop one more time, because destroying our other things
// like windows usually cancel all our event loop stuff and we need
@ -175,6 +194,10 @@ fn threadMain_(self: *Thread) !void {
defer self.render_h.setData(null);
try self.wakeup.send();
// Setup a timer for blinking the cursor
self.cursor_h.setData(self);
try self.cursor_h.start(cursorTimerCallback, 600, 600);
// Run
log.debug("starting renderer thread", .{});
defer log.debug("exiting renderer thread", .{});
@ -193,7 +216,25 @@ fn drainMailbox(self: *Thread) !void {
while (drain.next()) |message| {
log.debug("mailbox message={}", .{message});
switch (message) {
.focus => |v| try self.renderer.setFocus(v),
.focus => |v| {
// Set it on the renderer
try self.renderer.setFocus(v);
if (!v) {
// If we're not focused, then we stop the cursor blink
try self.cursor_h.stop();
} else {
// If we're focused, we immediately show the cursor again
// and then restart the timer.
if (!try self.cursor_h.isActive()) {
try self.cursor_h.start(
cursorTimerCallback,
0,
self.cursor_h.getRepeat(),
);
}
}
},
}
}
}
@ -230,6 +271,17 @@ fn renderCallback(h: *libuv.Timer) void {
log.warn("error rendering err={}", .{err});
}
fn cursorTimerCallback(h: *libuv.Timer) void {
const t = h.getData(Thread) orelse {
// This shouldn't happen so we log it.
log.warn("render callback fired without data set", .{});
return;
};
t.renderer.blinkCursor();
t.wakeup.send() catch {};
}
fn stopCallback(h: *libuv.Async) void {
h.loop().stop();
}

View File

@ -340,7 +340,7 @@ fn ttyRead(t: *libuv.Tty, n: isize, buf: []const u8) void {
// 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;
//ev.renderer_state.cursor.blink = false;
// TODO
// if (win.terminal_cursor.timer.isActive() catch false) {
// _ = win.terminal_cursor.timer.again() catch null;