mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 05:06:24 +03:00
App prepare for multi-window
This commit is contained in:
85
src/App.zig
85
src/App.zig
@ -9,46 +9,111 @@ const glfw = @import("glfw");
|
|||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
const Config = @import("config.zig").Config;
|
const Config = @import("config.zig").Config;
|
||||||
|
const BlockingQueue = @import("./blocking_queue.zig").BlockingQueue;
|
||||||
|
|
||||||
const log = std.log.scoped(.app);
|
const log = std.log.scoped(.app);
|
||||||
|
|
||||||
|
const WindowList = std.ArrayListUnmanaged(*Window);
|
||||||
|
|
||||||
|
/// The type used for sending messages to the app thread.
|
||||||
|
pub const Mailbox = BlockingQueue(Message, 64);
|
||||||
|
|
||||||
/// General purpose allocator
|
/// General purpose allocator
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
|
|
||||||
/// The primary window for the application. We currently support only
|
/// The list of windows that are currently open
|
||||||
/// single window operations.
|
windows: WindowList,
|
||||||
window: *Window,
|
|
||||||
|
|
||||||
// The configuration for the app.
|
// The configuration for the app.
|
||||||
config: *const Config,
|
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,
|
||||||
|
|
||||||
/// Initialize the main app instance. This creates the main window, sets
|
/// Initialize the main app instance. This creates the main window, sets
|
||||||
/// up the renderer state, compiles the shaders, etc. This is the primary
|
/// up the renderer state, compiles the shaders, etc. This is the primary
|
||||||
/// "startup" logic.
|
/// "startup" logic.
|
||||||
pub fn init(alloc: Allocator, config: *const Config) !App {
|
pub fn init(alloc: Allocator, config: *const Config) !App {
|
||||||
// Create the window
|
// 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);
|
var window = try Window.create(alloc, config);
|
||||||
errdefer window.destroy();
|
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{
|
return App{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.window = window,
|
.windows = windows,
|
||||||
.config = config,
|
.config = config,
|
||||||
|
.mailbox = mailbox,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *App) void {
|
pub fn deinit(self: *App) void {
|
||||||
self.window.destroy();
|
// 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.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(self: App) !void {
|
/// Wake up the app event loop. This should be called after any messages
|
||||||
while (!self.window.shouldClose()) {
|
/// are sent to the mailbox.
|
||||||
// Block for any glfw events. This may also be an "empty" event
|
pub fn wakeup(self: App) void {
|
||||||
// posted by the libuv watcher so that we trigger a libuv loop tick.
|
_ = self;
|
||||||
|
glfw.postEmptyEvent() catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the main event loop for the application. This blocks until the
|
||||||
|
/// application quits or every window is closed.
|
||||||
|
pub fn run(self: *App) !void {
|
||||||
|
while (self.windows.items.len > 0) {
|
||||||
|
// Block for any glfw events.
|
||||||
try glfw.waitEvents();
|
try glfw.waitEvents();
|
||||||
|
|
||||||
// Mark this so we're in a totally different "frame"
|
// Mark this so we're in a totally different "frame"
|
||||||
tracy.frameMark();
|
tracy.frameMark();
|
||||||
|
|
||||||
|
// If any windows are closing, destroy them
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < self.windows.items.len) {
|
||||||
|
const window = self.windows.items[i];
|
||||||
|
if (window.shouldClose()) {
|
||||||
|
window.destroy();
|
||||||
|
_ = self.windows.swapRemove(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drain our mailbox
|
||||||
|
try self.drainMailbox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Drain the mailbox.
|
||||||
|
fn drainMailbox(self: *App) !void {
|
||||||
|
var drain = self.mailbox.drain();
|
||||||
|
defer drain.deinit();
|
||||||
|
|
||||||
|
while (drain.next()) |message| {
|
||||||
|
log.debug("mailbox message={}", .{message});
|
||||||
|
switch (message) {
|
||||||
|
.new_window => unreachable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The message types that can be sent to the app thread.
|
||||||
|
pub const Message = union(enum) {
|
||||||
|
/// Create a new terminal window.
|
||||||
|
new_window: void,
|
||||||
|
};
|
||||||
|
@ -136,6 +136,10 @@ pub fn create(alloc: Allocator, config: *const Config) !*Window {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Find all the fonts for this window
|
// Find all the fonts for this window
|
||||||
|
//
|
||||||
|
// Future: we can share the font group amongst all windows to save
|
||||||
|
// some new window init time and some memory. This will require making
|
||||||
|
// thread-safe changes to font structs.
|
||||||
var font_lib = try font.Library.init();
|
var font_lib = try font.Library.init();
|
||||||
errdefer font_lib.deinit();
|
errdefer font_lib.deinit();
|
||||||
var font_group = try alloc.create(font.GroupCache);
|
var font_group = try alloc.create(font.GroupCache);
|
||||||
|
Reference in New Issue
Block a user