mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
more crap
This commit is contained in:
24
src/App.zig
24
src/App.zig
@ -164,9 +164,9 @@ fn drainMailbox(self: *App, rt_app: *apprt.runtime.App) !void {
|
||||
switch (message) {
|
||||
.new_window => |msg| {
|
||||
_ = msg; // TODO
|
||||
try rt_app.newWindow();
|
||||
_ = try rt_app.newWindow();
|
||||
},
|
||||
.new_tab => |msg| try self.newTab(msg),
|
||||
.new_tab => |msg| try self.newTab(rt_app, msg),
|
||||
.quit => try self.setQuit(),
|
||||
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
|
||||
}
|
||||
@ -174,19 +174,7 @@ fn drainMailbox(self: *App, rt_app: *apprt.runtime.App) !void {
|
||||
}
|
||||
|
||||
/// Create a new tab in the parent window
|
||||
fn newTab(self: *App, msg: Message.NewWindow) !void {
|
||||
if (comptime !builtin.target.isDarwin()) {
|
||||
log.warn("tabbing is not supported on this platform", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
// In embedded mode, it is up to the embedder to implement tabbing
|
||||
// on their own.
|
||||
if (comptime build_config.artifact != .exe) {
|
||||
log.warn("tabbing is not supported in embedded mode", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
fn newTab(self: *App, rt_app: *apprt.runtime.App, msg: Message.NewWindow) !void {
|
||||
const parent = msg.parent orelse {
|
||||
log.warn("parent must be set in new_tab message", .{});
|
||||
return;
|
||||
@ -198,11 +186,7 @@ fn newTab(self: *App, msg: Message.NewWindow) !void {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the new window
|
||||
const window = try self.newWindow(msg);
|
||||
|
||||
// Add the window to our parent tab group
|
||||
parent.addWindow(window);
|
||||
try rt_app.newTab(parent);
|
||||
}
|
||||
|
||||
/// Start quitting
|
||||
|
1679
src/Window.zig
1679
src/Window.zig
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@ const objc = @import("objc");
|
||||
const apprt = @import("../apprt.zig");
|
||||
const input = @import("../input.zig");
|
||||
const CoreApp = @import("../App.zig");
|
||||
const CoreWindow = @import("../Window.zig");
|
||||
const CoreSurface = @import("../Surface.zig");
|
||||
|
||||
const log = std.log.scoped(.embedded_window);
|
||||
|
||||
@ -65,11 +65,11 @@ pub const App = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Window = struct {
|
||||
pub const Surface = struct {
|
||||
nsview: objc.Object,
|
||||
core_win: *CoreWindow,
|
||||
core_win: *CoreSurface,
|
||||
content_scale: apprt.ContentScale,
|
||||
size: apprt.WindowSize,
|
||||
size: apprt.SurfaceSize,
|
||||
cursor_pos: apprt.CursorPos,
|
||||
opts: Options,
|
||||
|
||||
@ -84,7 +84,7 @@ pub const Window = struct {
|
||||
scale_factor: f64 = 1,
|
||||
};
|
||||
|
||||
pub fn init(app: *const CoreApp, core_win: *CoreWindow, opts: Options) !Window {
|
||||
pub fn init(app: *const CoreApp, core_win: *CoreSurface, opts: Options) !Surface {
|
||||
_ = app;
|
||||
|
||||
return .{
|
||||
@ -100,68 +100,68 @@ pub const Window = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Window) void {
|
||||
pub fn deinit(self: *Surface) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub fn getContentScale(self: *const Window) !apprt.ContentScale {
|
||||
pub fn getContentScale(self: *const Surface) !apprt.ContentScale {
|
||||
return self.content_scale;
|
||||
}
|
||||
|
||||
pub fn getSize(self: *const Window) !apprt.WindowSize {
|
||||
pub fn getSize(self: *const Surface) !apprt.SurfaceSize {
|
||||
return self.size;
|
||||
}
|
||||
|
||||
pub fn setSizeLimits(self: *Window, min: apprt.WindowSize, max_: ?apprt.WindowSize) !void {
|
||||
pub fn setSizeLimits(self: *Surface, min: apprt.SurfaceSize, max_: ?apprt.SurfaceSize) !void {
|
||||
_ = self;
|
||||
_ = min;
|
||||
_ = max_;
|
||||
}
|
||||
|
||||
pub fn setTitle(self: *Window, slice: [:0]const u8) !void {
|
||||
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
||||
self.core_win.app.runtime.opts.set_title(
|
||||
self.opts.userdata,
|
||||
slice.ptr,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn getClipboardString(self: *const Window) ![:0]const u8 {
|
||||
pub fn getClipboardString(self: *const Surface) ![:0]const u8 {
|
||||
const ptr = self.core_win.app.runtime.opts.read_clipboard(self.opts.userdata);
|
||||
return std.mem.sliceTo(ptr, 0);
|
||||
}
|
||||
|
||||
pub fn setClipboardString(self: *const Window, val: [:0]const u8) !void {
|
||||
pub fn setClipboardString(self: *const Surface, val: [:0]const u8) !void {
|
||||
self.core_win.app.runtime.opts.write_clipboard(self.opts.userdata, val.ptr);
|
||||
}
|
||||
|
||||
pub fn setShouldClose(self: *Window) void {
|
||||
pub fn setShouldClose(self: *Surface) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub fn shouldClose(self: *const Window) bool {
|
||||
pub fn shouldClose(self: *const Surface) bool {
|
||||
_ = self;
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn getCursorPos(self: *const Window) !apprt.CursorPos {
|
||||
pub fn getCursorPos(self: *const Surface) !apprt.CursorPos {
|
||||
return self.cursor_pos;
|
||||
}
|
||||
|
||||
pub fn refresh(self: *Window) void {
|
||||
pub fn refresh(self: *Surface) void {
|
||||
self.core_win.refreshCallback() catch |err| {
|
||||
log.err("error in refresh callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn updateContentScale(self: *Window, x: f64, y: f64) void {
|
||||
pub fn updateContentScale(self: *Surface, x: f64, y: f64) void {
|
||||
self.content_scale = .{
|
||||
.x = @floatCast(f32, x),
|
||||
.y = @floatCast(f32, y),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn updateSize(self: *Window, width: u32, height: u32) void {
|
||||
pub fn updateSize(self: *Surface, width: u32, height: u32) void {
|
||||
self.size = .{
|
||||
.width = width,
|
||||
.height = height,
|
||||
@ -175,7 +175,7 @@ pub const Window = struct {
|
||||
}
|
||||
|
||||
pub fn mouseButtonCallback(
|
||||
self: *const Window,
|
||||
self: *const Surface,
|
||||
action: input.MouseButtonState,
|
||||
button: input.MouseButton,
|
||||
mods: input.Mods,
|
||||
@ -186,14 +186,14 @@ pub const Window = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn scrollCallback(self: *const Window, xoff: f64, yoff: f64) void {
|
||||
pub fn scrollCallback(self: *const Surface, xoff: f64, yoff: f64) void {
|
||||
self.core_win.scrollCallback(xoff, yoff) catch |err| {
|
||||
log.err("error in scroll callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn cursorPosCallback(self: *Window, x: f64, y: f64) void {
|
||||
pub fn cursorPosCallback(self: *Surface, x: f64, y: f64) void {
|
||||
// Convert our unscaled x/y to scaled.
|
||||
self.cursor_pos = self.core_win.window.cursorPosToPixels(.{
|
||||
.x = @floatCast(f32, x),
|
||||
@ -213,7 +213,7 @@ pub const Window = struct {
|
||||
}
|
||||
|
||||
pub fn keyCallback(
|
||||
self: *const Window,
|
||||
self: *const Surface,
|
||||
action: input.Action,
|
||||
key: input.Key,
|
||||
mods: input.Mods,
|
||||
@ -225,7 +225,7 @@ pub const Window = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn charCallback(self: *const Window, cp_: u32) void {
|
||||
pub fn charCallback(self: *const Surface, cp_: u32) void {
|
||||
const cp = std.math.cast(u21, cp_) orelse return;
|
||||
self.core_win.charCallback(cp) catch |err| {
|
||||
log.err("error in char callback err={}", .{err});
|
||||
@ -233,7 +233,7 @@ pub const Window = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn focusCallback(self: *const Window, focused: bool) void {
|
||||
pub fn focusCallback(self: *const Surface, focused: bool) void {
|
||||
self.core_win.focusCallback(focused) catch |err| {
|
||||
log.err("error in focus callback err={}", .{err});
|
||||
return;
|
||||
@ -242,7 +242,7 @@ pub const Window = struct {
|
||||
|
||||
/// The cursor position from the host directly is in screen coordinates but
|
||||
/// all our interface works in pixels.
|
||||
fn cursorPosToPixels(self: *const Window, pos: apprt.CursorPos) !apprt.CursorPos {
|
||||
fn cursorPosToPixels(self: *const Surface, pos: apprt.CursorPos) !apprt.CursorPos {
|
||||
const scale = try self.getContentScale();
|
||||
return .{ .x = pos.x * scale.x, .y = pos.y * scale.y };
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ pub const App = struct {
|
||||
}
|
||||
|
||||
/// Create a new window for the app.
|
||||
pub fn newWindow(self: *App) !void {
|
||||
pub fn newWindow(self: *App) !*Surface {
|
||||
// Grab a surface allocation because we're going to need it.
|
||||
const surface = try self.app.surface_pool.create();
|
||||
errdefer self.app.surface_pool.destroy(surface);
|
||||
@ -84,6 +84,42 @@ pub const App = struct {
|
||||
// Create the surface -- because windows are surfaces for glfw.
|
||||
try surface.init(self);
|
||||
errdefer surface.deinit();
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
/// Create a new tab in the parent surface.
|
||||
pub fn newTab(self: *App, parent: *CoreSurface) !void {
|
||||
if (!Darwin.enabled) {
|
||||
log.warn("tabbing is not supported on this platform", .{});
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the new window
|
||||
const window = try self.newWindow();
|
||||
|
||||
// Add the new window the parent window
|
||||
const parent_win = glfwNative.getCocoaWindow(parent.rt_surface.window).?;
|
||||
const other_win = glfwNative.getCocoaWindow(window.window).?;
|
||||
const NSWindowOrderingMode = enum(isize) { below = -1, out = 0, above = 1 };
|
||||
const nswindow = objc.Object.fromId(parent_win);
|
||||
nswindow.msgSend(void, objc.sel("addTabbedWindow:ordered:"), .{
|
||||
objc.Object.fromId(other_win),
|
||||
NSWindowOrderingMode.above,
|
||||
});
|
||||
|
||||
// Adding a new tab can cause the tab bar to appear which changes
|
||||
// our viewport size. We need to call the size callback in order to
|
||||
// update values. For example, we need this to set the proper mouse selection
|
||||
// point in the grid.
|
||||
const size = parent.rt_surface.getSize() catch |err| {
|
||||
log.err("error querying window size for size callback on new tab err={}", .{err});
|
||||
return;
|
||||
};
|
||||
parent.sizeCallback(size) catch |err| {
|
||||
log.err("error in size callback from new tab err={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
/// Close the given surface.
|
||||
|
@ -6,7 +6,7 @@ const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const apprt = @import("../apprt.zig");
|
||||
const CoreApp = @import("../App.zig");
|
||||
const CoreWindow = @import("../Window.zig");
|
||||
const CoreSurface = @import("../Surface.zig");
|
||||
|
||||
pub const c = @cImport({
|
||||
@cInclude("gtk/gtk.h");
|
||||
@ -147,10 +147,10 @@ pub const App = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Window = struct {
|
||||
pub const Surface = struct {
|
||||
pub const Options = struct {};
|
||||
|
||||
pub fn init(app: *const CoreApp, core_win: *CoreWindow, opts: Options) !Window {
|
||||
pub fn init(app: *const CoreApp, core_win: *CoreSurface, opts: Options) !Surface {
|
||||
_ = app;
|
||||
_ = core_win;
|
||||
_ = opts;
|
||||
@ -158,46 +158,46 @@ pub const Window = struct {
|
||||
return .{};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Window) void {
|
||||
pub fn deinit(self: *Surface) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub fn setShouldClose(self: *Window) void {
|
||||
pub fn setShouldClose(self: *Surface) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
pub fn shouldClose(self: *const Window) bool {
|
||||
pub fn shouldClose(self: *const Surface) bool {
|
||||
_ = self;
|
||||
return false;
|
||||
}
|
||||
|
||||
pub fn getContentScale(self: *const Window) !apprt.ContentScale {
|
||||
pub fn getContentScale(self: *const Surface) !apprt.ContentScale {
|
||||
_ = self;
|
||||
return .{ .x = 1, .y = 1 };
|
||||
}
|
||||
|
||||
pub fn getSize(self: *const Window) !apprt.WindowSize {
|
||||
pub fn getSize(self: *const Surface) !apprt.SurfaceSize {
|
||||
_ = self;
|
||||
return .{ .width = 800, .height = 600 };
|
||||
}
|
||||
|
||||
pub fn setSizeLimits(self: *Window, min: apprt.WindowSize, max_: ?apprt.WindowSize) !void {
|
||||
pub fn setSizeLimits(self: *Surface, min: apprt.SurfaceSize, max_: ?apprt.SurfaceSize) !void {
|
||||
_ = self;
|
||||
_ = min;
|
||||
_ = max_;
|
||||
}
|
||||
|
||||
pub fn setTitle(self: *Window, slice: [:0]const u8) !void {
|
||||
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
||||
_ = self;
|
||||
_ = slice;
|
||||
}
|
||||
|
||||
pub fn getClipboardString(self: *const Window) ![:0]const u8 {
|
||||
pub fn getClipboardString(self: *const Surface) ![:0]const u8 {
|
||||
_ = self;
|
||||
return "";
|
||||
}
|
||||
|
||||
pub fn setClipboardString(self: *const Window, val: [:0]const u8) !void {
|
||||
pub fn setClipboardString(self: *const Surface, val: [:0]const u8) !void {
|
||||
_ = self;
|
||||
_ = val;
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ pub fn main() !void {
|
||||
defer app_runtime.terminate();
|
||||
|
||||
// Create an initial window
|
||||
try app_runtime.newWindow();
|
||||
_ = try app_runtime.newWindow();
|
||||
|
||||
// Run the GUI event loop
|
||||
try app_runtime.run();
|
||||
|
@ -16,7 +16,7 @@ const terminal = @import("../terminal/main.zig");
|
||||
const renderer = @import("../renderer.zig");
|
||||
const math = @import("../math.zig");
|
||||
const DevMode = @import("../DevMode.zig");
|
||||
const Window = @import("../Window.zig");
|
||||
const Surface = @import("../Surface.zig");
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Terminal = terminal.Terminal;
|
||||
@ -32,7 +32,7 @@ const log = std.log.scoped(.metal);
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
/// The mailbox for communicating with the window.
|
||||
window_mailbox: Window.Mailbox,
|
||||
surface_mailbox: apprt.surface.Mailbox,
|
||||
|
||||
/// Current cell dimensions for this grid.
|
||||
cell_size: renderer.CellSize,
|
||||
@ -135,8 +135,8 @@ pub fn glfwWindowHints() glfw.Window.Hints {
|
||||
|
||||
/// This is called early right after window creation to setup our
|
||||
/// window surface as necessary.
|
||||
pub fn windowInit(win: apprt.runtime.Window) !void {
|
||||
_ = win;
|
||||
pub fn surfaceInit(surface: *apprt.Surface) !void {
|
||||
_ = surface;
|
||||
|
||||
// We don't do anything else here because we want to set everything
|
||||
// else up during actual initialization.
|
||||
@ -240,7 +240,7 @@ pub fn init(alloc: Allocator, options: renderer.Options) !Metal {
|
||||
|
||||
return Metal{
|
||||
.alloc = alloc,
|
||||
.window_mailbox = options.window_mailbox,
|
||||
.surface_mailbox = options.surface_mailbox,
|
||||
.cell_size = .{ .width = metrics.cell_width, .height = metrics.cell_height },
|
||||
.padding = options.padding,
|
||||
.focused = true,
|
||||
@ -304,7 +304,7 @@ pub fn deinit(self: *Metal) void {
|
||||
|
||||
/// This is called just prior to spinning up the renderer thread for
|
||||
/// final main thread setup requirements.
|
||||
pub fn finalizeWindowInit(self: *const Metal, win: apprt.runtime.Window) !void {
|
||||
pub fn finalizeSurfaceInit(self: *const Metal, surface: *apprt.Surface) !void {
|
||||
const Info = struct {
|
||||
view: objc.Object,
|
||||
scaleFactor: f64,
|
||||
@ -315,7 +315,7 @@ pub fn finalizeWindowInit(self: *const Metal, win: apprt.runtime.Window) !void {
|
||||
apprt.glfw => info: {
|
||||
// Everything in glfw is window-oriented so we grab the backing
|
||||
// window, then derive everything from that.
|
||||
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(win.window).?);
|
||||
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(surface.window).?);
|
||||
const contentView = objc.Object.fromId(nswindow.getProperty(?*anyopaque, "contentView").?);
|
||||
const scaleFactor = nswindow.getProperty(macos.graphics.c.CGFloat, "backingScaleFactor");
|
||||
break :info .{
|
||||
@ -325,8 +325,8 @@ pub fn finalizeWindowInit(self: *const Metal, win: apprt.runtime.Window) !void {
|
||||
},
|
||||
|
||||
apprt.embedded => .{
|
||||
.view = win.nsview,
|
||||
.scaleFactor = @floatCast(f64, win.content_scale.x),
|
||||
.view = surface.nsview,
|
||||
.scaleFactor = @floatCast(f64, surface.content_scale.x),
|
||||
},
|
||||
|
||||
else => @compileError("unsupported apprt for metal"),
|
||||
@ -344,11 +344,11 @@ pub fn finalizeWindowInit(self: *const Metal, win: apprt.runtime.Window) !void {
|
||||
}
|
||||
|
||||
/// This is called if this renderer runs DevMode.
|
||||
pub fn initDevMode(self: *const Metal, win: apprt.runtime.Window) !void {
|
||||
pub fn initDevMode(self: *const Metal, surface: *apprt.Surface) !void {
|
||||
if (DevMode.enabled) {
|
||||
// Initialize for our window
|
||||
assert(imgui.ImplGlfw.initForOther(
|
||||
@ptrCast(*imgui.ImplGlfw.GLFWWindow, win.window.handle),
|
||||
@ptrCast(*imgui.ImplGlfw.GLFWWindow, surface.window.handle),
|
||||
true,
|
||||
));
|
||||
assert(imgui.ImplMetal.init(self.device.value));
|
||||
@ -366,9 +366,9 @@ pub fn deinitDevMode(self: *const Metal) void {
|
||||
}
|
||||
|
||||
/// Callback called by renderer.Thread when it begins.
|
||||
pub fn threadEnter(self: *const Metal, win: apprt.runtime.Window) !void {
|
||||
pub fn threadEnter(self: *const Metal, surface: *apprt.Surface) !void {
|
||||
_ = self;
|
||||
_ = win;
|
||||
_ = surface;
|
||||
|
||||
// Metal requires no per-thread state.
|
||||
}
|
||||
@ -442,7 +442,7 @@ pub fn setFontSize(self: *Metal, size: font.face.DesiredSize) !void {
|
||||
};
|
||||
|
||||
// Notify the window that the cell size changed.
|
||||
_ = self.window_mailbox.push(.{
|
||||
_ = self.surface_mailbox.push(.{
|
||||
.cell_size = new_cell_size,
|
||||
}, .{ .forever = {} });
|
||||
}
|
||||
@ -450,10 +450,10 @@ pub fn setFontSize(self: *Metal, size: font.face.DesiredSize) !void {
|
||||
/// The primary render callback that is completely thread-safe.
|
||||
pub fn render(
|
||||
self: *Metal,
|
||||
win: apprt.runtime.Window,
|
||||
surface: *apprt.Surface,
|
||||
state: *renderer.State,
|
||||
) !void {
|
||||
_ = win;
|
||||
_ = surface;
|
||||
|
||||
// Data we extract out of the critical area.
|
||||
const Critical = struct {
|
||||
@ -533,8 +533,8 @@ pub fn render(
|
||||
critical.draw_cursor,
|
||||
);
|
||||
|
||||
// Get our surface (CAMetalDrawable)
|
||||
const surface = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
|
||||
// Get our drawable (CAMetalDrawable)
|
||||
const drawable = self.swapchain.msgSend(objc.Object, objc.sel("nextDrawable"), .{});
|
||||
|
||||
// If our font atlas changed, sync the texture data
|
||||
if (self.font_group.atlas_greyscale.modified) {
|
||||
@ -572,7 +572,7 @@ pub fn render(
|
||||
// Ghostty in XCode in debug mode it returns a CaptureMTLDrawable
|
||||
// which ironically doesn't implement CAMetalDrawable as a
|
||||
// property so we just send a message.
|
||||
const texture = surface.msgSend(objc.c.id, objc.sel("texture"), .{});
|
||||
const texture = drawable.msgSend(objc.c.id, objc.sel("texture"), .{});
|
||||
attachment.setProperty("loadAction", @enumToInt(MTLLoadAction.clear));
|
||||
attachment.setProperty("storeAction", @enumToInt(MTLStoreAction.store));
|
||||
attachment.setProperty("texture", texture);
|
||||
@ -656,7 +656,7 @@ pub fn render(
|
||||
}
|
||||
}
|
||||
|
||||
buffer.msgSend(void, objc.sel("presentDrawable:"), .{surface.value});
|
||||
buffer.msgSend(void, objc.sel("presentDrawable:"), .{drawable.value});
|
||||
buffer.msgSend(void, objc.sel("commit"), .{});
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user