mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-14 15:56:13 +03:00
basic pty opening
This commit is contained in:
@ -7,10 +7,11 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
|
|
||||||
const log = std.log;
|
/// General purpose allocator
|
||||||
|
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
|
|
||||||
|
/// The primary window for the application. We currently support only
|
||||||
|
/// single window operations.
|
||||||
window: *Window,
|
window: *Window,
|
||||||
|
|
||||||
/// Initialize the main app instance. This creates the main window, sets
|
/// Initialize the main app instance. This creates the main window, sets
|
||||||
|
76
src/Pty.zig
Normal file
76
src/Pty.zig
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
//! Linux PTY creation and management. This is just a thin layer on top
|
||||||
|
//! of Linux syscalls. The caller is responsible for detail-oriented handling
|
||||||
|
//! of the returned file handles.
|
||||||
|
const Pty = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
const linux = std.os.linux;
|
||||||
|
const fd_t = std.os.fd_t;
|
||||||
|
const winsize = linux.winsize;
|
||||||
|
const c = @cImport({
|
||||||
|
@cInclude("pty.h");
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The file descriptors for the master and slave side of the pty.
|
||||||
|
master: fd_t,
|
||||||
|
slave: fd_t,
|
||||||
|
|
||||||
|
/// Open a new PTY with the given initial size.
|
||||||
|
pub fn open(size: winsize) !Pty {
|
||||||
|
var master_fd: fd_t = undefined;
|
||||||
|
var slave_fd: fd_t = undefined;
|
||||||
|
if (c.openpty(
|
||||||
|
&master_fd,
|
||||||
|
&slave_fd,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
@ptrCast([*c]const c.struct_winsize, &size),
|
||||||
|
) < 0)
|
||||||
|
return error.OpenptyFailed;
|
||||||
|
|
||||||
|
return Pty{
|
||||||
|
.master = master_fd,
|
||||||
|
.slave = slave_fd,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Pty) void {
|
||||||
|
std.os.close(self.master);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the size of the pty.
|
||||||
|
pub fn getSize(self: Pty) !winsize {
|
||||||
|
var ws: winsize = undefined;
|
||||||
|
if (linux.ioctl(self.master, linux.T.IOCGWINSZ, @ptrToInt(&ws)) < 0)
|
||||||
|
return error.IoctlFailed;
|
||||||
|
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the size of the pty.
|
||||||
|
pub fn setSize(self: Pty, size: winsize) !void {
|
||||||
|
if (linux.ioctl(self.master, linux.T.IOCSWINSZ, @ptrToInt(&size)) < 0)
|
||||||
|
return error.IoctlFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
var ws: winsize = .{
|
||||||
|
.ws_row = 50,
|
||||||
|
.ws_col = 80,
|
||||||
|
.ws_xpixel = 1,
|
||||||
|
.ws_ypixel = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
var pty = try open(ws);
|
||||||
|
defer pty.deinit();
|
||||||
|
|
||||||
|
// Initialize size should match what we gave it
|
||||||
|
try testing.expectEqual(ws, try pty.getSize());
|
||||||
|
|
||||||
|
// Can set and read new sizes
|
||||||
|
ws.ws_row *= 2;
|
||||||
|
try pty.setSize(ws);
|
||||||
|
try testing.expectEqual(ws, try pty.getSize());
|
||||||
|
}
|
@ -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 Pty = @import("Pty.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.window);
|
const log = std.log.scoped(.window);
|
||||||
|
|
||||||
@ -20,6 +21,9 @@ window: glfw.Window,
|
|||||||
/// The terminal grid attached to this window.
|
/// The terminal grid attached to this window.
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
|
|
||||||
|
/// The underlying pty for this window.
|
||||||
|
pty: Pty,
|
||||||
|
|
||||||
/// 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.
|
||||||
@ -61,13 +65,24 @@ pub fn create(alloc: Allocator) !*Window {
|
|||||||
gl.c.glEnable(gl.c.GL_BLEND);
|
gl.c.glEnable(gl.c.GL_BLEND);
|
||||||
gl.c.glBlendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA);
|
gl.c.glBlendFunc(gl.c.GL_SRC_ALPHA, gl.c.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
// Create our terminal grid with a bogus initial size.
|
// Create our terminal grid with the initial window size
|
||||||
|
const window_size = try window.getSize();
|
||||||
var grid = try Grid.init(alloc);
|
var grid = try Grid.init(alloc);
|
||||||
try grid.setScreenSize(.{ .width = 640, .height = 480 });
|
try grid.setScreenSize(.{ .width = window_size.width, .height = window_size.height });
|
||||||
|
|
||||||
|
// Create our pty
|
||||||
|
var pty = try Pty.open(.{
|
||||||
|
.ws_row = @intCast(u16, grid.size.rows),
|
||||||
|
.ws_col = @intCast(u16, grid.size.columns),
|
||||||
|
.ws_xpixel = @intCast(u16, window_size.width),
|
||||||
|
.ws_ypixel = @intCast(u16, window_size.height),
|
||||||
|
});
|
||||||
|
errdefer pty.deinit();
|
||||||
|
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.window = window,
|
.window = window,
|
||||||
.grid = grid,
|
.grid = grid,
|
||||||
|
.pty = pty,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Setup our callbacks and user data
|
// Setup our callbacks and user data
|
||||||
@ -78,6 +93,7 @@ pub fn create(alloc: Allocator) !*Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *Window, alloc: Allocator) void {
|
pub fn destroy(self: *Window, alloc: Allocator) void {
|
||||||
|
self.pty.deinit();
|
||||||
self.grid.deinit();
|
self.grid.deinit();
|
||||||
self.window.destroy();
|
self.window.destroy();
|
||||||
alloc.destroy(self);
|
alloc.destroy(self);
|
||||||
@ -114,6 +130,14 @@ fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
|||||||
// TODO: temp
|
// TODO: temp
|
||||||
win.grid.demoCells() catch unreachable;
|
win.grid.demoCells() catch unreachable;
|
||||||
|
|
||||||
|
// Update the size of our pty
|
||||||
|
win.pty.setSize(.{
|
||||||
|
.ws_row = @intCast(u16, win.grid.size.rows),
|
||||||
|
.ws_col = @intCast(u16, win.grid.size.columns),
|
||||||
|
.ws_xpixel = @intCast(u16, width),
|
||||||
|
.ws_ypixel = @intCast(u16, height),
|
||||||
|
}) catch |err| log.err("error updating pty screen size err={}", .{err});
|
||||||
|
|
||||||
// Update our viewport for this context to be the entire window
|
// Update our viewport for this context to be the entire window
|
||||||
gl.viewport(0, 0, width, height) catch |err|
|
gl.viewport(0, 0, width, height) catch |err|
|
||||||
log.err("error updating OpenGL viewport err={}", .{err});
|
log.err("error updating OpenGL viewport err={}", .{err});
|
||||||
|
@ -22,4 +22,5 @@ test {
|
|||||||
_ = @import("Atlas.zig");
|
_ = @import("Atlas.zig");
|
||||||
_ = @import("FontAtlas.zig");
|
_ = @import("FontAtlas.zig");
|
||||||
_ = @import("Grid.zig");
|
_ = @import("Grid.zig");
|
||||||
|
_ = @import("Pty.zig");
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user