mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
support screen size, rip out shared state
This commit is contained in:
@ -367,8 +367,11 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
|
|
||||||
// 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();
|
||||||
|
const screen_size: renderer.ScreenSize = .{
|
||||||
|
.width = window_size.width,
|
||||||
|
.height = window_size.height,
|
||||||
|
};
|
||||||
var renderer_impl = try renderer.OpenGL.init(alloc, font_group);
|
var renderer_impl = try renderer.OpenGL.init(alloc, font_group);
|
||||||
try renderer_impl.setScreenSize(.{ .width = window_size.width, .height = window_size.height });
|
|
||||||
renderer_impl.background = .{
|
renderer_impl.background = .{
|
||||||
.r = config.background.r,
|
.r = config.background.r,
|
||||||
.g = config.background.g,
|
.g = config.background.g,
|
||||||
@ -381,10 +384,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Calculate our grid size based on known dimensions.
|
// Calculate our grid size based on known dimensions.
|
||||||
const grid_size = renderer.GridSize.init(
|
const grid_size = renderer.GridSize.init(screen_size, renderer_impl.cell_size);
|
||||||
.{ .width = window_size.width, .height = window_size.height },
|
|
||||||
renderer_impl.cell_size,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
|
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
|
||||||
// but is otherwise somewhat arbitrary.
|
// but is otherwise somewhat arbitrary.
|
||||||
@ -486,6 +486,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
.renderer_thread = render_thread,
|
.renderer_thread = render_thread,
|
||||||
.renderer_state = .{
|
.renderer_state = .{
|
||||||
.mutex = mutex,
|
.mutex = mutex,
|
||||||
|
.resize_screen = screen_size,
|
||||||
.cursor = .{
|
.cursor = .{
|
||||||
.style = .blinking_block,
|
.style = .blinking_block,
|
||||||
.visible = true,
|
.visible = true,
|
||||||
@ -516,7 +517,7 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
|||||||
|
|
||||||
// Setup our callbacks and user data
|
// Setup our callbacks and user data
|
||||||
window.setUserPointer(self);
|
window.setUserPointer(self);
|
||||||
//window.setSizeCallback(sizeCallback);
|
window.setSizeCallback(sizeCallback);
|
||||||
window.setCharCallback(charCallback);
|
window.setCharCallback(charCallback);
|
||||||
window.setKeyCallback(keyCallback);
|
window.setKeyCallback(keyCallback);
|
||||||
window.setFocusCallback(focusCallback);
|
window.setFocusCallback(focusCallback);
|
||||||
@ -718,18 +719,15 @@ fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
|||||||
.height = px_size.height,
|
.height = px_size.height,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update our grid so that the projections on render are correct.
|
|
||||||
const win = window.getUserPointer(Window) orelse return;
|
const win = window.getUserPointer(Window) orelse return;
|
||||||
win.renderer.setScreenSize(screen_size) catch |err|
|
|
||||||
log.err("error updating grid screen size err={}", .{err});
|
// Resize usually forces a redraw
|
||||||
|
win.render_timer.schedule() catch |err|
|
||||||
|
log.err("error scheduling render timer in sizeCallback err={}", .{err});
|
||||||
|
|
||||||
// Recalculate our grid size
|
// Recalculate our grid size
|
||||||
win.grid_size.update(screen_size, win.renderer.cell_size);
|
win.grid_size.update(screen_size, win.renderer.cell_size);
|
||||||
|
|
||||||
// Update the size of our terminal state
|
|
||||||
win.terminal.resize(win.alloc, win.grid_size.columns, win.grid_size.rows) catch |err|
|
|
||||||
log.err("error updating terminal size: {}", .{err});
|
|
||||||
|
|
||||||
// Update the size of our pty
|
// Update the size of our pty
|
||||||
win.pty.setSize(.{
|
win.pty.setSize(.{
|
||||||
.ws_row = @intCast(u16, win.grid_size.rows),
|
.ws_row = @intCast(u16, win.grid_size.rows),
|
||||||
@ -738,14 +736,18 @@ fn sizeCallback(window: glfw.Window, width: i32, height: i32) void {
|
|||||||
.ws_ypixel = @intCast(u16, height),
|
.ws_ypixel = @intCast(u16, height),
|
||||||
}) catch |err| log.err("error updating pty screen size err={}", .{err});
|
}) catch |err| log.err("error updating pty screen size err={}", .{err});
|
||||||
|
|
||||||
// Update our viewport for this context to be the entire window.
|
// Enter the critical area that we want to keep small
|
||||||
// OpenGL works in pixels, so we have to use the pixel size.
|
{
|
||||||
gl.viewport(0, 0, @intCast(i32, px_size.width), @intCast(i32, px_size.height)) catch |err|
|
win.renderer_state.mutex.lock();
|
||||||
log.err("error updating OpenGL viewport err={}", .{err});
|
defer win.renderer_state.mutex.unlock();
|
||||||
|
|
||||||
// Draw
|
// We need to setup our render state to store our new pending size
|
||||||
win.render_timer.schedule() catch |err|
|
win.renderer_state.resize_screen = screen_size;
|
||||||
log.err("error scheduling render timer in sizeCallback err={}", .{err});
|
|
||||||
|
// Update the size of our terminal state
|
||||||
|
win.terminal.resize(win.alloc, win.grid_size.columns, win.grid_size.rows) catch |err|
|
||||||
|
log.err("error updating terminal size: {}", .{err});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn charCallback(window: glfw.Window, codepoint: u21) void {
|
fn charCallback(window: glfw.Window, codepoint: u21) void {
|
||||||
|
@ -359,14 +359,24 @@ pub fn threadExit(self: *const OpenGL) void {
|
|||||||
pub fn render(
|
pub fn render(
|
||||||
self: *OpenGL,
|
self: *OpenGL,
|
||||||
window: glfw.Window,
|
window: glfw.Window,
|
||||||
state: renderer.State,
|
state: *renderer.State,
|
||||||
) !void {
|
) !void {
|
||||||
|
// Data we extract out of the critical area.
|
||||||
|
const Critical = struct {
|
||||||
|
devmode_data: ?*imgui.DrawData,
|
||||||
|
screen_size: ?renderer.ScreenSize,
|
||||||
|
};
|
||||||
|
|
||||||
// Update all our data as tightly as possible within the mutex.
|
// Update all our data as tightly as possible within the mutex.
|
||||||
var gl_bg = self.background;
|
var gl_bg = self.background;
|
||||||
{
|
const critical: Critical = critical: {
|
||||||
state.mutex.lock();
|
state.mutex.lock();
|
||||||
defer state.mutex.unlock();
|
defer state.mutex.unlock();
|
||||||
|
|
||||||
|
// If we're resizing, then handle that now.
|
||||||
|
if (state.resize_screen) |size| try self.setScreenSize(size);
|
||||||
|
defer state.resize_screen = null;
|
||||||
|
|
||||||
// Setup our cursor state
|
// Setup our cursor state
|
||||||
self.cursor_visible = state.cursor.visible and !state.cursor.blink;
|
self.cursor_visible = state.cursor.visible and !state.cursor.blink;
|
||||||
self.cursor_style = CursorStyle.fromTerminal(state.cursor.style) orelse .box;
|
self.cursor_style = CursorStyle.fromTerminal(state.cursor.style) orelse .box;
|
||||||
@ -384,9 +394,33 @@ pub fn render(
|
|||||||
self.foreground = bg;
|
self.foreground = bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build our GPU cells
|
||||||
try self.rebuildCells(state.terminal);
|
try self.rebuildCells(state.terminal);
|
||||||
try self.finalizeCells(state.terminal);
|
try self.finalizeCells(state.terminal);
|
||||||
if (state.devmode) |dm| if (dm.visible) try dm.update();
|
|
||||||
|
// Build our devmode draw data
|
||||||
|
const devmode_data = devmode_data: {
|
||||||
|
if (state.devmode) |dm| {
|
||||||
|
if (dm.visible) {
|
||||||
|
try dm.update();
|
||||||
|
break :devmode_data try dm.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break :devmode_data null;
|
||||||
|
};
|
||||||
|
|
||||||
|
break :critical .{
|
||||||
|
.devmode_data = devmode_data,
|
||||||
|
.screen_size = state.resize_screen,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// If we are resizing we need to update the viewport
|
||||||
|
if (critical.screen_size) |size| {
|
||||||
|
// Update our viewport for this context to be the entire window.
|
||||||
|
// OpenGL works in pixels, so we have to use the pixel size.
|
||||||
|
try gl.viewport(0, 0, @intCast(i32, size.width), @intCast(i32, size.height));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the surface
|
// Clear the surface
|
||||||
@ -402,11 +436,8 @@ pub fn render(
|
|||||||
try self.draw();
|
try self.draw();
|
||||||
|
|
||||||
// If we have devmode, then render that
|
// If we have devmode, then render that
|
||||||
if (state.devmode) |dm| {
|
if (critical.devmode_data) |data| {
|
||||||
if (dm.visible) {
|
imgui.ImplOpenGL3.renderDrawData(data);
|
||||||
const data = try dm.render();
|
|
||||||
imgui.ImplOpenGL3.renderDrawData(data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap our window buffers
|
// Swap our window buffers
|
||||||
@ -783,7 +814,7 @@ pub fn updateCell(
|
|||||||
|
|
||||||
/// Set the screen size for rendering. This will update the projection
|
/// Set the screen size for rendering. This will update the projection
|
||||||
/// used for the shader so that the scaling of the grid is correct.
|
/// used for the shader so that the scaling of the grid is correct.
|
||||||
pub fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
|
fn setScreenSize(self: *OpenGL, dim: renderer.ScreenSize) !void {
|
||||||
// Update the projection uniform within our shader
|
// Update the projection uniform within our shader
|
||||||
const bind = try self.program.use();
|
const bind = try self.program.use();
|
||||||
defer bind.unbind();
|
defer bind.unbind();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const DevMode = @import("../DevMode.zig");
|
const DevMode = @import("../DevMode.zig");
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
|
const renderer = @import("../renderer.zig");
|
||||||
|
|
||||||
/// The mutex that must be held while reading any of the data in the
|
/// The mutex that must be held while reading any of the data in the
|
||||||
/// members of this state. Note that the state itself is NOT protected
|
/// members of this state. Note that the state itself is NOT protected
|
||||||
@ -11,7 +12,7 @@ const terminal = @import("../terminal/main.zig");
|
|||||||
mutex: *std.Thread.Mutex,
|
mutex: *std.Thread.Mutex,
|
||||||
|
|
||||||
/// A new screen size if the screen was resized.
|
/// A new screen size if the screen was resized.
|
||||||
resize: ?Resize = null,
|
resize_screen: ?renderer.ScreenSize,
|
||||||
|
|
||||||
/// Cursor configuration for rendering
|
/// Cursor configuration for rendering
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
@ -36,5 +37,3 @@ pub const Cursor = struct {
|
|||||||
/// the cursor will not be rendered.
|
/// the cursor will not be rendered.
|
||||||
blink: bool = false,
|
blink: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Resize = struct {};
|
|
||||||
|
@ -31,7 +31,7 @@ window: glfw.Window,
|
|||||||
renderer: *renderer.OpenGL,
|
renderer: *renderer.OpenGL,
|
||||||
|
|
||||||
/// Pointer to the shared state that is used to generate the final render.
|
/// Pointer to the shared state that is used to generate the final render.
|
||||||
state: *const renderer.State,
|
state: *renderer.State,
|
||||||
|
|
||||||
/// Initialize the thread. This does not START the thread. This only sets
|
/// Initialize the thread. This does not START the thread. This only sets
|
||||||
/// up all the internal state necessary prior to starting the thread. It
|
/// up all the internal state necessary prior to starting the thread. It
|
||||||
@ -40,7 +40,7 @@ pub fn init(
|
|||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
window: glfw.Window,
|
window: glfw.Window,
|
||||||
renderer_impl: *renderer.OpenGL,
|
renderer_impl: *renderer.OpenGL,
|
||||||
state: *const renderer.State,
|
state: *renderer.State,
|
||||||
) !Thread {
|
) !Thread {
|
||||||
// We always store allocator pointer on the loop data so that
|
// We always store allocator pointer on the loop data so that
|
||||||
// handles can use our global allocator.
|
// handles can use our global allocator.
|
||||||
@ -148,7 +148,7 @@ fn renderCallback(h: *libuv.Async) void {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
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});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user