mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
apprt/gtk: surface has inspector state
This commit is contained in:
@ -263,12 +263,6 @@ pub fn run(self: *App) !void {
|
||||
log.warn("error handling configuration changes err={}", .{err});
|
||||
};
|
||||
|
||||
// TODO: temporary, remove: show our inspector window
|
||||
{
|
||||
const win = try inspector.Window.create(self.core_app.alloc, self);
|
||||
_ = win;
|
||||
}
|
||||
|
||||
while (self.running) {
|
||||
_ = c.g_main_context_iteration(self.ctx, 1);
|
||||
|
||||
|
@ -14,6 +14,7 @@ const CoreSurface = @import("../../Surface.zig");
|
||||
|
||||
const App = @import("App.zig");
|
||||
const Window = @import("Window.zig");
|
||||
const inspector = @import("inspector.zig");
|
||||
const c = @import("c.zig");
|
||||
|
||||
const log = std.log.scoped(.gtk);
|
||||
@ -76,6 +77,9 @@ font_size: ?font.face.DesiredSize = null,
|
||||
size: apprt.SurfaceSize,
|
||||
cursor_pos: apprt.CursorPos,
|
||||
|
||||
/// Inspector state.
|
||||
inspector: ?*inspector.Inspector = null,
|
||||
|
||||
/// Key input states. See gtkKeyPressed for detailed descriptions.
|
||||
in_keypress: bool = false,
|
||||
im_context: *c.GtkIMContext,
|
||||
@ -218,6 +222,9 @@ pub fn deinit(self: *Surface) void {
|
||||
// We don't allocate anything if we aren't realized.
|
||||
if (!self.realized) return;
|
||||
|
||||
// Delete our inspector if we have one
|
||||
self.controlInspector(.hide);
|
||||
|
||||
// Remove ourselves from the list of known surfaces in the app.
|
||||
self.app.core_app.deleteSurface(self);
|
||||
|
||||
@ -281,6 +288,33 @@ pub fn close(self: *Surface, processActive: bool) void {
|
||||
c.gtk_widget_show(alert);
|
||||
}
|
||||
|
||||
pub fn controlInspector(self: *Surface, mode: input.InspectorMode) void {
|
||||
const show = switch (mode) {
|
||||
.toggle => self.inspector == null,
|
||||
.show => true,
|
||||
.hide => false,
|
||||
};
|
||||
|
||||
if (!show) {
|
||||
if (self.inspector) |v| {
|
||||
v.close(true);
|
||||
self.inspector = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we already have an inspector, we don't need to show anything.
|
||||
if (self.inspector != null) return;
|
||||
self.inspector = inspector.Inspector.create(
|
||||
self,
|
||||
.{ .window = {} },
|
||||
) catch |err| {
|
||||
log.err("failed to control inspector err={}", .{err});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn toggleFullscreen(self: *Surface, mac_non_native: configpkg.NonNativeFullscreen) void {
|
||||
self.window.toggleFullscreen(mac_non_native);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
const App = @import("App.zig");
|
||||
const Surface = @import("Surface.zig");
|
||||
const TerminalWindow = @import("Window.zig");
|
||||
const ImguiWidget = @import("ImguiWidget.zig");
|
||||
const c = @import("c.zig");
|
||||
@ -9,37 +11,127 @@ const icon = @import("icon.zig");
|
||||
|
||||
const log = std.log.scoped(.inspector);
|
||||
|
||||
/// A window to hold a dedicated inspector instance.
|
||||
pub const Window = struct {
|
||||
app: *App,
|
||||
/// Inspector is the primary stateful object that represents a terminal
|
||||
/// inspector. An inspector is 1:1 with a Surface and is owned by a Surface.
|
||||
/// Closing a surface must close its inspector.
|
||||
pub const Inspector = struct {
|
||||
/// The surface that owns this inspector.
|
||||
surface: *Surface,
|
||||
|
||||
/// The current state of where this inspector is rendered. The Inspector
|
||||
/// is the state of the inspector but this is the state of the GUI.
|
||||
location: LocationState,
|
||||
|
||||
/// This is true if we want to destroy this inspector as soon as the
|
||||
/// location is closed. For example: set this to true, request the
|
||||
/// window be closed, let GTK do its cleanup, then note this to destroy
|
||||
/// the inner state.
|
||||
request_destroy: bool = false,
|
||||
|
||||
/// Location where the inspector will be launched.
|
||||
pub const Location = union(LocationKey) {
|
||||
hidden: void,
|
||||
window: void,
|
||||
};
|
||||
|
||||
/// The internal state for each possible location.
|
||||
const LocationState = union(LocationKey) {
|
||||
hidden: void,
|
||||
window: Window,
|
||||
};
|
||||
|
||||
const LocationKey = enum {
|
||||
/// No GUI, but load the inspector state.
|
||||
hidden,
|
||||
|
||||
/// A dedicated window for the inspector.
|
||||
window,
|
||||
};
|
||||
|
||||
/// Create an inspector for the given surface in the given location.
|
||||
pub fn create(surface: *Surface, location: Location) !*Inspector {
|
||||
const alloc = surface.app.core_app.alloc;
|
||||
var ptr = try alloc.create(Inspector);
|
||||
errdefer alloc.destroy(ptr);
|
||||
try ptr.init(surface, location);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/// Destroy all memory associated with this inspector. You generally
|
||||
/// should NOT call this publicly and should call `close` instead to
|
||||
/// use the GTK lifecycle.
|
||||
pub fn destroy(self: *Inspector) void {
|
||||
assert(self.location == .hidden);
|
||||
const alloc = self.allocator();
|
||||
self.deinit();
|
||||
alloc.destroy(self);
|
||||
}
|
||||
|
||||
fn init(self: *Inspector, surface: *Surface, location: Location) !void {
|
||||
self.* = .{
|
||||
.surface = surface,
|
||||
.location = undefined,
|
||||
};
|
||||
|
||||
switch (location) {
|
||||
.hidden => self.location = .{ .hidden = {} },
|
||||
.window => try self.initWindow(),
|
||||
}
|
||||
}
|
||||
|
||||
fn deinit(self: *Inspector) void {
|
||||
_ = self;
|
||||
}
|
||||
|
||||
/// Request the inspector is closed. If request_destroy is true, also
|
||||
/// destroy the inspector state when the GUI is closed.
|
||||
pub fn close(self: *Inspector, request_destroy: bool) void {
|
||||
self.request_destroy = request_destroy;
|
||||
switch (self.location) {
|
||||
.hidden => self.locationDidClose(),
|
||||
.window => |v| v.close(),
|
||||
}
|
||||
}
|
||||
|
||||
fn locationDidClose(self: *Inspector) void {
|
||||
self.location = .{ .hidden = {} };
|
||||
if (self.request_destroy) self.destroy();
|
||||
}
|
||||
|
||||
fn allocator(self: *const Inspector) Allocator {
|
||||
return self.surface.app.core_app.alloc;
|
||||
}
|
||||
|
||||
fn initWindow(self: *Inspector) !void {
|
||||
self.location = .{ .window = undefined };
|
||||
try self.location.window.init(self);
|
||||
}
|
||||
};
|
||||
|
||||
/// A dedicated window to hold an inspector instance.
|
||||
const Window = struct {
|
||||
inspector: *Inspector,
|
||||
window: *c.GtkWindow,
|
||||
icon: icon.Icon,
|
||||
imgui_widget: ImguiWidget,
|
||||
|
||||
pub fn create(alloc: Allocator, app: *App) !*Window {
|
||||
var window = try alloc.create(Window);
|
||||
errdefer alloc.destroy(window);
|
||||
try window.init(app);
|
||||
return window;
|
||||
}
|
||||
|
||||
pub fn init(self: *Window, app: *App) !void {
|
||||
pub fn init(self: *Window, inspector: *Inspector) !void {
|
||||
// Initialize to undefined
|
||||
self.* = .{
|
||||
.app = app,
|
||||
.inspector = inspector,
|
||||
.icon = undefined,
|
||||
.window = undefined,
|
||||
.imgui_widget = undefined,
|
||||
};
|
||||
|
||||
// Create the window
|
||||
const window = c.gtk_application_window_new(app.app);
|
||||
const window = c.gtk_application_window_new(inspector.surface.app.app);
|
||||
const gtk_window: *c.GtkWindow = @ptrCast(window);
|
||||
errdefer c.gtk_window_destroy(gtk_window);
|
||||
self.window = gtk_window;
|
||||
c.gtk_window_set_title(gtk_window, "Ghostty");
|
||||
c.gtk_window_set_default_size(gtk_window, 1000, 600);
|
||||
self.icon = try icon.appIcon(self.app, window);
|
||||
self.icon = try icon.appIcon(self.inspector.surface.app, window);
|
||||
c.gtk_window_set_icon_name(gtk_window, self.icon.name);
|
||||
|
||||
// Initialize our imgui widget
|
||||
@ -55,7 +147,12 @@ pub const Window = struct {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Window) void {
|
||||
self.icon.deinit(self.app);
|
||||
self.icon.deinit(self.inspector.surface.app);
|
||||
self.inspector.locationDidClose();
|
||||
}
|
||||
|
||||
pub fn close(self: *const Window) void {
|
||||
c.gtk_window_destroy(self.window);
|
||||
}
|
||||
|
||||
/// "destroy" signal for the window
|
||||
@ -64,8 +161,6 @@ pub const Window = struct {
|
||||
log.debug("window destroy", .{});
|
||||
|
||||
const self: *Window = @ptrCast(@alignCast(ud.?));
|
||||
const alloc = self.app.core_app.alloc;
|
||||
self.deinit();
|
||||
alloc.destroy(self);
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user