mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
renderer uses libxev
Still some bugs and TODOs, but it is workable.
This commit is contained in:
@ -441,7 +441,7 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
pub fn destroy(self: *Window) void {
|
pub fn destroy(self: *Window) void {
|
||||||
{
|
{
|
||||||
// Stop rendering thread
|
// Stop rendering thread
|
||||||
self.renderer_thread.stop.send() catch |err|
|
self.renderer_thread.stop.notify() catch |err|
|
||||||
log.err("error notifying renderer thread to stop, may stall err={}", .{err});
|
log.err("error notifying renderer thread to stop, may stall err={}", .{err});
|
||||||
self.renderer_thr.join();
|
self.renderer_thr.join();
|
||||||
|
|
||||||
@ -652,7 +652,7 @@ pub fn setFontSize(self: *Window, size: font.face.DesiredSize) void {
|
|||||||
/// isn't guaranteed to happen immediately but it will happen as soon as
|
/// isn't guaranteed to happen immediately but it will happen as soon as
|
||||||
/// practical.
|
/// practical.
|
||||||
fn queueRender(self: *const Window) !void {
|
fn queueRender(self: *const Window) !void {
|
||||||
try self.renderer_thread.wakeup.send();
|
try self.renderer_thread.wakeup.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sizeCallback(self: *Window, size: apprt.WindowSize) !void {
|
pub fn sizeCallback(self: *Window, size: apprt.WindowSize) !void {
|
||||||
|
@ -4,7 +4,7 @@ pub const Thread = @This();
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const libuv = @import("libuv");
|
const xev = @import("xev");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const apprt = @import("../apprt.zig");
|
const apprt = @import("../apprt.zig");
|
||||||
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
||||||
@ -14,28 +14,38 @@ const trace = tracy.trace;
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const log = std.log.scoped(.renderer_thread);
|
const log = std.log.scoped(.renderer_thread);
|
||||||
|
|
||||||
|
const CURSOR_BLINK_INTERVAL = 600;
|
||||||
|
|
||||||
/// The type used for sending messages to the IO thread. For now this is
|
/// The type used for sending messages to the IO thread. For now this is
|
||||||
/// hardcoded with a capacity. We can make this a comptime parameter in
|
/// hardcoded with a capacity. We can make this a comptime parameter in
|
||||||
/// the future if we want it configurable.
|
/// the future if we want it configurable.
|
||||||
pub const Mailbox = BlockingQueue(renderer.Message, 64);
|
pub const Mailbox = BlockingQueue(renderer.Message, 64);
|
||||||
|
|
||||||
|
/// Allocator used for some state
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
|
||||||
/// The main event loop for the application. The user data of this loop
|
/// The main event loop for the application. The user data of this loop
|
||||||
/// is always the allocator used to create the loop. This is a convenience
|
/// is always the allocator used to create the loop. This is a convenience
|
||||||
/// so that users of the loop always have an allocator.
|
/// so that users of the loop always have an allocator.
|
||||||
loop: libuv.Loop,
|
loop: xev.Loop,
|
||||||
|
|
||||||
/// This can be used to wake up the renderer and force a render safely from
|
/// This can be used to wake up the renderer and force a render safely from
|
||||||
/// any thread.
|
/// any thread.
|
||||||
wakeup: libuv.Async,
|
wakeup: xev.Async,
|
||||||
|
wakeup_c: xev.Completion = .{},
|
||||||
|
|
||||||
/// This can be used to stop the renderer on the next loop iteration.
|
/// This can be used to stop the renderer on the next loop iteration.
|
||||||
stop: libuv.Async,
|
stop: xev.Async,
|
||||||
|
stop_c: xev.Completion = .{},
|
||||||
|
|
||||||
/// The timer used for rendering
|
/// The timer used for rendering
|
||||||
render_h: libuv.Timer,
|
render_h: xev.Timer,
|
||||||
|
render_c: xev.Completion = .{},
|
||||||
|
|
||||||
/// The timer used for cursor blinking
|
/// The timer used for cursor blinking
|
||||||
cursor_h: libuv.Timer,
|
cursor_h: xev.Timer,
|
||||||
|
cursor_c: xev.Completion = .{},
|
||||||
|
cursor_c_cancel: xev.Completion = .{},
|
||||||
|
|
||||||
/// The window we're rendering to.
|
/// The window we're rendering to.
|
||||||
window: apprt.runtime.Window,
|
window: apprt.runtime.Window,
|
||||||
@ -59,62 +69,32 @@ pub fn init(
|
|||||||
renderer_impl: *renderer.Renderer,
|
renderer_impl: *renderer.Renderer,
|
||||||
state: *renderer.State,
|
state: *renderer.State,
|
||||||
) !Thread {
|
) !Thread {
|
||||||
// We always store allocator pointer on the loop data so that
|
|
||||||
// handles can use our global allocator.
|
|
||||||
const allocPtr = try alloc.create(Allocator);
|
|
||||||
errdefer alloc.destroy(allocPtr);
|
|
||||||
allocPtr.* = alloc;
|
|
||||||
|
|
||||||
// Create our event loop.
|
// Create our event loop.
|
||||||
var loop = try libuv.Loop.init(alloc);
|
var loop = try xev.Loop.init(.{});
|
||||||
errdefer {
|
errdefer loop.deinit();
|
||||||
// Run the loop once to close any of our handles
|
|
||||||
_ = loop.run(.nowait) catch 0;
|
|
||||||
loop.deinit(alloc);
|
|
||||||
}
|
|
||||||
loop.setData(allocPtr);
|
|
||||||
|
|
||||||
// This async handle is used to "wake up" the renderer and force a render.
|
// This async handle is used to "wake up" the renderer and force a render.
|
||||||
var wakeup_h = try libuv.Async.init(alloc, loop, wakeupCallback);
|
var wakeup_h = try xev.Async.init();
|
||||||
errdefer wakeup_h.close((struct {
|
errdefer wakeup_h.deinit();
|
||||||
fn callback(h: *libuv.Async) void {
|
|
||||||
const loop_alloc = h.loop().getData(Allocator).?.*;
|
|
||||||
h.deinit(loop_alloc);
|
|
||||||
}
|
|
||||||
}).callback);
|
|
||||||
|
|
||||||
// This async handle is used to stop the loop and force the thread to end.
|
// This async handle is used to stop the loop and force the thread to end.
|
||||||
var stop_h = try libuv.Async.init(alloc, loop, stopCallback);
|
var stop_h = try xev.Async.init();
|
||||||
errdefer stop_h.close((struct {
|
errdefer stop_h.deinit();
|
||||||
fn callback(h: *libuv.Async) void {
|
|
||||||
const loop_alloc = h.loop().getData(Allocator).?.*;
|
|
||||||
h.deinit(loop_alloc);
|
|
||||||
}
|
|
||||||
}).callback);
|
|
||||||
|
|
||||||
// The primary timer for rendering.
|
// The primary timer for rendering.
|
||||||
var render_h = try libuv.Timer.init(alloc, loop);
|
var render_h = try xev.Timer.init();
|
||||||
errdefer render_h.close((struct {
|
errdefer render_h.deinit();
|
||||||
fn callback(h: *libuv.Timer) void {
|
|
||||||
const loop_alloc = h.loop().getData(Allocator).?.*;
|
|
||||||
h.deinit(loop_alloc);
|
|
||||||
}
|
|
||||||
}).callback);
|
|
||||||
|
|
||||||
// Setup a timer for blinking the cursor
|
// Setup a timer for blinking the cursor
|
||||||
var cursor_timer = try libuv.Timer.init(alloc, loop);
|
var cursor_timer = try xev.Timer.init();
|
||||||
errdefer cursor_timer.close((struct {
|
errdefer cursor_timer.deinit();
|
||||||
fn callback(t: *libuv.Timer) void {
|
|
||||||
const alloc_h = t.loop().getData(Allocator).?.*;
|
|
||||||
t.deinit(alloc_h);
|
|
||||||
}
|
|
||||||
}).callback);
|
|
||||||
|
|
||||||
// The mailbox for messaging this thread
|
// The mailbox for messaging this thread
|
||||||
var mailbox = try Mailbox.create(alloc);
|
var mailbox = try Mailbox.create(alloc);
|
||||||
errdefer mailbox.destroy(alloc);
|
errdefer mailbox.destroy(alloc);
|
||||||
|
|
||||||
return Thread{
|
return Thread{
|
||||||
|
.alloc = alloc,
|
||||||
.loop = loop,
|
.loop = loop,
|
||||||
.wakeup = wakeup_h,
|
.wakeup = wakeup_h,
|
||||||
.stop = stop_h,
|
.stop = stop_h,
|
||||||
@ -130,49 +110,14 @@ pub fn init(
|
|||||||
/// Clean up the thread. This is only safe to call once the thread
|
/// Clean up the thread. This is only safe to call once the thread
|
||||||
/// completes executing; the caller must join prior to this.
|
/// completes executing; the caller must join prior to this.
|
||||||
pub fn deinit(self: *Thread) void {
|
pub fn deinit(self: *Thread) void {
|
||||||
// Get a copy to our allocator
|
self.stop.deinit();
|
||||||
const alloc_ptr = self.loop.getData(Allocator).?;
|
self.wakeup.deinit();
|
||||||
const alloc = alloc_ptr.*;
|
self.render_h.deinit();
|
||||||
|
self.cursor_h.deinit();
|
||||||
// Schedule our handles to close
|
self.loop.deinit();
|
||||||
self.stop.close((struct {
|
|
||||||
fn callback(h: *libuv.Async) void {
|
|
||||||
const handle_alloc = h.loop().getData(Allocator).?.*;
|
|
||||||
h.deinit(handle_alloc);
|
|
||||||
}
|
|
||||||
}).callback);
|
|
||||||
self.wakeup.close((struct {
|
|
||||||
fn callback(h: *libuv.Async) void {
|
|
||||||
const handle_alloc = h.loop().getData(Allocator).?.*;
|
|
||||||
h.deinit(handle_alloc);
|
|
||||||
}
|
|
||||||
}).callback);
|
|
||||||
self.render_h.close((struct {
|
|
||||||
fn callback(h: *libuv.Timer) void {
|
|
||||||
const handle_alloc = h.loop().getData(Allocator).?.*;
|
|
||||||
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
|
|
||||||
// one more run through to finalize all the closes.
|
|
||||||
_ = self.loop.run(.default) catch |err|
|
|
||||||
log.err("error finalizing event loop: {}", .{err});
|
|
||||||
|
|
||||||
// Nothing can possibly access the mailbox anymore, destroy it.
|
// Nothing can possibly access the mailbox anymore, destroy it.
|
||||||
self.mailbox.destroy(alloc);
|
self.mailbox.destroy(self.alloc);
|
||||||
|
|
||||||
// Dealloc our allocator copy
|
|
||||||
alloc.destroy(alloc_ptr);
|
|
||||||
|
|
||||||
self.loop.deinit(alloc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The main entrypoint for the thread.
|
/// The main entrypoint for the thread.
|
||||||
@ -193,44 +138,49 @@ fn threadMain_(self: *Thread) !void {
|
|||||||
try self.renderer.threadEnter(self.window);
|
try self.renderer.threadEnter(self.window);
|
||||||
defer self.renderer.threadExit();
|
defer self.renderer.threadExit();
|
||||||
|
|
||||||
// Set up our async handler to support rendering
|
// Start the async handlers
|
||||||
self.wakeup.setData(self);
|
self.wakeup.wait(&self.loop, &self.wakeup_c, Thread, self, wakeupCallback);
|
||||||
defer self.wakeup.setData(null);
|
self.stop.wait(&self.loop, &self.stop_c, Thread, self, stopCallback);
|
||||||
|
|
||||||
// Set up our timer and start it for rendering
|
// Send an initial wakeup message so that we render right away.
|
||||||
self.render_h.setData(self);
|
try self.wakeup.notify();
|
||||||
defer self.render_h.setData(null);
|
|
||||||
try self.wakeup.send();
|
|
||||||
|
|
||||||
// Setup a timer for blinking the cursor
|
// Start blinking the cursor.
|
||||||
self.cursor_h.setData(self);
|
self.cursor_h.run(
|
||||||
try self.cursor_h.start(cursorTimerCallback, 600, 600);
|
&self.loop,
|
||||||
|
&self.cursor_c,
|
||||||
|
CURSOR_BLINK_INTERVAL,
|
||||||
|
Thread,
|
||||||
|
self,
|
||||||
|
cursorTimerCallback,
|
||||||
|
);
|
||||||
|
|
||||||
// If we are using tracy, then we setup a prepare handle so that
|
// If we are using tracy, then we setup a prepare handle so that
|
||||||
// we can mark the frame.
|
// we can mark the frame.
|
||||||
var frame_h: libuv.Prepare = if (!tracy.enabled) undefined else frame_h: {
|
// TODO
|
||||||
const alloc_ptr = self.loop.getData(Allocator).?;
|
// var frame_h: libuv.Prepare = if (!tracy.enabled) undefined else frame_h: {
|
||||||
const alloc = alloc_ptr.*;
|
// const alloc_ptr = self.loop.getData(Allocator).?;
|
||||||
const h = try libuv.Prepare.init(alloc, self.loop);
|
// const alloc = alloc_ptr.*;
|
||||||
h.setData(self);
|
// const h = try libuv.Prepare.init(alloc, self.loop);
|
||||||
try h.start(prepFrameCallback);
|
// h.setData(self);
|
||||||
|
// try h.start(prepFrameCallback);
|
||||||
break :frame_h h;
|
//
|
||||||
};
|
// break :frame_h h;
|
||||||
defer if (tracy.enabled) {
|
// };
|
||||||
frame_h.close((struct {
|
// defer if (tracy.enabled) {
|
||||||
fn callback(h: *libuv.Prepare) void {
|
// frame_h.close((struct {
|
||||||
const alloc_h = h.loop().getData(Allocator).?.*;
|
// fn callback(h: *libuv.Prepare) void {
|
||||||
h.deinit(alloc_h);
|
// const alloc_h = h.loop().getData(Allocator).?.*;
|
||||||
}
|
// h.deinit(alloc_h);
|
||||||
}).callback);
|
// }
|
||||||
_ = self.loop.run(.nowait) catch {};
|
// }).callback);
|
||||||
};
|
// _ = self.loop.run(.nowait) catch {};
|
||||||
|
// };
|
||||||
|
|
||||||
// Run
|
// Run
|
||||||
log.debug("starting renderer thread", .{});
|
log.debug("starting renderer thread", .{});
|
||||||
defer log.debug("exiting renderer thread", .{});
|
defer log.debug("exiting renderer thread", .{});
|
||||||
_ = try self.loop.run(.default);
|
_ = try self.loop.run(.until_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drain the mailbox.
|
/// Drain the mailbox.
|
||||||
@ -247,16 +197,30 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
|
|
||||||
if (!v) {
|
if (!v) {
|
||||||
// If we're not focused, then we stop the cursor blink
|
// If we're not focused, then we stop the cursor blink
|
||||||
try self.cursor_h.stop();
|
if (self.cursor_c.state() == .active and
|
||||||
|
self.cursor_c_cancel.state() == .dead)
|
||||||
|
{
|
||||||
|
self.cursor_h.cancel(
|
||||||
|
&self.loop,
|
||||||
|
&self.cursor_c,
|
||||||
|
&self.cursor_c_cancel,
|
||||||
|
void,
|
||||||
|
null,
|
||||||
|
cursorCancelCallback,
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we're focused, we immediately show the cursor again
|
// If we're focused, we immediately show the cursor again
|
||||||
// and then restart the timer.
|
// and then restart the timer.
|
||||||
if (!try self.cursor_h.isActive()) {
|
if (self.cursor_c.state() != .active) {
|
||||||
self.renderer.blinkCursor(true);
|
self.renderer.blinkCursor(true);
|
||||||
try self.cursor_h.start(
|
self.cursor_h.run(
|
||||||
|
&self.loop,
|
||||||
|
&self.cursor_c,
|
||||||
|
CURSOR_BLINK_INTERVAL,
|
||||||
|
Thread,
|
||||||
|
self,
|
||||||
cursorTimerCallback,
|
cursorTimerCallback,
|
||||||
self.cursor_h.getRepeat(),
|
|
||||||
self.cursor_h.getRepeat(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,8 +228,16 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
|
|
||||||
.reset_cursor_blink => {
|
.reset_cursor_blink => {
|
||||||
self.renderer.blinkCursor(true);
|
self.renderer.blinkCursor(true);
|
||||||
if (try self.cursor_h.isActive()) {
|
if (self.cursor_c.state() == .active) {
|
||||||
_ = try self.cursor_h.again();
|
self.cursor_h.reset(
|
||||||
|
&self.loop,
|
||||||
|
&self.cursor_c,
|
||||||
|
&self.cursor_c_cancel,
|
||||||
|
CURSOR_BLINK_INTERVAL,
|
||||||
|
Thread,
|
||||||
|
self,
|
||||||
|
cursorTimerCallback,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -280,15 +252,21 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wakeupCallback(h: *libuv.Async) void {
|
fn wakeupCallback(
|
||||||
|
self_: ?*Thread,
|
||||||
|
_: *xev.Loop,
|
||||||
|
_: *xev.Completion,
|
||||||
|
r: xev.Async.WaitError!void,
|
||||||
|
) xev.CallbackAction {
|
||||||
|
_ = r catch |err| {
|
||||||
|
log.err("error in wakeup err={}", .{err});
|
||||||
|
return .rearm;
|
||||||
|
};
|
||||||
|
|
||||||
const zone = trace(@src());
|
const zone = trace(@src());
|
||||||
defer zone.end();
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
const t = self_.?;
|
||||||
// This shouldn't happen so we log it.
|
|
||||||
log.warn("render callback fired without data set", .{});
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
// When we wake up, we check the mailbox. Mailbox producers should
|
// When we wake up, we check the mailbox. Mailbox producers should
|
||||||
// wake up our thread after publishing.
|
// wake up our thread after publishing.
|
||||||
@ -296,48 +274,104 @@ fn wakeupCallback(h: *libuv.Async) void {
|
|||||||
log.err("error draining mailbox err={}", .{err});
|
log.err("error draining mailbox err={}", .{err});
|
||||||
|
|
||||||
// If the timer is already active then we don't have to do anything.
|
// If the timer is already active then we don't have to do anything.
|
||||||
const active = t.render_h.isActive() catch true;
|
if (t.render_c.state() == .active) return .rearm;
|
||||||
if (active) return;
|
|
||||||
|
|
||||||
// Timer is not active, let's start it
|
// Timer is not active, let's start it
|
||||||
t.render_h.start(renderCallback, 10, 0) catch |err|
|
t.render_h.run(
|
||||||
log.warn("render timer failed to start err={}", .{err});
|
&t.loop,
|
||||||
|
&t.render_c,
|
||||||
|
10,
|
||||||
|
Thread,
|
||||||
|
t,
|
||||||
|
renderCallback,
|
||||||
|
);
|
||||||
|
|
||||||
|
return .rearm;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderCallback(h: *libuv.Timer) void {
|
fn renderCallback(
|
||||||
|
self_: ?*Thread,
|
||||||
|
_: *xev.Loop,
|
||||||
|
_: *xev.Completion,
|
||||||
|
r: xev.Timer.RunError!void,
|
||||||
|
) xev.CallbackAction {
|
||||||
const zone = trace(@src());
|
const zone = trace(@src());
|
||||||
defer zone.end();
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
_ = r catch unreachable;
|
||||||
|
const t = self_ orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
return;
|
return .disarm;
|
||||||
};
|
};
|
||||||
|
|
||||||
t.renderer.render(t.window, t.state) catch |err|
|
t.renderer.render(t.window, t.state) catch |err|
|
||||||
log.warn("error rendering err={}", .{err});
|
log.warn("error rendering err={}", .{err});
|
||||||
|
return .disarm;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cursorTimerCallback(h: *libuv.Timer) void {
|
fn cursorTimerCallback(
|
||||||
|
self_: ?*Thread,
|
||||||
|
_: *xev.Loop,
|
||||||
|
_: *xev.Completion,
|
||||||
|
r: xev.Timer.RunError!void,
|
||||||
|
) xev.CallbackAction {
|
||||||
const zone = trace(@src());
|
const zone = trace(@src());
|
||||||
defer zone.end();
|
defer zone.end();
|
||||||
|
|
||||||
const t = h.getData(Thread) orelse {
|
_ = r catch |err| switch (err) {
|
||||||
|
// This is sent when our timer is canceled. That's fine.
|
||||||
|
error.Canceled => return .disarm,
|
||||||
|
|
||||||
|
else => {
|
||||||
|
log.warn("error in cursor timer callback err={}", .{err});
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const t = self_ orelse {
|
||||||
// This shouldn't happen so we log it.
|
// This shouldn't happen so we log it.
|
||||||
log.warn("render callback fired without data set", .{});
|
log.warn("render callback fired without data set", .{});
|
||||||
return;
|
return .disarm;
|
||||||
};
|
};
|
||||||
|
|
||||||
t.renderer.blinkCursor(false);
|
t.renderer.blinkCursor(false);
|
||||||
t.wakeup.send() catch {};
|
t.wakeup.notify() catch {};
|
||||||
|
|
||||||
|
t.cursor_h.run(&t.loop, &t.cursor_c, CURSOR_BLINK_INTERVAL, Thread, t, cursorTimerCallback);
|
||||||
|
return .disarm;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepFrameCallback(h: *libuv.Prepare) void {
|
fn cursorCancelCallback(
|
||||||
_ = h;
|
_: ?*void,
|
||||||
|
_: *xev.Loop,
|
||||||
|
_: *xev.Completion,
|
||||||
|
r: xev.Timer.CancelError!void,
|
||||||
|
) xev.CallbackAction {
|
||||||
|
_ = r catch |err| switch (err) {
|
||||||
|
error.NotFound => {},
|
||||||
|
else => {
|
||||||
|
log.warn("error in cursor cancel callback err={}", .{err});
|
||||||
|
unreachable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
tracy.frameMark();
|
return .disarm;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stopCallback(h: *libuv.Async) void {
|
// fn prepFrameCallback(h: *libuv.Prepare) void {
|
||||||
h.loop().stop();
|
// _ = h;
|
||||||
|
//
|
||||||
|
// tracy.frameMark();
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn stopCallback(
|
||||||
|
self_: ?*Thread,
|
||||||
|
_: *xev.Loop,
|
||||||
|
_: *xev.Completion,
|
||||||
|
r: xev.Async.WaitError!void,
|
||||||
|
) xev.CallbackAction {
|
||||||
|
_ = r catch unreachable;
|
||||||
|
self_.?.loop.stop();
|
||||||
|
return .disarm;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ const Window = @import("../Window.zig");
|
|||||||
const Pty = @import("../Pty.zig");
|
const Pty = @import("../Pty.zig");
|
||||||
const SegmentedPool = @import("../segmented_pool.zig").SegmentedPool;
|
const SegmentedPool = @import("../segmented_pool.zig").SegmentedPool;
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
|
const xev = @import("xev");
|
||||||
const libuv = @import("libuv");
|
const libuv = @import("libuv");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
@ -48,7 +49,7 @@ renderer_state: *renderer.State,
|
|||||||
|
|
||||||
/// A handle to wake up the renderer. This hints to the renderer that that
|
/// A handle to wake up the renderer. This hints to the renderer that that
|
||||||
/// a repaint should happen.
|
/// a repaint should happen.
|
||||||
renderer_wakeup: libuv.Async,
|
renderer_wakeup: xev.Async,
|
||||||
|
|
||||||
/// The mailbox for notifying the renderer of things.
|
/// The mailbox for notifying the renderer of things.
|
||||||
renderer_mailbox: *renderer.Thread.Mailbox,
|
renderer_mailbox: *renderer.Thread.Mailbox,
|
||||||
@ -320,7 +321,7 @@ const EventData = struct {
|
|||||||
|
|
||||||
/// A handle to wake up the renderer. This hints to the renderer that that
|
/// A handle to wake up the renderer. This hints to the renderer that that
|
||||||
/// a repaint should happen.
|
/// a repaint should happen.
|
||||||
renderer_wakeup: libuv.Async,
|
renderer_wakeup: xev.Async,
|
||||||
|
|
||||||
/// The mailbox for notifying the renderer of things.
|
/// The mailbox for notifying the renderer of things.
|
||||||
renderer_mailbox: *renderer.Thread.Mailbox,
|
renderer_mailbox: *renderer.Thread.Mailbox,
|
||||||
@ -362,7 +363,7 @@ const EventData = struct {
|
|||||||
/// isn't guaranteed to happen immediately but it will happen as soon as
|
/// isn't guaranteed to happen immediately but it will happen as soon as
|
||||||
/// practical.
|
/// practical.
|
||||||
inline fn queueRender(self: *EventData) !void {
|
inline fn queueRender(self: *EventData) !void {
|
||||||
try self.renderer_wakeup.send();
|
try self.renderer_wakeup.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Queue a write to the pty.
|
/// Queue a write to the pty.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! The options that are used to configure a terminal IO implementation.
|
//! The options that are used to configure a terminal IO implementation.
|
||||||
|
|
||||||
const libuv = @import("libuv");
|
const xev = @import("xev");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const Config = @import("../config.zig").Config;
|
const Config = @import("../config.zig").Config;
|
||||||
const Window = @import("../Window.zig");
|
const Window = @import("../Window.zig");
|
||||||
@ -22,7 +22,7 @@ renderer_state: *renderer.State,
|
|||||||
|
|
||||||
/// A handle to wake up the renderer. This hints to the renderer that that
|
/// A handle to wake up the renderer. This hints to the renderer that that
|
||||||
/// a repaint should happen.
|
/// a repaint should happen.
|
||||||
renderer_wakeup: libuv.Async,
|
renderer_wakeup: xev.Async,
|
||||||
|
|
||||||
/// The mailbox for renderer messages.
|
/// The mailbox for renderer messages.
|
||||||
renderer_mailbox: *renderer.Thread.Mailbox,
|
renderer_mailbox: *renderer.Thread.Mailbox,
|
||||||
|
@ -181,7 +181,7 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
// Trigger a redraw after we've drained so we don't waste cyces
|
// Trigger a redraw after we've drained so we don't waste cyces
|
||||||
// messaging a redraw.
|
// messaging a redraw.
|
||||||
if (redraw) {
|
if (redraw) {
|
||||||
try self.impl.renderer_wakeup.send();
|
try self.impl.renderer_wakeup.notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user