mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +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.
|
// posted by the libuv watcher so that we trigger a libuv loop tick.
|
||||||
try glfw.waitEvents();
|
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
|
// Run the libuv loop
|
||||||
try embed.loopRun();
|
try embed.loopRun();
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,10 @@ terminal: Terminal,
|
|||||||
/// Timer that blinks the cursor.
|
/// Timer that blinks the cursor.
|
||||||
cursor_timer: libuv.Timer,
|
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
|
/// Create a new window. This allocates and returns a pointer because we
|
||||||
/// need a stable pointer for user data callbacks. Therefore, a stack-only
|
/// need a stable pointer for user data callbacks. Therefore, a stack-only
|
||||||
/// initialization is not currently possible.
|
/// initialization is not currently possible.
|
||||||
@ -119,6 +123,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop) !*Window {
|
|||||||
window.setSizeCallback(sizeCallback);
|
window.setSizeCallback(sizeCallback);
|
||||||
window.setCharCallback(charCallback);
|
window.setCharCallback(charCallback);
|
||||||
window.setKeyCallback(keyCallback);
|
window.setKeyCallback(keyCallback);
|
||||||
|
window.setFocusCallback(focusCallback);
|
||||||
|
|
||||||
return self;
|
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 {
|
fn cursorTimerCallback(t: *libuv.Timer) void {
|
||||||
const win = t.getData(Window) orelse return;
|
const win = t.getData(Window) orelse return;
|
||||||
win.grid.cursor_visible = !win.grid.cursor_visible;
|
win.grid.cursor_visible = !win.grid.cursor_visible;
|
||||||
|
@ -13,11 +13,14 @@ const Loop = @import("Loop.zig");
|
|||||||
const Sem = @import("Sem.zig");
|
const Sem = @import("Sem.zig");
|
||||||
const Thread = @import("Thread.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,
|
loop: Loop,
|
||||||
sem: Sem,
|
sem: Sem,
|
||||||
terminate: TerminateAtomic,
|
terminate: BoolAtomic,
|
||||||
|
sleeping: BoolAtomic,
|
||||||
callback: fn () void,
|
callback: fn () void,
|
||||||
thread: ?Thread,
|
thread: ?Thread,
|
||||||
|
|
||||||
@ -27,7 +30,8 @@ pub fn init(alloc: Allocator, loop: Loop, callback: fn () void) !Embed {
|
|||||||
return Embed{
|
return Embed{
|
||||||
.loop = loop,
|
.loop = loop,
|
||||||
.sem = try Sem.init(alloc, 0),
|
.sem = try Sem.init(alloc, 0),
|
||||||
.terminate = TerminateAtomic.init(false),
|
.terminate = BoolAtomic.init(false),
|
||||||
|
.sleeping = BoolAtomic.init(false),
|
||||||
.callback = callback,
|
.callback = callback,
|
||||||
.thread = null,
|
.thread = null,
|
||||||
};
|
};
|
||||||
@ -77,6 +81,19 @@ fn threadMain(self: *Embed) void {
|
|||||||
while (self.terminate.load(.SeqCst) == false) {
|
while (self.terminate.load(.SeqCst) == false) {
|
||||||
const fd = self.loop.backendFd() catch unreachable;
|
const fd = self.loop.backendFd() catch unreachable;
|
||||||
const timeout = self.loop.backendTimeout();
|
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) {
|
switch (builtin.os.tag) {
|
||||||
// epoll
|
// epoll
|
||||||
.linux => {
|
.linux => {
|
||||||
|
@ -56,6 +56,24 @@ pub fn stop(self: Timer) !void {
|
|||||||
try errors.convertError(c.uv_timer_stop(self.handle));
|
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" {
|
test "Timer" {
|
||||||
var loop = try Loop.init(testing.allocator);
|
var loop = try Loop.init(testing.allocator);
|
||||||
defer loop.deinit(testing.allocator);
|
defer loop.deinit(testing.allocator);
|
||||||
|
Reference in New Issue
Block a user