core: hook up all the inspector activation state and such

This commit is contained in:
Mitchell Hashimoto
2023-10-20 11:25:04 -07:00
parent dcb6eef9c4
commit 7a30d1080e
5 changed files with 87 additions and 3 deletions

View File

@ -3,6 +3,19 @@
//! debugging issues in Ghostty itself.
const Inspector = @This();
const cimgui = @import("cimgui");
pub fn init() Inspector {
return .{};
}
pub fn deinit(self: *Inspector) void {
_ = self;
}
pub fn render(self: *Inspector) void {
_ = self;
var show: bool = true;
cimgui.c.igShowDemoWindow(&show);
}

View File

@ -20,6 +20,7 @@ const builtin = @import("builtin");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;
const Inspector = @import("Inspector.zig");
const renderer = @import("renderer.zig");
const termio = @import("termio.zig");
const objc = @import("objc");
@ -74,6 +75,9 @@ io: termio.Impl,
io_thread: termio.Thread,
io_thr: std.Thread,
/// Terminal inspector
inspector: ?*Inspector = null,
/// All the cached sizes since we need them at various times.
screen_size: renderer.ScreenSize,
grid_size: renderer.GridSize,
@ -550,8 +554,14 @@ pub fn deinit(self: *Surface) void {
self.font_lib.deinit();
self.alloc.destroy(self.font_group);
if (self.inspector) |v| {
v.deinit();
self.alloc.destroy(v);
}
self.alloc.destroy(self.renderer_state.mutex);
self.config.deinit();
log.info("surface closed addr={x}", .{@intFromPtr(self)});
}
@ -561,6 +571,51 @@ pub fn close(self: *Surface) void {
self.rt_surface.close(self.needsConfirmQuit());
}
/// Activate the inspector. This will begin collecting inspection data.
/// This will not affect the GUI. The GUI must use performAction to
/// show/hide the inspector UI.
pub fn activateInspector(self: *Surface) !void {
if (self.inspector != null) return;
// Setup the inspector
var ptr = try self.alloc.create(Inspector);
errdefer self.alloc.destroy(ptr);
ptr.* = Inspector.init();
self.inspector = ptr;
// Put the inspector onto the render state
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
assert(self.renderer_state.inspector == null);
self.renderer_state.inspector = self.inspector;
}
/// Deactivate the inspector and stop collecting any information.
pub fn deactivateInspector(self: *Surface) void {
const inspector = self.inspector orelse return;
// Remove the inspector from the render state
{
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
assert(self.renderer_state.inspector != null);
self.renderer_state.inspector = null;
}
// Deinit the inspector
inspector.deinit();
self.alloc.destroy(inspector);
self.inspector = null;
}
/// Render the inspector. This requires an active ImGui context.
pub fn renderInspector(self: *Surface) void {
const inspector = self.inspector orelse return;
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
inspector.render();
}
/// True if the surface requires confirmation to quit. This should be called
/// by apprt to determine if the surface should confirm before quitting.
pub fn needsConfirmQuit(self: *Surface) bool {

View File

@ -209,8 +209,6 @@ fn gtkRender(area: *c.GtkGLArea, ctx: *c.GdkGLContext, ud: ?*anyopaque) callconv
cimgui.c.igNewFrame();
// Build our UI
var show: bool = true;
cimgui.c.igShowDemoWindow(&show);
if (self.render_callback) |cb| cb(self.render_userdata);
// Render

View File

@ -74,6 +74,12 @@ pub const Inspector = struct {
.location = undefined,
};
// Activate the inspector. If it doesn't work we ignore the error
// because we can just show an error in the inspector window.
self.surface.core_surface.activateInspector() catch |err| {
log.err("failed to activate inspector err={}", .{err});
};
switch (location) {
.hidden => self.location = .{ .hidden = {} },
.window => try self.initWindow(),
@ -81,7 +87,7 @@ pub const Inspector = struct {
}
fn deinit(self: *Inspector) void {
_ = self;
self.surface.core_surface.deactivateInspector();
}
/// Request the inspector is closed.
@ -136,6 +142,8 @@ const Window = struct {
// Initialize our imgui widget
try self.imgui_widget.init();
errdefer self.imgui_widget.deinit();
self.imgui_widget.render_callback = &imguiRender;
self.imgui_widget.render_userdata = self;
// Signals
_ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(&gtkDestroy), self, null, c.G_CONNECT_DEFAULT);
@ -154,6 +162,11 @@ const Window = struct {
c.gtk_window_destroy(self.window);
}
fn imguiRender(ud: ?*anyopaque) void {
const self: *Window = @ptrCast(@alignCast(ud orelse return));
self.inspector.surface.core_surface.renderInspector();
}
/// "destroy" signal for the window
fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void {
_ = v;

View File

@ -2,6 +2,7 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const Inspector = @import("../Inspector.zig");
const terminal = @import("../terminal/main.zig");
const renderer = @import("../renderer.zig");
@ -14,6 +15,10 @@ mutex: *std.Thread.Mutex,
/// The terminal data.
terminal: *terminal.Terminal,
/// The terminal inspector, if any. This will be null while the inspector
/// is not active and will be set when it is active.
inspector: ?*Inspector = null,
/// Dead key state. This will render the current dead key preedit text
/// over the cursor. This currently only ever renders a single codepoint.
/// Preedit can in theory be multiple codepoints long but that is left as