mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
pass around the event loop, setup a timer to prove it works
This commit is contained in:
28
src/App.zig
28
src/App.zig
@ -18,21 +18,30 @@ alloc: Allocator,
|
|||||||
/// single window operations.
|
/// single window operations.
|
||||||
window: *Window,
|
window: *Window,
|
||||||
|
|
||||||
// The main event loop for the application.
|
// 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
|
||||||
|
// so that users of the loop always have an allocator.
|
||||||
loop: libuv.Loop,
|
loop: libuv.Loop,
|
||||||
|
|
||||||
/// Initialize the main app instance. This creates the main window, sets
|
/// Initialize the main app instance. This creates the main window, sets
|
||||||
/// up the renderer state, compiles the shaders, etc. This is the primary
|
/// up the renderer state, compiles the shaders, etc. This is the primary
|
||||||
/// "startup" logic.
|
/// "startup" logic.
|
||||||
pub fn init(alloc: Allocator) !App {
|
pub fn init(alloc: Allocator) !App {
|
||||||
// Create the window
|
|
||||||
var window = try Window.create(alloc);
|
|
||||||
errdefer window.destroy();
|
|
||||||
|
|
||||||
// Create the event loop
|
// Create the event loop
|
||||||
var loop = try libuv.Loop.init(alloc);
|
var loop = try libuv.Loop.init(alloc);
|
||||||
errdefer loop.deinit(alloc);
|
errdefer loop.deinit(alloc);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
loop.setData(allocPtr);
|
||||||
|
|
||||||
|
// Create the window
|
||||||
|
var window = try Window.create(alloc, loop);
|
||||||
|
errdefer window.destroy();
|
||||||
|
|
||||||
return App{
|
return App{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.window = window,
|
.window = window,
|
||||||
@ -42,6 +51,15 @@ pub fn init(alloc: Allocator) !App {
|
|||||||
|
|
||||||
pub fn deinit(self: *App) void {
|
pub fn deinit(self: *App) void {
|
||||||
self.window.destroy();
|
self.window.destroy();
|
||||||
|
|
||||||
|
// 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 unreachable;
|
||||||
|
|
||||||
|
// Dealloc our allocator copy
|
||||||
|
self.alloc.destroy(self.loop.getData(Allocator).?);
|
||||||
|
|
||||||
self.loop.deinit(self.alloc);
|
self.loop.deinit(self.alloc);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
17
src/Grid.zig
17
src/Grid.zig
@ -10,6 +10,7 @@ const FontAtlas = @import("FontAtlas.zig");
|
|||||||
const Terminal = @import("terminal/Terminal.zig");
|
const Terminal = @import("terminal/Terminal.zig");
|
||||||
const gl = @import("opengl.zig");
|
const gl = @import("opengl.zig");
|
||||||
const gb = @import("gb_math.zig");
|
const gb = @import("gb_math.zig");
|
||||||
|
const libuv = @import("libuv/main.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.grid);
|
const log = std.log.scoped(.grid);
|
||||||
|
|
||||||
@ -34,6 +35,9 @@ texture: gl.Texture,
|
|||||||
/// The font atlas.
|
/// The font atlas.
|
||||||
font_atlas: FontAtlas,
|
font_atlas: FontAtlas,
|
||||||
|
|
||||||
|
/// The timer for cursor blining.
|
||||||
|
cursor_timer: libuv.Timer,
|
||||||
|
|
||||||
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
||||||
const GPUCell = struct {
|
const GPUCell = struct {
|
||||||
/// vec2 grid_coord
|
/// vec2 grid_coord
|
||||||
@ -68,7 +72,11 @@ const GPUCell = struct {
|
|||||||
mode: u8,
|
mode: u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(alloc: Allocator) !Grid {
|
pub fn init(alloc: Allocator, loop: libuv.Loop) !Grid {
|
||||||
|
// Setup the timer for our cursor.
|
||||||
|
var timer = try libuv.Timer.init(alloc, loop);
|
||||||
|
errdefer timer.deinit(alloc);
|
||||||
|
|
||||||
// Initialize our font atlas. We will initially populate the
|
// Initialize our font atlas. We will initially populate the
|
||||||
// font atlas with all the visible ASCII characters since they are common.
|
// font atlas with all the visible ASCII characters since they are common.
|
||||||
var atlas = try Atlas.init(alloc, 512);
|
var atlas = try Atlas.init(alloc, 512);
|
||||||
@ -206,10 +214,17 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
.vbo = vbo,
|
.vbo = vbo,
|
||||||
.texture = tex,
|
.texture = tex,
|
||||||
.font_atlas = font,
|
.font_atlas = font,
|
||||||
|
.cursor_timer = timer,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Grid) void {
|
pub fn deinit(self: *Grid) void {
|
||||||
|
self.cursor_timer.close((struct {
|
||||||
|
fn callback(t: *libuv.Timer) void {
|
||||||
|
const alloc = t.loop().getData(Allocator).?;
|
||||||
|
t.deinit(alloc.*);
|
||||||
|
}
|
||||||
|
}).callback);
|
||||||
self.font_atlas.atlas.deinit(self.alloc);
|
self.font_atlas.atlas.deinit(self.alloc);
|
||||||
self.font_atlas.deinit(self.alloc);
|
self.font_atlas.deinit(self.alloc);
|
||||||
self.texture.destroy();
|
self.texture.destroy();
|
||||||
|
@ -11,6 +11,7 @@ const Allocator = std.mem.Allocator;
|
|||||||
const Grid = @import("Grid.zig");
|
const Grid = @import("Grid.zig");
|
||||||
const glfw = @import("glfw");
|
const glfw = @import("glfw");
|
||||||
const gl = @import("opengl.zig");
|
const gl = @import("opengl.zig");
|
||||||
|
const libuv = @import("libuv/main.zig");
|
||||||
const Pty = @import("Pty.zig");
|
const Pty = @import("Pty.zig");
|
||||||
const Terminal = @import("terminal/Terminal.zig");
|
const Terminal = @import("terminal/Terminal.zig");
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ terminal: Terminal,
|
|||||||
/// 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.
|
||||||
pub fn create(alloc: Allocator) !*Window {
|
pub fn create(alloc: Allocator, loop: libuv.Loop) !*Window {
|
||||||
var self = try alloc.create(Window);
|
var self = try alloc.create(Window);
|
||||||
errdefer alloc.destroy(self);
|
errdefer alloc.destroy(self);
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ pub fn create(alloc: Allocator) !*Window {
|
|||||||
|
|
||||||
// Create our terminal grid with the initial window size
|
// Create our terminal grid with the initial window size
|
||||||
const window_size = try window.getSize();
|
const window_size = try window.getSize();
|
||||||
var grid = try Grid.init(alloc);
|
var grid = try Grid.init(alloc, loop);
|
||||||
try grid.setScreenSize(.{ .width = window_size.width, .height = window_size.height });
|
try grid.setScreenSize(.{ .width = window_size.width, .height = window_size.height });
|
||||||
|
|
||||||
// Create our pty
|
// Create our pty
|
||||||
|
@ -70,6 +70,19 @@ pub fn backendTimeout(self: Loop) c_int {
|
|||||||
return c.uv_backend_timeout(self.loop);
|
return c.uv_backend_timeout(self.loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets loop->data to data.
|
||||||
|
pub fn setData(self: Loop, pointer: ?*anyopaque) void {
|
||||||
|
c.uv_loop_set_data(self.loop, pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns loop->data.
|
||||||
|
pub fn getData(self: Loop, comptime DT: type) ?*DT {
|
||||||
|
return if (c.uv_loop_get_data(self.loop)) |ptr|
|
||||||
|
@ptrCast(?*DT, @alignCast(@alignOf(DT), ptr))
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
/// Mode used to run the loop with uv_run().
|
/// Mode used to run the loop with uv_run().
|
||||||
pub const RunMode = enum(c.uv_run_mode) {
|
pub const RunMode = enum(c.uv_run_mode) {
|
||||||
default = c.UV_RUN_DEFAULT,
|
default = c.UV_RUN_DEFAULT,
|
||||||
@ -81,6 +94,10 @@ test {
|
|||||||
var loop = try init(testing.allocator);
|
var loop = try init(testing.allocator);
|
||||||
defer loop.deinit(testing.allocator);
|
defer loop.deinit(testing.allocator);
|
||||||
|
|
||||||
|
var data: u8 = 42;
|
||||||
|
loop.setData(&data);
|
||||||
|
try testing.expect(loop.getData(u8).?.* == 42);
|
||||||
|
|
||||||
try testing.expect((try loop.backendFd()) > 0);
|
try testing.expect((try loop.backendFd()) > 0);
|
||||||
try testing.expectEqual(@as(u32, 0), try loop.run(.nowait));
|
try testing.expectEqual(@as(u32, 0), try loop.run(.nowait));
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ test "Timer: close callback" {
|
|||||||
var data: u8 = 42;
|
var data: u8 = 42;
|
||||||
timer.setData(&data);
|
timer.setData(&data);
|
||||||
timer.close((struct {
|
timer.close((struct {
|
||||||
fn callback(v: Timer) void {
|
fn callback(v: *Timer) void {
|
||||||
var dataPtr = v.getData(u8).?;
|
var dataPtr = v.getData(u8).?;
|
||||||
dataPtr.* = 24;
|
dataPtr.* = 24;
|
||||||
}
|
}
|
||||||
|
@ -27,15 +27,15 @@ pub fn Handle(comptime T: type) type {
|
|||||||
//
|
//
|
||||||
// In-progress requests, like uv_connect_t or uv_write_t, are cancelled
|
// In-progress requests, like uv_connect_t or uv_write_t, are cancelled
|
||||||
// and have their callbacks called asynchronously with status=UV_ECANCELED.
|
// and have their callbacks called asynchronously with status=UV_ECANCELED.
|
||||||
pub fn close(self: T, comptime cb: ?fn (T) void) void {
|
pub fn close(self: T, comptime cb: ?fn (*T) void) void {
|
||||||
const cbParam = if (cb) |f|
|
const cbParam = if (cb) |f|
|
||||||
(struct {
|
(struct {
|
||||||
pub fn callback(handle: [*c]c.uv_handle_t) callconv(.C) void {
|
pub fn callback(handle: [*c]c.uv_handle_t) callconv(.C) void {
|
||||||
// We get the raw handle, so we need to reconstruct
|
// We get the raw handle, so we need to reconstruct
|
||||||
// the T. This is mutable because a lot of the libuv APIs
|
// the T. This is mutable because a lot of the libuv APIs
|
||||||
// are non-const but modifying it makes no sense.
|
// are non-const but modifying it makes no sense.
|
||||||
const param: T = .{ .handle = @ptrCast(HandleType, handle) };
|
var param: T = .{ .handle = @ptrCast(HandleType, handle) };
|
||||||
@call(.{ .modifier = .always_inline }, f, .{param});
|
@call(.{ .modifier = .always_inline }, f, .{¶m});
|
||||||
}
|
}
|
||||||
}).callback
|
}).callback
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user