apprt/gtk: empty inspector window

This commit is contained in:
Mitchell Hashimoto
2023-10-18 08:41:33 -07:00
parent 4b1809f35e
commit a60f9eb9e6
5 changed files with 134 additions and 24 deletions

View File

@ -6,5 +6,6 @@ pub const Surface = @import("gtk/Surface.zig");
test {
@import("std").testing.refAllDecls(@This());
_ = @import("gtk/inspector.zig");
_ = @import("gtk/key.zig");
}

View File

@ -25,6 +25,7 @@ const Surface = @import("Surface.zig");
const Window = @import("Window.zig");
const ConfigErrorsWindow = @import("ConfigErrorsWindow.zig");
const c = @import("c.zig");
const inspector = @import("inspector.zig");
const key = @import("key.zig");
const log = std.log.scoped(.gtk);
@ -262,6 +263,12 @@ 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);

View File

@ -12,6 +12,7 @@ const CoreSurface = @import("../../Surface.zig");
const App = @import("App.zig");
const Surface = @import("Surface.zig");
const icon = @import("icon.zig");
const c = @import("c.zig");
const log = std.log.scoped(.gtk);
@ -28,7 +29,7 @@ notebook: *c.GtkNotebook,
/// The resources directory for the icon (if any). We need to retain a
/// pointer to this because GTK can use it at any time.
icon_search_dir: ?[:0]const u8 = null,
icon: icon.Icon,
pub fn create(alloc: Allocator, app: *App) !*Window {
// Allocate a fixed pointer for our window. We try to minimize
@ -48,6 +49,7 @@ pub fn init(self: *Window, app: *App) !void {
// Set up our own state
self.* = .{
.app = app,
.icon = undefined,
.window = undefined,
.notebook = undefined,
};
@ -62,28 +64,8 @@ pub fn init(self: *Window, app: *App) !void {
// If we don't have the icon then we'll try to add our resources dir
// to the search path and see if we can find it there.
const icon_name = "com.mitchellh.ghostty";
const icon_theme = c.gtk_icon_theme_get_for_display(c.gtk_widget_get_display(window));
if (c.gtk_icon_theme_has_icon(icon_theme, icon_name) == 0) icon: {
const base = self.app.core_app.resources_dir orelse {
log.info("gtk app missing Ghostty icon and no resources dir detected", .{});
log.info("gtk app will not have Ghostty icon", .{});
break :icon;
};
// Note that this method for adding the icon search path is
// a fallback mechanism. The recommended mechanism is the
// Freedesktop Icon Theme Specification. We distribute a ".desktop"
// file in zig-out/share that should be installed to the proper
// place.
const dir = try std.fmt.allocPrintZ(app.core_app.alloc, "{s}/icons", .{base});
self.icon_search_dir = dir;
c.gtk_icon_theme_add_search_path(icon_theme, dir.ptr);
if (c.gtk_icon_theme_has_icon(icon_theme, icon_name) == 0) {
log.warn("Ghostty icon for gtk app not found", .{});
}
}
c.gtk_window_set_icon_name(gtk_window, icon_name);
self.icon = try icon.appIcon(self.app, window);
c.gtk_window_set_icon_name(gtk_window, self.icon.name);
// Apply background opacity if we have it
if (app.config.@"background-opacity" < 1) {
@ -185,7 +167,7 @@ fn initActions(self: *Window) void {
}
pub fn deinit(self: *Window) void {
if (self.icon_search_dir) |ptr| self.app.core_app.alloc.free(ptr);
self.icon.deinit(self.app);
}
/// Add a new tab to this window.

52
src/apprt/gtk/icon.zig Normal file
View File

@ -0,0 +1,52 @@
const std = @import("std");
const App = @import("App.zig");
const c = @import("c.zig");
const log = std.log.scoped(.gtk_icon);
/// An icon. The icon may be associated with some allocated state so when
/// the icon is no longer in use it should be deinitialized.
pub const Icon = struct {
name: [:0]const u8,
state: ?[:0]const u8 = null,
pub fn deinit(self: *const Icon, app: *App) void {
if (self.state) |v| app.core_app.alloc.free(v);
}
};
/// Returns the application icon that can be used anywhere. This attempts to
/// find the icon in the theme and if it can't be found, it is loaded from
/// the resources dir. If the resources dir can't be found, we'll log a warning
/// and let GTK choose a fallback.
pub fn appIcon(app: *App, widget: *c.GtkWidget) !Icon {
const icon_name = "com.mitchellh.ghostty";
var result: Icon = .{ .name = icon_name };
// If we don't have the icon then we'll try to add our resources dir
// to the search path and see if we can find it there.
const icon_theme = c.gtk_icon_theme_get_for_display(c.gtk_widget_get_display(widget));
if (c.gtk_icon_theme_has_icon(icon_theme, icon_name) == 0) icon: {
const base = app.core_app.resources_dir orelse {
log.info("gtk app missing Ghostty icon and no resources dir detected", .{});
log.info("gtk app will not have Ghostty icon", .{});
break :icon;
};
// Note that this method for adding the icon search path is
// a fallback mechanism. The recommended mechanism is the
// Freedesktop Icon Theme Specification. We distribute a ".desktop"
// file in zig-out/share that should be installed to the proper
// place.
const dir = try std.fmt.allocPrintZ(app.core_app.alloc, "{s}/icons", .{base});
errdefer app.core_app.alloc.free(dir);
result.state = dir;
c.gtk_icon_theme_add_search_path(icon_theme, dir.ptr);
if (c.gtk_icon_theme_has_icon(icon_theme, icon_name) == 0) {
log.warn("Ghostty icon for gtk app not found", .{});
}
}
return result;
}

View File

@ -0,0 +1,68 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const App = @import("App.zig");
const TerminalWindow = @import("Window.zig");
const c = @import("c.zig");
const icon = @import("icon.zig");
const log = std.log.scoped(.inspector);
/// A window to hold a dedicated inspector instance.
pub const Window = struct {
/// Our app
app: *App,
/// Our window
window: *c.GtkWindow,
/// The window icon
icon: icon.Icon,
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 {
// Initialize to undefined
self.* = .{
.app = app,
.icon = undefined,
.window = undefined,
};
// Create the window
const window = c.gtk_application_window_new(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);
c.gtk_window_set_icon_name(gtk_window, self.icon.name);
// Signals
_ = c.g_signal_connect_data(window, "destroy", c.G_CALLBACK(&gtkDestroy), self, null, c.G_CONNECT_DEFAULT);
// Show the window
c.gtk_widget_show(window);
}
pub fn deinit(self: *Window) void {
self.icon.deinit(self.app);
}
/// "destroy" signal for the window
fn gtkDestroy(v: *c.GtkWidget, ud: ?*anyopaque) callconv(.C) void {
_ = v;
log.debug("window destroy", .{});
const self: *Window = @ptrCast(@alignCast(ud.?));
const alloc = self.app.core_app.alloc;
self.deinit();
alloc.destroy(self);
}
};