mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46: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 App = @import("App.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.
|
||||
const glfwNative = glfw.Native(.{
|
||||
@ -47,6 +48,9 @@ alloc: Allocator,
|
||||
/// The app that this window is a part of.
|
||||
app: *App,
|
||||
|
||||
/// The windowing system state
|
||||
windowing_system: WindowingSystem,
|
||||
|
||||
/// The font structures
|
||||
font_lib: font.Library,
|
||||
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);
|
||||
errdefer alloc.destroy(self);
|
||||
|
||||
// Create the windowing system
|
||||
var winsys = try WindowingSystem.init(app);
|
||||
winsys.deinit();
|
||||
|
||||
// Create our window
|
||||
const window = try glfw.Window.create(640, 480, "ghostty", null, null, Renderer.windowHints());
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
// font points to pixels and handle other high-DPI scaling factors.
|
||||
const content_scale = try window.getContentScale();
|
||||
@ -322,23 +340,6 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
||||
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.
|
||||
var mutex = try alloc.create(std.Thread.Mutex);
|
||||
mutex.* = .{};
|
||||
@ -377,6 +378,7 @@ pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
|
||||
self.* = .{
|
||||
.alloc = alloc,
|
||||
.app = app,
|
||||
.windowing_system = winsys,
|
||||
.font_lib = font_lib,
|
||||
.font_group = font_group,
|
||||
.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();
|
||||
|
||||
// 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
|
||||
window.setUserPointer(self);
|
||||
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