don't blink cursor when losing focus

This commit is contained in:
Mitchell Hashimoto
2022-04-22 17:40:37 -07:00
parent 0b689723f7
commit 87899421bd
4 changed files with 66 additions and 3 deletions

View File

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

View File

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

View File

@ -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 => {

View File

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