mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +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});
|
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) {
|
while (self.running) {
|
||||||
_ = c.g_main_context_iteration(self.ctx, 1);
|
_ = c.g_main_context_iteration(self.ctx, 1);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ const CoreSurface = @import("../../Surface.zig");
|
|||||||
|
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
const Window = @import("Window.zig");
|
const Window = @import("Window.zig");
|
||||||
|
const inspector = @import("inspector.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.gtk);
|
const log = std.log.scoped(.gtk);
|
||||||
@ -76,6 +77,9 @@ font_size: ?font.face.DesiredSize = null,
|
|||||||
size: apprt.SurfaceSize,
|
size: apprt.SurfaceSize,
|
||||||
cursor_pos: apprt.CursorPos,
|
cursor_pos: apprt.CursorPos,
|
||||||
|
|
||||||
|
/// Inspector state.
|
||||||
|
inspector: ?*inspector.Inspector = null,
|
||||||
|
|
||||||
/// Key input states. See gtkKeyPressed for detailed descriptions.
|
/// Key input states. See gtkKeyPressed for detailed descriptions.
|
||||||
in_keypress: bool = false,
|
in_keypress: bool = false,
|
||||||
im_context: *c.GtkIMContext,
|
im_context: *c.GtkIMContext,
|
||||||
@ -218,6 +222,9 @@ pub fn deinit(self: *Surface) void {
|
|||||||
// We don't allocate anything if we aren't realized.
|
// We don't allocate anything if we aren't realized.
|
||||||
if (!self.realized) return;
|
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.
|
// Remove ourselves from the list of known surfaces in the app.
|
||||||
self.app.core_app.deleteSurface(self);
|
self.app.core_app.deleteSurface(self);
|
||||||
|
|
||||||
@ -281,6 +288,33 @@ pub fn close(self: *Surface, processActive: bool) void {
|
|||||||
c.gtk_widget_show(alert);
|
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 {
|
pub fn toggleFullscreen(self: *Surface, mac_non_native: configpkg.NonNativeFullscreen) void {
|
||||||
self.window.toggleFullscreen(mac_non_native);
|
self.window.toggleFullscreen(mac_non_native);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
const App = @import("App.zig");
|
const App = @import("App.zig");
|
||||||
|
const Surface = @import("Surface.zig");
|
||||||
const TerminalWindow = @import("Window.zig");
|
const TerminalWindow = @import("Window.zig");
|
||||||
const ImguiWidget = @import("ImguiWidget.zig");
|
const ImguiWidget = @import("ImguiWidget.zig");
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
@ -9,37 +11,127 @@ const icon = @import("icon.zig");
|
|||||||
|
|
||||||
const log = std.log.scoped(.inspector);
|
const log = std.log.scoped(.inspector);
|
||||||
|
|
||||||
/// A window to hold a dedicated inspector instance.
|
/// Inspector is the primary stateful object that represents a terminal
|
||||||
pub const Window = struct {
|
/// inspector. An inspector is 1:1 with a Surface and is owned by a Surface.
|
||||||
app: *App,
|
/// 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,
|
window: *c.GtkWindow,
|
||||||
icon: icon.Icon,
|
icon: icon.Icon,
|
||||||
imgui_widget: ImguiWidget,
|
imgui_widget: ImguiWidget,
|
||||||
|
|
||||||
pub fn create(alloc: Allocator, app: *App) !*Window {
|
pub fn init(self: *Window, inspector: *Inspector) !void {
|
||||||
var window = try alloc.create(Window);
|
|
||||||
errdefer alloc.destroy(window);
|
|
||||||
try window.init(app);
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(self: *Window, app: *App) !void {
|
|
||||||
// Initialize to undefined
|
// Initialize to undefined
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.app = app,
|
.inspector = inspector,
|
||||||
.icon = undefined,
|
.icon = undefined,
|
||||||
.window = undefined,
|
.window = undefined,
|
||||||
.imgui_widget = undefined,
|
.imgui_widget = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the window
|
// 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);
|
const gtk_window: *c.GtkWindow = @ptrCast(window);
|
||||||
errdefer c.gtk_window_destroy(gtk_window);
|
errdefer c.gtk_window_destroy(gtk_window);
|
||||||
self.window = gtk_window;
|
self.window = gtk_window;
|
||||||
c.gtk_window_set_title(gtk_window, "Ghostty");
|
c.gtk_window_set_title(gtk_window, "Ghostty");
|
||||||
c.gtk_window_set_default_size(gtk_window, 1000, 600);
|
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);
|
c.gtk_window_set_icon_name(gtk_window, self.icon.name);
|
||||||
|
|
||||||
// Initialize our imgui widget
|
// Initialize our imgui widget
|
||||||
@ -55,7 +147,12 @@ pub const Window = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Window) void {
|
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
|
/// "destroy" signal for the window
|
||||||
@ -64,8 +161,6 @@ pub const Window = struct {
|
|||||||
log.debug("window destroy", .{});
|
log.debug("window destroy", .{});
|
||||||
|
|
||||||
const self: *Window = @ptrCast(@alignCast(ud.?));
|
const self: *Window = @ptrCast(@alignCast(ud.?));
|
||||||
const alloc = self.app.core_app.alloc;
|
|
||||||
self.deinit();
|
self.deinit();
|
||||||
alloc.destroy(self);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user