remove imgui and devmode

imgui has been a source of compilation challenges (our fault not theirs)
and devmode hasn't worked in awhile, so drop it.
This commit is contained in:
Mitchell Hashimoto
2023-08-20 08:50:24 -07:00
parent 27c62ea381
commit 7ccf86b175
22 changed files with 0 additions and 1081 deletions

View File

@@ -1,180 +0,0 @@
//! This file implements the "dev mode" interface for the terminal. This
//! includes state managements and rendering.
const DevMode = @This();
const std = @import("std");
const builtin = @import("builtin");
const build_config = @import("build_config.zig");
const imgui = @import("imgui");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const font = @import("font/main.zig");
const Surface = @import("Surface.zig");
const renderer = @import("renderer.zig");
const Config = @import("config.zig").Config;
/// If this is false, the rest of the terminal will be compiled without
/// dev mode support at all.
/// TODO: remove this and use build_config everywhere
pub const enabled = build_config.devmode_enabled;
/// The global DevMode instance that can be used app-wide. Assume all functions
/// are NOT thread-safe unless otherwise noted.
pub var instance: DevMode = .{};
/// Whether to show the dev mode UI currently.
visible: bool = false,
/// Our app config
config: ?Config = null,
/// The surface we're tracking.
surface: ?*Surface = null,
/// Update the state associated with the dev mode. This should generally
/// only be called paired with a render since it otherwise wastes CPU
/// cycles.
///
/// Note: renderers should call their implementation "newFrame" functions
/// prior to this.
pub fn update(self: *const DevMode) !void {
// Buffer that can be used for stuff...
var buf: [1024 * 32]u8 = undefined;
imgui.newFrame();
if (imgui.begin("dev mode", null, .{})) {
defer imgui.end();
if (self.config) |config| {
if (imgui.collapsingHeader("Ghostty Configuration", null, .{})) {
if (imgui.beginTable("config", 2, .{
.row_bg = true,
.borders_inner_h = true,
.borders_outer_h = true,
.borders_inner_v = true,
.borders_outer_v = true,
})) {
defer imgui.endTable();
// Setup headers
imgui.tableSetupColumn("Key", .{}, 0);
imgui.tableSetupColumn("Value", .{}, 0);
imgui.tableHeadersRow();
// Values
imgui.tableNextRow(0);
_ = imgui.tableNextColumn();
imgui.text("font-family");
_ = imgui.tableNextColumn();
imgui.text((try std.fmt.bufPrintZ(&buf, "{any}", .{config.@"font-family"})).ptr);
imgui.tableNextRow(0);
_ = imgui.tableNextColumn();
imgui.text("click-repeat-interval");
_ = imgui.tableNextColumn();
imgui.text((try std.fmt.bufPrintZ(&buf, "{d}", .{config.@"click-repeat-interval"})).ptr);
}
if (imgui.treeNode("Raw Config (Advanced & Ugly)", .{})) {
defer imgui.treePop();
var raw = try std.fmt.bufPrintZ(&buf, "{}", .{config});
imgui.textWrapped("%s", raw.ptr);
}
}
}
if (self.surface) |surface| {
if (imgui.collapsingHeader("Font Manager", null, .{})) {
imgui.text("Glyphs: %d", surface.font_group.glyphs.count());
imgui.sameLine(0, -1);
helpMarker("The number of glyphs loaded and rendered into a " ++
"font atlas currently.");
const Renderer = @TypeOf(surface.renderer);
if (imgui.treeNode("Atlas: Greyscale", .{ .default_open = true })) {
defer imgui.treePop();
const atlas = &surface.font_group.atlas_greyscale;
const tex: usize = switch (Renderer) {
renderer.OpenGL => @intCast(surface.renderer.texture.id),
renderer.Metal => @intFromPtr(surface.renderer.texture_greyscale.value),
else => @compileError("renderer unsupported, add it!"),
};
try self.atlasInfo(atlas, tex);
}
if (imgui.treeNode("Atlas: Color (Emoji)", .{ .default_open = true })) {
defer imgui.treePop();
const atlas = &surface.font_group.atlas_color;
const tex: usize = switch (Renderer) {
renderer.OpenGL => @intCast(surface.renderer.texture_color.id),
renderer.Metal => @intFromPtr(surface.renderer.texture_color.value),
else => @compileError("renderer unsupported, add it!"),
};
try self.atlasInfo(atlas, tex);
}
}
}
}
// Just demo for now
// imgui.showDemoWindow(null);
}
/// Render the scene and return the draw data. The caller must be imgui-aware
/// in order to render the draw data. This lets this file be renderer/backend
/// agnostic.
pub fn render(self: DevMode) !*imgui.DrawData {
_ = self;
imgui.render();
return try imgui.DrawData.get();
}
/// Helper to render a tooltip.
fn helpMarker(desc: [:0]const u8) void {
imgui.textDisabled("(?)");
if (imgui.isItemHovered(.{})) {
imgui.beginTooltip();
defer imgui.endTooltip();
imgui.pushTextWrapPos(imgui.getFontSize() * 35);
defer imgui.popTextWrapPos();
imgui.text(desc.ptr);
}
}
fn atlasInfo(self: *const DevMode, atlas: *font.Atlas, tex: ?usize) !void {
_ = self;
imgui.text("Dimensions: %d x %d", atlas.size, atlas.size);
imgui.sameLine(0, -1);
helpMarker("The pixel dimensions of the atlas texture.");
imgui.text("Size: %d KB", atlas.data.len >> 10);
imgui.sameLine(0, -1);
helpMarker("The byte size of the atlas texture.");
var buf: [1024]u8 = undefined;
imgui.text(
"Format: %s (depth = %d)",
(try std.fmt.bufPrintZ(&buf, "{}", .{atlas.format})).ptr,
atlas.format.depth(),
);
imgui.sameLine(0, -1);
helpMarker("The internal storage format of this atlas.");
if (tex) |id| {
imgui.c.igImage(
@ptrFromInt(id),
.{
.x = @floatFromInt(atlas.size),
.y = @floatFromInt(atlas.size),
},
.{ .x = 0, .y = 0 },
.{ .x = 1, .y = 1 },
.{ .x = 1, .y = 1, .z = 1, .w = 1 },
.{ .x = 0, .y = 0, .z = 0, .w = 0 },
);
}
}

View File

@@ -31,7 +31,6 @@ const trace = @import("tracy").trace;
const terminal = @import("terminal/main.zig");
const configpkg = @import("config.zig");
const input = @import("input.zig");
const DevMode = @import("DevMode.zig");
const App = @import("App.zig");
const internal_os = @import("os/main.zig");
@@ -54,9 +53,6 @@ font_lib: font.Library,
font_group: *font.GroupCache,
font_size: font.face.DesiredSize,
/// Imgui context
imgui_ctx: if (DevMode.enabled) *imgui.Context else void,
/// The renderer for this surface.
renderer: Renderer,
@@ -419,11 +415,6 @@ pub fn init(
var io_thread = try termio.Thread.init(alloc, &self.io);
errdefer io_thread.deinit();
// True if this surface is hosting devmode. We only host devmode on
// the first surface since imgui is not threadsafe. We need to do some
// work to make DevMode work with multiple threads.
const host_devmode = DevMode.enabled and DevMode.instance.surface == null;
self.* = .{
.alloc = alloc,
.app_mailbox = app_mailbox,
@@ -440,7 +431,6 @@ pub fn init(
.visible = true,
},
.terminal = &self.io.terminal,
.devmode = if (!host_devmode) null else &DevMode.instance,
},
.renderer_thr = undefined,
.mouse = .{},
@@ -452,10 +442,7 @@ pub fn init(
.cell_size = cell_size,
.padding = padding,
.config = try DerivedConfig.init(alloc, config),
.imgui_ctx = if (!DevMode.enabled) {} else try imgui.Context.create(),
};
errdefer if (DevMode.enabled) self.imgui_ctx.destroy();
// Set a minimum size that is cols=10 h=4. This matches Mac's Terminal.app
// but is otherwise somewhat arbitrary.
@@ -471,30 +458,6 @@ pub fn init(
// to duplicate.
try self.sizeCallback(surface_size);
// Load imgui. This must be done LAST because it has to be done after
// all our GLFW setup is complete.
if (DevMode.enabled and DevMode.instance.surface == null) {
const dev_io = try imgui.IO.get();
dev_io.cval().IniFilename = "ghostty_dev_mode.ini";
// Add our built-in fonts so it looks slightly better
const dev_atlas: *imgui.FontAtlas = @ptrCast(dev_io.cval().Fonts);
dev_atlas.addFontFromMemoryTTF(
face_ttf,
@floatFromInt(font_size.pixels()),
);
// Default dark style
const style = try imgui.Style.get();
style.colorsDark();
// Add our surface to the instance if it isn't set.
DevMode.instance.surface = self;
// Let our renderer setup
try renderer_impl.initDevMode(rt_surface);
}
// Give the renderer one more opportunity to finalize any surface
// setup on the main thread prior to spinning up the rendering thread.
try renderer_impl.finalizeSurfaceInit(rt_surface);
@@ -525,18 +488,6 @@ pub fn deinit(self: *Surface) void {
// We need to become the active rendering thread again
self.renderer.threadEnter(self.rt_surface) catch unreachable;
// If we are devmode-owning, clean that up.
if (DevMode.enabled and DevMode.instance.surface == self) {
// Let our renderer clean up
self.renderer.deinitDevMode();
// Clear the surface
DevMode.instance.surface = null;
// Uninitialize imgui
self.imgui_ctx.destroy();
}
}
// Stop our IO thread
@@ -1113,17 +1064,6 @@ pub fn scrollCallback(
const tracy = trace(@src());
defer tracy.end();
// If our dev mode surface is visible then we always schedule a render on
// cursor move because the cursor might touch our surfaces.
if (DevMode.enabled and DevMode.instance.visible) {
try self.queueRender();
// If the mouse event was handled by imgui, ignore it.
if (imgui.IO.get()) |io| {
if (io.cval().WantCaptureMouse) return;
} else |_| {}
}
// log.info("SCROLL: xoff={} yoff={} mods={}", .{ xoff, yoff, scroll_mods });
const ScrollAmount = struct {
@@ -1473,17 +1413,6 @@ pub fn mouseButtonCallback(
const tracy = trace(@src());
defer tracy.end();
// If our dev mode surface is visible then we always schedule a render on
// cursor move because the cursor might touch our surfaces.
if (DevMode.enabled and DevMode.instance.visible) {
try self.queueRender();
// If the mouse event was handled by imgui, ignore it.
if (imgui.IO.get()) |io| {
if (io.cval().WantCaptureMouse) return;
} else |_| {}
}
// Always record our latest mouse state
self.mouse.click_state[@intCast(@intFromEnum(button))] = action;
self.mouse.mods = @bitCast(mods);
@@ -1636,17 +1565,6 @@ pub fn cursorPosCallback(
const tracy = trace(@src());
defer tracy.end();
// If our dev mode surface is visible then we always schedule a render on
// cursor move because the cursor might touch our surfaces.
if (DevMode.enabled and DevMode.instance.visible) {
try self.queueRender();
// If the mouse event was handled by imgui, ignore it.
if (imgui.IO.get()) |io| {
if (io.cval().WantCaptureMouse) return;
} else |_| {}
}
// We are reading/writing state for the remainder
self.renderer_state.mutex.lock();
defer self.renderer_state.mutex.unlock();
@@ -2113,11 +2031,6 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !void
try self.io_thread.wakeup.notify();
},
.toggle_dev_mode => if (DevMode.enabled) {
DevMode.instance.visible = !DevMode.instance.visible;
try self.queueRender();
} else log.warn("dev mode was not compiled into this binary", .{}),
.new_window => {
_ = self.app_mailbox.push(.{
.new_window = .{

View File

@@ -20,7 +20,6 @@ const apprt = @import("../apprt.zig");
const CoreApp = @import("../App.zig");
const CoreSurface = @import("../Surface.zig");
const Config = @import("../config.zig").Config;
const DevMode = @import("../DevMode.zig");
// Get native API access on certain platforms so we can do more customization.
const glfwNative = glfw.Native(.{
@@ -68,11 +67,6 @@ pub const App = struct {
var config = try Config.load(core_app.alloc);
errdefer config.deinit();
// If we have DevMode on, store the config so we can show it. This
// is messy because we're copying a thing here. We should clean this
// up when we take a pass at cleaning up the dev mode.
if (DevMode.enabled) DevMode.instance.config = config;
// Queue a single new window that starts on launch
_ = core_app.mailbox.push(.{
.new_window = .{},

View File

@@ -29,10 +29,6 @@ pub const font_backend: font.Backend = std.meta.stringToEnum(
@tagName(options.font_backend),
).?;
/// Whether our devmode UI is enabled or not. This requires imgui to be
/// compiled.
pub const devmode_enabled = artifact == .exe and app_runtime == .glfw;
/// We want to integrate with Flatpak APIs.
pub const flatpak = options.flatpak;

View File

@@ -365,13 +365,6 @@ pub const Config = struct {
.{ .reset_font_size = {} },
);
// Dev Mode
try result.keybind.set.put(
alloc,
.{ .key = .down, .mods = .{ .shift = true, .super = true } },
.{ .toggle_dev_mode = {} },
);
try result.keybind.set.put(
alloc,
.{ .key = .j, .mods = ctrlOrSuper(.{ .shift = true }) },

View File

@@ -201,9 +201,6 @@ pub const Action = union(enum) {
/// path to the file to the tty.
write_scrollback_file: void,
/// Dev mode
toggle_dev_mode: void,
/// Open a new window
new_window: void,

View File

@@ -16,7 +16,6 @@ const font = @import("../font/main.zig");
const terminal = @import("../terminal/main.zig");
const renderer = @import("../renderer.zig");
const math = @import("../math.zig");
const DevMode = @import("../DevMode.zig");
const Surface = @import("../Surface.zig");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
@@ -393,25 +392,6 @@ pub fn finalizeSurfaceInit(self: *const Metal, surface: *apprt.Surface) !void {
layer.setProperty("contentsScale", info.scaleFactor);
}
/// This is called if this renderer runs DevMode.
pub fn initDevMode(self: *const Metal, surface: *apprt.Surface) !void {
if (DevMode.enabled) {
// Initialize for our window
assert(imgui.ImplGlfw.initForOther(@ptrCast(surface.window.handle), true));
assert(imgui.ImplMetal.init(self.device.value));
}
}
/// This is called if this renderer runs DevMode.
pub fn deinitDevMode(self: *const Metal) void {
_ = self;
if (DevMode.enabled) {
imgui.ImplMetal.shutdown();
imgui.ImplGlfw.shutdown();
}
}
/// Callback called by renderer.Thread when it begins.
pub fn threadEnter(self: *const Metal, surface: *apprt.Surface) !void {
_ = self;
@@ -517,7 +497,6 @@ pub fn render(
// Data we extract out of the critical area.
const Critical = struct {
bg: terminal.color.RGB,
devmode: bool,
selection: ?terminal.Selection,
screen: terminal.Screen,
draw_cursor: bool,
@@ -596,7 +575,6 @@ pub fn render(
break :critical .{
.bg = self.config.background,
.devmode = if (state.devmode) |dm| dm.visible else false,
.selection = selection,
.screen = screen_copy,
.draw_cursor = draw_cursor,
@@ -715,29 +693,6 @@ pub fn render(
// Issue the draw calls for this shader
try self.drawCells(encoder, &self.buf_cells_bg, self.cells_bg);
try self.drawCells(encoder, &self.buf_cells, self.cells);
// Build our devmode draw data. This sucks because it requires we
// lock our state mutex but the metal imgui implementation requires
// access to all this stuff.
if (critical.devmode) {
state.mutex.lock();
defer state.mutex.unlock();
if (DevMode.enabled) {
if (state.devmode) |dm| {
if (dm.visible) {
imgui.ImplMetal.newFrame(desc.value);
imgui.ImplGlfw.newFrame();
try dm.update();
imgui.ImplMetal.renderDrawData(
try dm.render(),
buffer.value,
encoder.value,
);
}
}
}
}
}
buffer.msgSend(void, objc.sel("presentDrawable:"), .{drawable.value});

View File

@@ -18,7 +18,6 @@ const gl = @import("opengl/main.zig");
const trace = @import("tracy").trace;
const math = @import("../math.zig");
const lru = @import("../lru.zig");
const DevMode = @import("../DevMode.zig");
const Surface = @import("../Surface.zig");
const log = std.log.scoped(.grid);
@@ -540,30 +539,6 @@ pub fn finalizeSurfaceInit(self: *const OpenGL, surface: *apprt.Surface) !void {
}
}
/// This is called if this renderer runs DevMode.
pub fn initDevMode(self: *const OpenGL, surface: *apprt.Surface) !void {
_ = self;
if (DevMode.enabled) {
// Initialize for our window
assert(imgui.ImplGlfw.initForOpenGL(
@ptrCast(surface.window.handle),
true,
));
assert(imgui.ImplOpenGL3.init("#version 330 core"));
}
}
/// This is called if this renderer runs DevMode.
pub fn deinitDevMode(self: *const OpenGL) void {
_ = self;
if (DevMode.enabled) {
imgui.ImplOpenGL3.shutdown();
imgui.ImplGlfw.shutdown();
}
}
/// Callback called by renderer.Thread when it begins.
pub fn threadEnter(self: *const OpenGL, surface: *apprt.Surface) !void {
_ = self;
@@ -716,7 +691,6 @@ pub fn render(
// Data we extract out of the critical area.
const Critical = struct {
gl_bg: terminal.color.RGB,
devmode_data: ?*imgui.DrawData,
active_screen: terminal.Terminal.ScreenType,
selection: ?terminal.Selection,
screen: terminal.Screen,
@@ -769,22 +743,6 @@ pub fn render(
self.config.foreground = bg;
}
// Build our devmode draw data
const devmode_data = devmode_data: {
if (DevMode.enabled) {
if (state.devmode) |dm| {
if (dm.visible) {
imgui.ImplOpenGL3.newFrame();
imgui.ImplGlfw.newFrame();
try dm.update();
break :devmode_data try dm.render();
}
}
}
break :devmode_data null;
};
// We used to share terminal state, but we've since learned through
// analysis that it is faster to copy the terminal state than to
// hold the lock wile rebuilding GPU cells.
@@ -812,7 +770,6 @@ pub fn render(
break :critical .{
.gl_bg = self.config.background,
.devmode_data = devmode_data,
.active_screen = state.terminal.active_screen,
.selection = selection,
.screen = screen_copy,
@@ -847,13 +804,6 @@ pub fn render(
try self.draw();
// If we have devmode, then render that
if (DevMode.enabled) {
if (critical.devmode_data) |data| {
imgui.ImplOpenGL3.renderDrawData(data);
}
}
// Swap our window buffers
switch (apprt.runtime) {
else => @compileError("unsupported runtime"),

View File

@@ -2,7 +2,6 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const DevMode = @import("../DevMode.zig");
const terminal = @import("../terminal/main.zig");
const renderer = @import("../renderer.zig");
@@ -24,9 +23,6 @@ terminal: *terminal.Terminal,
/// a future exercise.
preedit: ?Preedit = null,
/// The devmode data.
devmode: ?*const DevMode = null,
pub const Cursor = struct {
/// Current cursor style. This can be set by escape sequences. To get
/// the default style, the config has to be referenced.