mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
don't blink cursor when losing focus
This commit is contained in:
12
src/App.zig
12
src/App.zig
@ -90,6 +90,18 @@ pub fn run(self: App) !void {
|
||||
// posted by the libuv watcher so that we trigger a libuv loop tick.
|
||||
try glfw.waitEvents();
|
||||
|
||||
// If the window wants the event loop to wakeup, then we "kick" the
|
||||
// embed thread to wake up. I'm not sure why we have to do this in a
|
||||
// loop, this is surely a lacking in my understanding of libuv. But
|
||||
// this works.
|
||||
if (self.window.wakeup) {
|
||||
self.window.wakeup = false;
|
||||
while (embed.sleeping.load(.SeqCst) and embed.terminate.load(.SeqCst) == false) {
|
||||
try async_h.send();
|
||||
try embed.loopRun();
|
||||
}
|
||||
}
|
||||
|
||||
// Run the libuv loop
|
||||
try embed.loopRun();
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ terminal: Terminal,
|
||||
/// Timer that blinks the cursor.
|
||||
cursor_timer: libuv.Timer,
|
||||
|
||||
/// Set this to true whenver an event occurs that we may want to wake up
|
||||
/// the event loop. Only set this from the main thread.
|
||||
wakeup: bool = false,
|
||||
|
||||
/// Create a new window. This allocates and returns a pointer because we
|
||||
/// need a stable pointer for user data callbacks. Therefore, a stack-only
|
||||
/// initialization is not currently possible.
|
||||
@ -119,6 +123,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop) !*Window {
|
||||
window.setSizeCallback(sizeCallback);
|
||||
window.setCharCallback(charCallback);
|
||||
window.setKeyCallback(keyCallback);
|
||||
window.setFocusCallback(focusCallback);
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -213,6 +218,17 @@ fn keyCallback(
|
||||
}
|
||||
}
|
||||
|
||||
fn focusCallback(window: glfw.Window, focused: bool) void {
|
||||
const win = window.getUserPointer(Window) orelse return;
|
||||
if (focused) {
|
||||
win.cursor_timer.start(cursorTimerCallback, 800, 800) catch unreachable;
|
||||
win.wakeup = true;
|
||||
} else {
|
||||
win.grid.cursor_visible = false;
|
||||
win.cursor_timer.stop() catch unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
fn cursorTimerCallback(t: *libuv.Timer) void {
|
||||
const win = t.getData(Window) orelse return;
|
||||
win.grid.cursor_visible = !win.grid.cursor_visible;
|
||||
|
@ -13,11 +13,14 @@ const Loop = @import("Loop.zig");
|
||||
const Sem = @import("Sem.zig");
|
||||
const Thread = @import("Thread.zig");
|
||||
|
||||
const TerminateAtomic = std.atomic.Atomic(bool);
|
||||
const log = std.log.scoped(.libuv_embed);
|
||||
|
||||
const BoolAtomic = std.atomic.Atomic(bool);
|
||||
|
||||
loop: Loop,
|
||||
sem: Sem,
|
||||
terminate: TerminateAtomic,
|
||||
terminate: BoolAtomic,
|
||||
sleeping: BoolAtomic,
|
||||
callback: fn () void,
|
||||
thread: ?Thread,
|
||||
|
||||
@ -27,7 +30,8 @@ pub fn init(alloc: Allocator, loop: Loop, callback: fn () void) !Embed {
|
||||
return Embed{
|
||||
.loop = loop,
|
||||
.sem = try Sem.init(alloc, 0),
|
||||
.terminate = TerminateAtomic.init(false),
|
||||
.terminate = BoolAtomic.init(false),
|
||||
.sleeping = BoolAtomic.init(false),
|
||||
.callback = callback,
|
||||
.thread = null,
|
||||
};
|
||||
@ -77,6 +81,19 @@ fn threadMain(self: *Embed) void {
|
||||
while (self.terminate.load(.SeqCst) == false) {
|
||||
const fd = self.loop.backendFd() catch unreachable;
|
||||
const timeout = self.loop.backendTimeout();
|
||||
|
||||
// If the timeout is negative then we are sleeping (i.e. no
|
||||
// timers active or anything). In that case, we set the boolean
|
||||
// to true so that we can wake up the event loop if we have to.
|
||||
if (timeout < 0) {
|
||||
log.debug("going to sleep", .{});
|
||||
self.sleeping.store(true, .SeqCst);
|
||||
}
|
||||
defer if (timeout < 0) {
|
||||
log.debug("waking from sleep", .{});
|
||||
self.sleeping.store(false, .SeqCst);
|
||||
};
|
||||
|
||||
switch (builtin.os.tag) {
|
||||
// epoll
|
||||
.linux => {
|
||||
|
@ -56,6 +56,24 @@ pub fn stop(self: Timer) !void {
|
||||
try errors.convertError(c.uv_timer_stop(self.handle));
|
||||
}
|
||||
|
||||
/// Stop the timer, and if it is repeating restart it using the repeat value
|
||||
/// as the timeout. If the timer has never been started before it returns UV_EINVAL.
|
||||
pub fn again(self: Timer) !void {
|
||||
try errors.convertError(c.uv_timer_again(self.handle));
|
||||
}
|
||||
|
||||
/// Get the timer repeat value.
|
||||
pub fn getRepeat(self: Timer) u64 {
|
||||
return c.uv_timer_get_repeat(self.handle);
|
||||
}
|
||||
|
||||
/// Set the repeat interval value in milliseconds. The timer will be scheduled
|
||||
/// to run on the given interval, regardless of the callback execution duration,
|
||||
/// and will follow normal timer semantics in the case of a time-slice overrun.
|
||||
pub fn setRepeat(self: Timer, repeat: u64) void {
|
||||
c.uv_timer_set_repeat(self.handle, repeat);
|
||||
}
|
||||
|
||||
test "Timer" {
|
||||
var loop = try Loop.init(testing.allocator);
|
||||
defer loop.deinit(testing.allocator);
|
||||
|
Reference in New Issue
Block a user