Hook up new window, modify renderers

This commit is contained in:
Mitchell Hashimoto
2022-11-06 10:34:43 -08:00
parent a2edbb4698
commit ecbd119654
7 changed files with 90 additions and 33 deletions

View File

@ -10,6 +10,7 @@ const Window = @import("Window.zig");
const tracy = @import("tracy");
const Config = @import("config.zig").Config;
const BlockingQueue = @import("./blocking_queue.zig").BlockingQueue;
const renderer = @import("renderer.zig");
const log = std.log.scoped(.app);
@ -34,34 +35,33 @@ mailbox: *Mailbox,
/// 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.
pub fn init(alloc: Allocator, config: *const Config) !App {
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);
// Create the first window
var window = try Window.create(alloc, config);
errdefer window.destroy();
// Create our windows list and add our initial window.
var windows: WindowList = .{};
errdefer windows.deinit(alloc);
try windows.append(alloc, window);
return App{
var app = try alloc.create(App);
errdefer alloc.destroy(app);
app.* = .{
.alloc = alloc,
.windows = windows,
.windows = .{},
.config = config,
.mailbox = mailbox,
};
errdefer app.windows.deinit(alloc);
// Create the first window
try app.newWindow();
return app;
}
pub fn deinit(self: *App) void {
pub fn destroy(self: *App) void {
// Clean up all our windows
for (self.windows.items) |window| window.destroy();
self.windows.deinit(self.alloc);
self.mailbox.destroy(self.alloc);
self.* = undefined;
self.alloc.destroy(self);
}
/// Wake up the app event loop. This should be called after any messages
@ -86,6 +86,11 @@ pub fn run(self: *App) !void {
while (i < self.windows.items.len) {
const window = self.windows.items[i];
if (window.shouldClose()) {
// If this was our final window, deinitialize the renderer
if (self.windows.items.len == 1) {
renderer.Renderer.lastWindowDeinit();
}
window.destroy();
_ = self.windows.swapRemove(i);
continue;
@ -107,11 +112,24 @@ fn drainMailbox(self: *App) !void {
while (drain.next()) |message| {
log.debug("mailbox message={}", .{message});
switch (message) {
.new_window => unreachable,
.new_window => try self.newWindow(),
}
}
}
/// Create a new window
fn newWindow(self: *App) !void {
var window = try Window.create(self.alloc, self, self.config);
errdefer window.destroy();
try self.windows.append(self.alloc, window);
errdefer _ = self.windows.pop();
// This was the first window, so we need to initialize our renderer.
if (self.windows.items.len == 1) {
try window.renderer.firstWindowInit(window.window);
}
}
/// The message types that can be sent to the app thread.
pub const Message = union(enum) {
/// Create a new terminal window.

View File

@ -22,6 +22,7 @@ const terminal = @import("terminal/main.zig");
const Config = @import("config.zig").Config;
const input = @import("input.zig");
const DevMode = @import("DevMode.zig");
const App = @import("App.zig");
// Get native API access on certain platforms so we can do more customization.
const glfwNative = glfw.Native(.{
@ -36,6 +37,9 @@ const Renderer = renderer.Renderer;
/// Allocator
alloc: Allocator,
/// The app that this window is a part of.
app: *App,
/// The font structures
font_lib: font.Library,
font_group: *font.GroupCache,
@ -107,7 +111,7 @@ const Mouse = struct {
/// Create a new window. This allocates and returns a pointer because we
/// need a stable pointer for user data callbacks. Therefore, a stack-only
/// initialization is not currently possible.
pub fn create(alloc: Allocator, config: *const Config) !*Window {
pub fn create(alloc: Allocator, app: *App, config: *const Config) !*Window {
var self = try alloc.create(Window);
errdefer alloc.destroy(self);
@ -313,6 +317,7 @@ pub fn create(alloc: Allocator, config: *const Config) !*Window {
self.* = .{
.alloc = alloc,
.app = app,
.font_lib = font_lib,
.font_group = font_group,
.window = window,
@ -386,7 +391,7 @@ pub fn create(alloc: Allocator, config: *const Config) !*Window {
// Give the renderer one more opportunity to finalize any window
// setup on the main thread prior to spinning up the rendering thread.
try renderer_impl.finalizeInit(window);
try renderer_impl.finalizeWindowInit(window);
// Start our renderer thread
self.renderer_thr = try std.Thread.spawn(
@ -752,6 +757,13 @@ fn keyCallback(
DevMode.instance.visible = !DevMode.instance.visible;
win.queueRender() catch unreachable;
} else log.warn("dev mode was not compiled into this binary", .{}),
.new_window => {
_ = win.app.mailbox.push(.{
.new_window = {},
}, .{ .forever = {} });
win.app.wakeup();
},
}
// Bindings always result in us ignoring the char if printable

View File

@ -157,6 +157,12 @@ pub const Config = struct {
.{ .toggle_dev_mode = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .up, .mods = .{ .super = true } },
.{ .new_window = {} },
);
return result;
}

View File

@ -133,6 +133,9 @@ pub const Action = union(enum) {
/// Dev mode
toggle_dev_mode: void,
/// Open a new terminal window.
new_window: void,
};
/// Trigger is the associated key state that can trigger an action.

View File

@ -128,8 +128,8 @@ pub fn main() !void {
defer glfw.terminate();
// Run our app
var app = try App.init(alloc, &config);
defer app.deinit();
var app = try App.create(alloc, &config);
defer app.destroy();
try app.run();
}

View File

@ -240,11 +240,6 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !Metal {
}
pub fn deinit(self: *Metal) void {
if (DevMode.enabled) {
imgui.ImplMetal.shutdown();
imgui.ImplGlfw.shutdown();
}
self.cells.deinit(self.alloc);
self.font_shaper.deinit();
@ -255,7 +250,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 finalizeInit(self: *const Metal, window: glfw.Window) !void {
pub fn finalizeWindowInit(self: *const Metal, window: glfw.Window) !void {
// Set our window backing layer to be our swapchain
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(window).?);
const contentView = objc.Object.fromId(nswindow.getProperty(?*anyopaque, "contentView").?);
@ -268,7 +263,12 @@ pub fn finalizeInit(self: *const Metal, window: glfw.Window) !void {
const layer = contentView.getProperty(objc.Object, "layer");
const scaleFactor = nswindow.getProperty(macos.graphics.c.CGFloat, "backingScaleFactor");
layer.setProperty("contentsScale", scaleFactor);
}
/// This is called only after the first window is opened. This may be
/// called multiple times if all windows are closed and a new one is
/// reopened.
pub fn firstWindowInit(self: *const Metal, window: glfw.Window) !void {
if (DevMode.enabled) {
// Initialize for our window
assert(imgui.ImplGlfw.initForOther(
@ -279,6 +279,14 @@ pub fn finalizeInit(self: *const Metal, window: glfw.Window) !void {
}
}
/// This is called only when the last window is destroyed.
pub fn lastWindowDeinit() void {
if (DevMode.enabled) {
imgui.ImplMetal.shutdown();
imgui.ImplGlfw.shutdown();
}
}
/// Callback called by renderer.Thread when it begins.
pub fn threadEnter(self: *const Metal, window: glfw.Window) !void {
_ = self;

View File

@ -300,11 +300,6 @@ pub fn init(alloc: Allocator, font_group: *font.GroupCache) !OpenGL {
}
pub fn deinit(self: *OpenGL) void {
if (DevMode.enabled) {
imgui.ImplOpenGL3.shutdown();
imgui.ImplGlfw.shutdown();
}
self.font_shaper.deinit();
self.alloc.free(self.font_shaper.cell_buf);
@ -387,7 +382,17 @@ pub fn windowInit(window: glfw.Window) !void {
/// This is called just prior to spinning up the renderer thread for
/// final main thread setup requirements.
pub fn finalizeInit(self: *const OpenGL, window: glfw.Window) !void {
pub fn finalizeWindowInit(self: *const OpenGL, window: glfw.Window) !void {
_ = self;
_ = window;
}
/// This is called only after the first window is opened. This may be
/// called multiple times if all windows are closed and a new one is
/// reopened.
pub fn firstWindowInit(self: *const OpenGL, window: glfw.Window) !void {
_ = self;
if (DevMode.enabled) {
// Initialize for our window
assert(imgui.ImplGlfw.initForOpenGL(
@ -396,9 +401,14 @@ pub fn finalizeInit(self: *const OpenGL, window: glfw.Window) !void {
));
assert(imgui.ImplOpenGL3.init("#version 330 core"));
}
}
// Call thread exit to clean up our context
self.threadExit();
/// This is called only when the last window is destroyed.
pub fn lastWindowDeinit() void {
if (DevMode.enabled) {
imgui.ImplOpenGL3.shutdown();
imgui.ImplGlfw.shutdown();
}
}
/// Callback called by renderer.Thread when it begins.