mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 01:06:08 +03:00
window: start abstracting a window implementation
This commit is contained in:
@ -30,6 +30,7 @@ const input = @import("input.zig");
|
|||||||
const DevMode = @import("DevMode.zig");
|
const DevMode = @import("DevMode.zig");
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const internal_os = @import("os/main.zig");
|
const internal_os = @import("os/main.zig");
|
||||||
|
const WindowingSystem = @import("window.zig").System;
|
||||||
|
|
||||||
// Get native API access on certain platforms so we can do more customization.
|
// Get native API access on certain platforms so we can do more customization.
|
||||||
const glfwNative = glfw.Native(.{
|
const glfwNative = glfw.Native(.{
|
||||||
@ -47,6 +48,9 @@ alloc: Allocator,
|
|||||||
/// The app that this window is a part of.
|
/// The app that this window is a part of.
|
||||||
app: *App,
|
app: *App,
|
||||||
|
|
||||||
|
/// The windowing system state
|
||||||
|
windowing_system: WindowingSystem,
|
||||||
|
|
||||||
/// The font structures
|
/// The font structures
|
||||||
font_lib: font.Library,
|
font_lib: font.Library,
|
||||||
font_group: *font.GroupCache,
|
font_group: *font.GroupCache,
|
||||||
@ -135,6 +139,10 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
var self = try alloc.create(Window);
|
var self = try alloc.create(Window);
|
||||||
errdefer alloc.destroy(self);
|
errdefer alloc.destroy(self);
|
||||||
|
|
||||||
|
// Create the windowing system
|
||||||
|
var winsys = try WindowingSystem.init(app);
|
||||||
|
winsys.deinit();
|
||||||
|
|
||||||
// Create our window
|
// Create our window
|
||||||
const window = try glfw.Window.create(640, 480, "ghostty", null, null, Renderer.windowHints());
|
const window = try glfw.Window.create(640, 480, "ghostty", null, null, Renderer.windowHints());
|
||||||
errdefer window.destroy();
|
errdefer window.destroy();
|
||||||
@ -153,6 +161,16 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
nswindow.setProperty("tabbingIdentifier", app.darwin.tabbing_id);
|
nswindow.setProperty("tabbingIdentifier", app.darwin.tabbing_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create the cursor
|
||||||
|
const cursor = try glfw.Cursor.createStandard(.ibeam);
|
||||||
|
errdefer cursor.destroy();
|
||||||
|
if ((comptime !builtin.target.isDarwin()) or internal_os.macosVersionAtLeast(13, 0, 0)) {
|
||||||
|
// We only set our cursor if we're NOT on Mac, or if we are then the
|
||||||
|
// macOS version is >= 13 (Ventura). On prior versions, glfw crashes
|
||||||
|
// since we use a tab group.
|
||||||
|
try window.setCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
// Determine our DPI configurations so we can properly configure
|
// Determine our DPI configurations so we can properly configure
|
||||||
// font points to pixels and handle other high-DPI scaling factors.
|
// font points to pixels and handle other high-DPI scaling factors.
|
||||||
const content_scale = try window.getContentScale();
|
const content_scale = try window.getContentScale();
|
||||||
@ -322,23 +340,6 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
cell_size,
|
cell_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
|
|
||||||
// but is otherwise somewhat arbitrary.
|
|
||||||
try window.setSizeLimits(.{
|
|
||||||
.width = @floatToInt(u32, cell_size.width * 10),
|
|
||||||
.height = @floatToInt(u32, cell_size.height * 4),
|
|
||||||
}, .{ .width = null, .height = null });
|
|
||||||
|
|
||||||
// Create the cursor
|
|
||||||
const cursor = try glfw.Cursor.createStandard(.ibeam);
|
|
||||||
errdefer cursor.destroy();
|
|
||||||
if ((comptime !builtin.target.isDarwin()) or internal_os.macosVersionAtLeast(13, 0, 0)) {
|
|
||||||
// We only set our cursor if we're NOT on Mac, or if we are then the
|
|
||||||
// macOS version is >= 13 (Ventura). On prior versions, glfw crashes
|
|
||||||
// since we use a tab group.
|
|
||||||
try window.setCursor(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The mutex used to protect our renderer state.
|
// The mutex used to protect our renderer state.
|
||||||
var mutex = try alloc.create(std.Thread.Mutex);
|
var mutex = try alloc.create(std.Thread.Mutex);
|
||||||
mutex.* = .{};
|
mutex.* = .{};
|
||||||
@ -377,6 +378,7 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
self.* = .{
|
self.* = .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.app = app,
|
.app = app,
|
||||||
|
.windowing_system = winsys,
|
||||||
.font_lib = font_lib,
|
.font_lib = font_lib,
|
||||||
.font_group = font_group,
|
.font_group = font_group,
|
||||||
.font_size = font_size,
|
.font_size = font_size,
|
||||||
@ -409,6 +411,13 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
|||||||
};
|
};
|
||||||
errdefer if (DevMode.enabled) self.imgui_ctx.destroy();
|
errdefer if (DevMode.enabled) self.imgui_ctx.destroy();
|
||||||
|
|
||||||
|
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
|
||||||
|
// but is otherwise somewhat arbitrary.
|
||||||
|
try window.setSizeLimits(.{
|
||||||
|
.width = @floatToInt(u32, cell_size.width * 10),
|
||||||
|
.height = @floatToInt(u32, cell_size.height * 4),
|
||||||
|
}, .{ .width = null, .height = null });
|
||||||
|
|
||||||
// Setup our callbacks and user data
|
// Setup our callbacks and user data
|
||||||
window.setUserPointer(self);
|
window.setUserPointer(self);
|
||||||
window.setSizeCallback(sizeCallback);
|
window.setSizeCallback(sizeCallback);
|
||||||
|
18
src/window.zig
Normal file
18
src/window.zig
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//! Window implementation and utilities. The window subsystem is responsible
|
||||||
|
//! for maintaining a "window" or "surface" abstraction around a terminal,
|
||||||
|
//! effectively being the primary interface to the terminal.
|
||||||
|
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
pub usingnamespace @import("window/structs.zig");
|
||||||
|
pub const Glfw = @import("window/Glfw.zig");
|
||||||
|
|
||||||
|
/// The implementation to use for the windowing system. This is comptime chosen
|
||||||
|
/// so that every build has exactly one windowing implementation.
|
||||||
|
pub const System = switch (builtin.os.tag) {
|
||||||
|
else => Glfw,
|
||||||
|
};
|
||||||
|
|
||||||
|
test {
|
||||||
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
}
|
77
src/window/Glfw.zig
Normal file
77
src/window/Glfw.zig
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
//! Window implementation that uses GLFW (https://www.glfw.org/).
|
||||||
|
pub const Glfw = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const glfw = @import("glfw");
|
||||||
|
const objc = @import("objc");
|
||||||
|
const App = @import("../App.zig");
|
||||||
|
const internal_os = @import("../os/main.zig");
|
||||||
|
const renderer = @import("../renderer.zig");
|
||||||
|
const Renderer = renderer.Renderer;
|
||||||
|
const window = @import("../window.zig");
|
||||||
|
|
||||||
|
// Get native API access on certain platforms so we can do more customization.
|
||||||
|
const glfwNative = glfw.Native(.{
|
||||||
|
.cocoa = builtin.target.isDarwin(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The glfw window handle
|
||||||
|
window: glfw.Window,
|
||||||
|
|
||||||
|
/// The glfw mouse cursor handle.
|
||||||
|
cursor: glfw.Cursor,
|
||||||
|
|
||||||
|
pub fn init(app: *const App) !Glfw {
|
||||||
|
// Create our window
|
||||||
|
const win = try glfw.Window.create(640, 480, "ghostty", null, null, Renderer.windowHints());
|
||||||
|
errdefer win.destroy();
|
||||||
|
try Renderer.windowInit(win);
|
||||||
|
|
||||||
|
// On Mac, enable tabbing
|
||||||
|
if (comptime builtin.target.isDarwin()) {
|
||||||
|
const NSWindowTabbingMode = enum(usize) { automatic = 0, preferred = 1, disallowed = 2 };
|
||||||
|
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(win).?);
|
||||||
|
|
||||||
|
// Tabbing mode enables tabbing at all
|
||||||
|
nswindow.setProperty("tabbingMode", NSWindowTabbingMode.automatic);
|
||||||
|
|
||||||
|
// All windows within a tab bar must have a matching tabbing ID.
|
||||||
|
// The app sets this up for us.
|
||||||
|
nswindow.setProperty("tabbingIdentifier", app.darwin.tabbing_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the cursor
|
||||||
|
const cursor = try glfw.Cursor.createStandard(.ibeam);
|
||||||
|
errdefer cursor.destroy();
|
||||||
|
if ((comptime !builtin.target.isDarwin()) or internal_os.macosVersionAtLeast(13, 0, 0)) {
|
||||||
|
// We only set our cursor if we're NOT on Mac, or if we are then the
|
||||||
|
// macOS version is >= 13 (Ventura). On prior versions, glfw crashes
|
||||||
|
// since we use a tab group.
|
||||||
|
try win.setCursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Glfw{
|
||||||
|
.window = win,
|
||||||
|
.cursor = cursor,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Glfw) void {
|
||||||
|
self.window.destroy();
|
||||||
|
self.cursor.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the content scale for the created window.
|
||||||
|
pub fn getContentScale(self: *const Glfw) !window.ContentScale {
|
||||||
|
const scale = try self.window.getContentScale();
|
||||||
|
return window.ContentScale{ .x = scale.x_scale, .y = scale.y_scale };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the size of the window in screen coordinates.
|
||||||
|
pub fn getSize(self: *const Glfw) !window.Size {
|
||||||
|
const size = try self.window.getSize();
|
||||||
|
return window.Size{ .width = size.width, .height = size.height };
|
||||||
|
}
|
2
src/window/Web.zig
Normal file
2
src/window/Web.zig
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
//! Window implementation for the web (browser) via WebAssembly.
|
||||||
|
pub const Window = @This();
|
10
src/window/Window.zig
Normal file
10
src/window/Window.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//! Window represents a single terminal window. A terminal window is
|
||||||
|
//! a single drawable terminal surface.
|
||||||
|
//!
|
||||||
|
//! This Window is the abstract window logic that applies to all platforms.
|
||||||
|
//! Platforms are expected to implement a compile-time "interface" to
|
||||||
|
//! implement platform-specific logic.
|
||||||
|
//!
|
||||||
|
//! Note(mitchellh): We current conflate a "window" and a "surface". If
|
||||||
|
//! we implement splits, we probably will need to separate these concepts.
|
||||||
|
pub const Window = @This();
|
13
src/window/structs.zig
Normal file
13
src/window/structs.zig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/// ContentScale is the ratio between the current DPI and the platform's
|
||||||
|
/// default DPI. This is used to determine how much certain rendered elements
|
||||||
|
/// need to be scaled up or down.
|
||||||
|
pub const ContentScale = struct {
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The size of the window in screen coordinates.
|
||||||
|
pub const Size = struct {
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
};
|
Reference in New Issue
Block a user