mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
surface no longer has reference to app
This commit is contained in:
74
src/App.zig
74
src/App.zig
@ -24,9 +24,6 @@ const log = std.log.scoped(.app);
|
||||
|
||||
const SurfaceList = std.ArrayListUnmanaged(*apprt.Surface);
|
||||
|
||||
/// The type used for sending messages to the app thread.
|
||||
pub const Mailbox = BlockingQueue(Message, 64);
|
||||
|
||||
/// General purpose allocator
|
||||
alloc: Allocator,
|
||||
|
||||
@ -38,14 +35,11 @@ config: *const Config,
|
||||
|
||||
/// The mailbox that can be used to send this thread messages. Note
|
||||
/// this is a blocking queue so if it is full you will get errors (or block).
|
||||
mailbox: *Mailbox,
|
||||
mailbox: Mailbox.Queue,
|
||||
|
||||
/// Set to true once we're quitting. This never goes false again.
|
||||
quit: bool,
|
||||
|
||||
/// App will call this when tick should be called.
|
||||
wakeup_cb: ?*const fn () void = null,
|
||||
|
||||
/// Initialize the main app instance. This creates the main window, sets
|
||||
/// up the renderer state, compiles the shaders, etc. This is the primary
|
||||
/// "startup" logic.
|
||||
@ -53,10 +47,6 @@ pub fn create(
|
||||
alloc: Allocator,
|
||||
config: *const Config,
|
||||
) !*App {
|
||||
// The mailbox for messaging this thread
|
||||
var mailbox = try Mailbox.create(alloc);
|
||||
errdefer mailbox.destroy(alloc);
|
||||
|
||||
// If we have DevMode on, store the config so we can show it
|
||||
if (DevMode.enabled) DevMode.instance.config = config;
|
||||
|
||||
@ -66,7 +56,7 @@ pub fn create(
|
||||
.alloc = alloc,
|
||||
.surfaces = .{},
|
||||
.config = config,
|
||||
.mailbox = mailbox,
|
||||
.mailbox = .{},
|
||||
.quit = false,
|
||||
};
|
||||
errdefer app.surfaces.deinit(alloc);
|
||||
@ -78,16 +68,10 @@ pub fn destroy(self: *App) void {
|
||||
// Clean up all our surfaces
|
||||
for (self.surfaces.items) |surface| surface.deinit();
|
||||
self.surfaces.deinit(self.alloc);
|
||||
self.mailbox.destroy(self.alloc);
|
||||
|
||||
self.alloc.destroy(self);
|
||||
}
|
||||
|
||||
/// Request the app runtime to process app events via tick.
|
||||
pub fn wakeup(self: App) void {
|
||||
if (self.wakeup_cb) |cb| cb();
|
||||
}
|
||||
|
||||
/// Tick ticks the app loop. This will drain our mailbox and process those
|
||||
/// events. This should be called by the application runtime on every loop
|
||||
/// tick.
|
||||
@ -127,25 +111,12 @@ pub fn deleteSurface(self: *App, rt_surface: *apprt.Surface) void {
|
||||
while (i < self.surfaces.items.len) {
|
||||
if (self.surfaces.items[i] == rt_surface) {
|
||||
_ = self.surfaces.swapRemove(i);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/// Close a window and free all resources associated with it. This can
|
||||
/// only be called from the main thread.
|
||||
// pub fn closeWindow(self: *App, window: *Window) void {
|
||||
// var i: usize = 0;
|
||||
// while (i < self.surfaces.items.len) {
|
||||
// const current = self.surfaces.items[i];
|
||||
// if (window == current) {
|
||||
// window.destroy();
|
||||
// _ = self.surfaces.swapRemove(i);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// i += 1;
|
||||
// }
|
||||
// }
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Drain the mailbox.
|
||||
fn drainMailbox(self: *App, rt_app: *apprt.runtime.App) !void {
|
||||
@ -154,12 +125,18 @@ fn drainMailbox(self: *App, rt_app: *apprt.runtime.App) !void {
|
||||
switch (message) {
|
||||
.new_window => |msg| try self.newWindow(rt_app, msg),
|
||||
.new_tab => |msg| try self.newTab(rt_app, msg),
|
||||
.close => |surface| try self.closeSurface(rt_app, surface),
|
||||
.quit => try self.setQuit(),
|
||||
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn closeSurface(self: *App, rt_app: *apprt.App, surface: *Surface) !void {
|
||||
if (!self.hasSurface(surface)) return;
|
||||
rt_app.closeSurface(surface.rt_surface);
|
||||
}
|
||||
|
||||
/// Create a new window
|
||||
fn newWindow(self: *App, rt_app: *apprt.runtime.App, msg: Message.NewWindow) !void {
|
||||
const window = try rt_app.newWindow();
|
||||
@ -231,6 +208,10 @@ pub const Message = union(enum) {
|
||||
/// environment that doesn't support tabs.
|
||||
new_tab: NewTab,
|
||||
|
||||
/// Close a surface. This notifies the runtime that a surface
|
||||
/// should close.
|
||||
close: *Surface,
|
||||
|
||||
/// Quit
|
||||
quit: void,
|
||||
|
||||
@ -254,6 +235,25 @@ pub const Message = union(enum) {
|
||||
};
|
||||
};
|
||||
|
||||
/// Mailbox is the way that other threads send the app thread messages.
|
||||
pub const Mailbox = struct {
|
||||
/// The type used for sending messages to the app thread.
|
||||
pub const Queue = BlockingQueue(Message, 64);
|
||||
|
||||
rt_app: *apprt.App,
|
||||
mailbox: *Queue,
|
||||
|
||||
/// Send a message to the surface.
|
||||
pub fn push(self: Mailbox, msg: Message, timeout: Queue.Timeout) Queue.Size {
|
||||
const result = self.mailbox.push(msg, timeout);
|
||||
|
||||
// Wake up our app loop
|
||||
self.rt_app.wakeup();
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Wasm API.
|
||||
pub const Wasm = if (!builtin.target.isWasm()) struct {} else struct {
|
||||
const wasm = @import("os/wasm.zig");
|
||||
@ -329,7 +329,7 @@ pub const CAPI = struct {
|
||||
/// Create a new surface as part of an app.
|
||||
export fn ghostty_surface_new(
|
||||
app: *App,
|
||||
opts: *const apprt.runtime.Window.Options,
|
||||
opts: *const apprt.Surface.Options,
|
||||
) ?*Surface {
|
||||
return surface_new_(app, opts) catch |err| {
|
||||
log.err("error initializing surface err={}", .{err});
|
||||
@ -339,7 +339,7 @@ pub const CAPI = struct {
|
||||
|
||||
fn surface_new_(
|
||||
app: *App,
|
||||
opts: *const apprt.runtime.Window.Options,
|
||||
opts: *const apprt.Surface.Options,
|
||||
) !*Surface {
|
||||
const w = try app.newWindow(.{
|
||||
.runtime = opts.*,
|
||||
|
@ -42,8 +42,8 @@ const Renderer = renderer.Renderer;
|
||||
/// Allocator
|
||||
alloc: Allocator,
|
||||
|
||||
/// The app that this window is a part of.
|
||||
app: *App,
|
||||
/// The mailbox for sending messages to the main app thread.
|
||||
app_mailbox: App.Mailbox,
|
||||
|
||||
/// The windowing system surface
|
||||
rt_surface: *apprt.runtime.Surface,
|
||||
@ -128,12 +128,11 @@ const Mouse = struct {
|
||||
/// stable due to interfacing with various callbacks.
|
||||
pub fn init(
|
||||
self: *Surface,
|
||||
app: *App,
|
||||
alloc: Allocator,
|
||||
config: *const Config,
|
||||
app_mailbox: App.Mailbox,
|
||||
rt_surface: *apprt.runtime.Surface,
|
||||
) !void {
|
||||
const alloc = app.alloc;
|
||||
|
||||
// Initialize our renderer with our initialized surface.
|
||||
try Renderer.surfaceInit(rt_surface);
|
||||
|
||||
@ -291,7 +290,7 @@ pub fn init(
|
||||
.explicit = padding,
|
||||
.balance = config.@"window-padding-balance",
|
||||
},
|
||||
.surface_mailbox = .{ .surface = self, .app = app.mailbox },
|
||||
.surface_mailbox = .{ .surface = self, .app = app_mailbox },
|
||||
});
|
||||
errdefer renderer_impl.deinit();
|
||||
|
||||
@ -328,7 +327,7 @@ pub fn init(
|
||||
.renderer_state = &self.renderer_state,
|
||||
.renderer_wakeup = render_thread.wakeup,
|
||||
.renderer_mailbox = render_thread.mailbox,
|
||||
.surface_mailbox = .{ .surface = self, .app = app.mailbox },
|
||||
.surface_mailbox = .{ .surface = self, .app = app_mailbox },
|
||||
});
|
||||
errdefer io.deinit();
|
||||
|
||||
@ -343,7 +342,7 @@ pub fn init(
|
||||
|
||||
self.* = .{
|
||||
.alloc = alloc,
|
||||
.app = app,
|
||||
.app_mailbox = app_mailbox,
|
||||
.rt_surface = rt_surface,
|
||||
.font_lib = font_lib,
|
||||
.font_group = font_group,
|
||||
@ -902,30 +901,29 @@ pub fn keyCallback(
|
||||
} else log.warn("dev mode was not compiled into this binary", .{}),
|
||||
|
||||
.new_window => {
|
||||
_ = self.app.mailbox.push(.{
|
||||
_ = self.app_mailbox.push(.{
|
||||
.new_window = .{
|
||||
.parent = self,
|
||||
},
|
||||
}, .{ .instant = {} });
|
||||
self.app.wakeup();
|
||||
},
|
||||
|
||||
.new_tab => {
|
||||
_ = self.app.mailbox.push(.{
|
||||
_ = self.app_mailbox.push(.{
|
||||
.new_tab = .{
|
||||
.parent = self,
|
||||
},
|
||||
}, .{ .instant = {} });
|
||||
self.app.wakeup();
|
||||
},
|
||||
|
||||
.close_window => self.rt_surface.setShouldClose(),
|
||||
.close_window => {
|
||||
_ = self.app_mailbox.push(.{ .close = self }, .{ .instant = {} });
|
||||
},
|
||||
|
||||
.quit => {
|
||||
_ = self.app.mailbox.push(.{
|
||||
_ = self.app_mailbox.push(.{
|
||||
.quit = {},
|
||||
}, .{ .instant = {} });
|
||||
self.app.wakeup();
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,11 @@ pub const App = struct {
|
||||
write_clipboard: *const fn (SurfaceUD, [*:0]const u8) callconv(.C) void,
|
||||
};
|
||||
|
||||
core_app: *CoreApp,
|
||||
opts: Options,
|
||||
|
||||
pub fn init(opts: Options) !App {
|
||||
return .{ .opts = opts };
|
||||
pub fn init(core_app: *CoreApp, opts: Options) !App {
|
||||
return .{ .core_app = core_app, .opts = opts };
|
||||
}
|
||||
|
||||
pub fn terminate(self: App) void {
|
||||
@ -67,7 +68,7 @@ pub const App = struct {
|
||||
|
||||
pub const Surface = struct {
|
||||
nsview: objc.Object,
|
||||
core_win: *CoreSurface,
|
||||
core_surface: *CoreSurface,
|
||||
content_scale: apprt.ContentScale,
|
||||
size: apprt.SurfaceSize,
|
||||
cursor_pos: apprt.CursorPos,
|
||||
@ -84,11 +85,9 @@ pub const Surface = struct {
|
||||
scale_factor: f64 = 1,
|
||||
};
|
||||
|
||||
pub fn init(app: *const CoreApp, core_win: *CoreSurface, opts: Options) !Surface {
|
||||
_ = app;
|
||||
|
||||
return .{
|
||||
.core_win = core_win,
|
||||
pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
||||
self.* = .{
|
||||
.core_surface = undefined,
|
||||
.nsview = objc.Object.fromId(opts.nsview),
|
||||
.content_scale = .{
|
||||
.x = @floatCast(f32, opts.scale_factor),
|
||||
@ -98,10 +97,23 @@ pub const Surface = struct {
|
||||
.cursor_pos = .{ .x = 0, .y = 0 },
|
||||
.opts = opts,
|
||||
};
|
||||
|
||||
// Add ourselves to the list of surfaces on the app.
|
||||
try app.app.addSurface(self);
|
||||
errdefer app.app.deleteSurface(self);
|
||||
|
||||
// Initialize our surface right away. We're given a view that is
|
||||
// ready to use.
|
||||
try self.core_surface.init(app.app, app.app.config, self);
|
||||
errdefer self.core_surface.deinit();
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Surface) void {
|
||||
_ = self;
|
||||
// Remove ourselves from the list of known surfaces in the app.
|
||||
self.core_surface.app.deleteSurface(self);
|
||||
|
||||
// Clean up our core surface so that all the rendering and IO stop.
|
||||
self.core_surface.deinit();
|
||||
}
|
||||
|
||||
pub fn getContentScale(self: *const Surface) !apprt.ContentScale {
|
||||
@ -119,19 +131,19 @@ pub const Surface = struct {
|
||||
}
|
||||
|
||||
pub fn setTitle(self: *Surface, slice: [:0]const u8) !void {
|
||||
self.core_win.app.runtime.opts.set_title(
|
||||
self.core_surface.app.runtime.opts.set_title(
|
||||
self.opts.userdata,
|
||||
slice.ptr,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn getClipboardString(self: *const Surface) ![:0]const u8 {
|
||||
const ptr = self.core_win.app.runtime.opts.read_clipboard(self.opts.userdata);
|
||||
const ptr = self.core_surface.app.runtime.opts.read_clipboard(self.opts.userdata);
|
||||
return std.mem.sliceTo(ptr, 0);
|
||||
}
|
||||
|
||||
pub fn setClipboardString(self: *const Surface, val: [:0]const u8) !void {
|
||||
self.core_win.app.runtime.opts.write_clipboard(self.opts.userdata, val.ptr);
|
||||
self.core_surface.app.runtime.opts.write_clipboard(self.opts.userdata, val.ptr);
|
||||
}
|
||||
|
||||
pub fn setShouldClose(self: *Surface) void {
|
||||
@ -148,7 +160,7 @@ pub const Surface = struct {
|
||||
}
|
||||
|
||||
pub fn refresh(self: *Surface) void {
|
||||
self.core_win.refreshCallback() catch |err| {
|
||||
self.core_surface.refreshCallback() catch |err| {
|
||||
log.err("error in refresh callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
@ -168,7 +180,7 @@ pub const Surface = struct {
|
||||
};
|
||||
|
||||
// Call the primary callback.
|
||||
self.core_win.sizeCallback(self.size) catch |err| {
|
||||
self.core_surface.sizeCallback(self.size) catch |err| {
|
||||
log.err("error in size callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
@ -180,14 +192,14 @@ pub const Surface = struct {
|
||||
button: input.MouseButton,
|
||||
mods: input.Mods,
|
||||
) void {
|
||||
self.core_win.mouseButtonCallback(action, button, mods) catch |err| {
|
||||
self.core_surface.mouseButtonCallback(action, button, mods) catch |err| {
|
||||
log.err("error in mouse button callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn scrollCallback(self: *const Surface, xoff: f64, yoff: f64) void {
|
||||
self.core_win.scrollCallback(xoff, yoff) catch |err| {
|
||||
self.core_surface.scrollCallback(xoff, yoff) catch |err| {
|
||||
log.err("error in scroll callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
@ -195,7 +207,7 @@ pub const Surface = struct {
|
||||
|
||||
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(.{
|
||||
self.cursor_pos = self.core_surface.window.cursorPosToPixels(.{
|
||||
.x = @floatCast(f32, x),
|
||||
.y = @floatCast(f32, y),
|
||||
}) catch |err| {
|
||||
@ -206,7 +218,7 @@ pub const Surface = struct {
|
||||
return;
|
||||
};
|
||||
|
||||
self.core_win.cursorPosCallback(self.cursor_pos) catch |err| {
|
||||
self.core_surface.cursorPosCallback(self.cursor_pos) catch |err| {
|
||||
log.err("error in cursor pos callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
@ -219,7 +231,7 @@ pub const Surface = struct {
|
||||
mods: input.Mods,
|
||||
) void {
|
||||
// log.warn("key action={} key={} mods={}", .{ action, key, mods });
|
||||
self.core_win.keyCallback(action, key, mods) catch |err| {
|
||||
self.core_surface.keyCallback(action, key, mods) catch |err| {
|
||||
log.err("error in key callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
@ -227,14 +239,14 @@ pub const Surface = struct {
|
||||
|
||||
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| {
|
||||
self.core_surface.charCallback(cp) catch |err| {
|
||||
log.err("error in char callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn focusCallback(self: *const Surface, focused: bool) void {
|
||||
self.core_win.focusCallback(focused) catch |err| {
|
||||
self.core_surface.focusCallback(focused) catch |err| {
|
||||
log.err("error in focus callback err={}", .{err});
|
||||
return;
|
||||
};
|
||||
|
@ -43,9 +43,6 @@ pub const App = struct {
|
||||
var darwin = if (Darwin.enabled) try Darwin.init() else {};
|
||||
errdefer if (Darwin.enabled) darwin.deinit();
|
||||
|
||||
// Set our callback for being woken up
|
||||
core_app.wakeup_cb = wakeup;
|
||||
|
||||
return .{
|
||||
.app = core_app,
|
||||
.darwin = darwin,
|
||||
@ -71,7 +68,8 @@ pub const App = struct {
|
||||
}
|
||||
|
||||
/// Wakeup the event loop. This should be able to be called from any thread.
|
||||
pub fn wakeup() void {
|
||||
pub fn wakeup(self: *const App) void {
|
||||
_ = self;
|
||||
glfw.postEmptyEvent();
|
||||
}
|
||||
|
||||
@ -114,11 +112,11 @@ pub const App = struct {
|
||||
// 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;
|
||||
return window;
|
||||
};
|
||||
parent.sizeCallback(size) catch |err| {
|
||||
log.err("error in size callback from new tab err={}", .{err});
|
||||
return;
|
||||
return window;
|
||||
};
|
||||
|
||||
return window;
|
||||
@ -193,6 +191,9 @@ pub const Surface = struct {
|
||||
/// The glfw mouse cursor handle.
|
||||
cursor: glfw.Cursor,
|
||||
|
||||
/// The app we're part of
|
||||
app: *App,
|
||||
|
||||
/// A core surface
|
||||
core_surface: CoreSurface,
|
||||
|
||||
@ -265,6 +266,7 @@ pub const Surface = struct {
|
||||
|
||||
// Build our result
|
||||
self.* = .{
|
||||
.app = app,
|
||||
.window = win,
|
||||
.cursor = cursor,
|
||||
.core_surface = undefined,
|
||||
@ -276,13 +278,18 @@ pub const Surface = struct {
|
||||
errdefer app.app.deleteSurface(self);
|
||||
|
||||
// Initialize our surface now that we have the stable pointer.
|
||||
try self.core_surface.init(app.app, app.app.config, self);
|
||||
try self.core_surface.init(
|
||||
app.app.alloc,
|
||||
app.app.config,
|
||||
.{ .rt_app = app, .mailbox = &app.app.mailbox },
|
||||
self,
|
||||
);
|
||||
errdefer self.core_surface.deinit();
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Surface) void {
|
||||
// Remove ourselves from the list of known surfaces in the app.
|
||||
self.core_surface.app.deleteSurface(self);
|
||||
self.app.app.deleteSurface(self);
|
||||
|
||||
// Clean up our core surface so that all the rendering and IO stop.
|
||||
self.core_surface.deinit();
|
||||
|
@ -28,23 +28,22 @@ pub const Message = union(enum) {
|
||||
/// A surface mailbox.
|
||||
pub const Mailbox = struct {
|
||||
surface: *Surface,
|
||||
app: *App.Mailbox,
|
||||
app: App.Mailbox,
|
||||
|
||||
/// Send a message to the surface.
|
||||
pub fn push(self: Mailbox, msg: Message, timeout: App.Mailbox.Timeout) App.Mailbox.Size {
|
||||
pub fn push(
|
||||
self: Mailbox,
|
||||
msg: Message,
|
||||
timeout: App.Mailbox.Queue.Timeout,
|
||||
) App.Mailbox.Queue.Size {
|
||||
// Surface message sending is actually implemented on the app
|
||||
// thread, so we have to rewrap the message with our surface
|
||||
// pointer and send it to the app thread.
|
||||
const result = self.app.push(.{
|
||||
return self.app.push(.{
|
||||
.surface_message = .{
|
||||
.surface = self.surface,
|
||||
.message = msg,
|
||||
},
|
||||
}, timeout);
|
||||
|
||||
// Wake up our app loop
|
||||
self.surface.app.wakeup();
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user