mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Move cursor timer to renderer
This commit is contained in:
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user