apprt/gtk: use adwaita helpers, move out some complicated logic

This commit is contained in:
Mitchell Hashimoto
2024-09-11 09:37:49 -07:00
parent 1ab850fa94
commit afc95fefe2
4 changed files with 83 additions and 63 deletions

View File

@ -21,8 +21,7 @@ const Config = configpkg.Config;
const CoreApp = @import("../../App.zig");
const CoreSurface = @import("../../Surface.zig");
const build_options = @import("build_options");
const adwaita = @import("adwaita.zig");
const cgroup = @import("cgroup.zig");
const Surface = @import("Surface.zig");
const Window = @import("Window.zig");
@ -143,8 +142,6 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
// Create our GTK Application which encapsulates our process.
const app: *c.GtkApplication = app: {
const adwaita = build_options.libadwaita and config.@"gtk-adwaita";
log.debug("creating GTK application id={s} single-instance={} adwaita={}", .{
app_id,
single_instance,
@ -152,10 +149,14 @@ pub fn init(core_app: *CoreApp, opts: Options) !App {
});
// If not libadwaita, create a standard GTK application.
if (!adwaita) break :app @as(?*c.GtkApplication, @ptrCast(c.gtk_application_new(
app_id.ptr,
app_flags,
))) orelse return error.GtkInitFailed;
if ((comptime adwaita.comptimeEnabled()) and
!adwaita.enabled(&config))
{
break :app @as(?*c.GtkApplication, @ptrCast(c.gtk_application_new(
app_id.ptr,
app_flags,
))) orelse return error.GtkInitFailed;
}
// Use libadwaita if requested. Using an AdwApplication lets us use
// Adwaita widgets and access things such as the color scheme.

View File

@ -8,7 +8,6 @@ const Window = @This();
const std = @import("std");
const builtin = @import("builtin");
const build_config = @import("../../build_config.zig");
const build_options = @import("build_options");
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
const configpkg = @import("../../config.zig");
@ -61,9 +60,10 @@ pub fn init(self: *Window, app: *App) !void {
};
// Create the window
const adw_window = adwaita.enabled(&app.config) and
const adw_window = (comptime adwaita.comptimeEnabled()) and
adwaita.enabled(&app.config) and
app.config.@"gtk-titlebar" and
comptime adwaita.versionAtLeast(1, 4, 0) and
(comptime adwaita.versionAtLeast(1, 4, 0)) and
adwaita.versionAtLeast(1, 4, 0);
const window: *c.GtkWidget = if (adw_window)
c.adw_application_window_new(app.app)
@ -127,8 +127,9 @@ pub fn init(self: *Window, app: *App) !void {
// This is a really common issue where people build from source in debug and performance is really bad.
if (comptime std.debug.runtime_safety) {
const warning_text = "⚠️ You're running a debug build of Ghostty! Performance will be degraded.";
if (adwaita.enabled(&app.config) and
comptime adwaita.versionAtLeast(1, 3, 0) and
if ((comptime adwaita.comptimeEnabled()) and
(comptime adwaita.versionAtLeast(1, 3, 0)) and
adwaita.enabled(&app.config) and
adwaita.versionAtLeast(1, 3, 0))
{
const banner = c.adw_banner_new(warning_text);
@ -160,11 +161,12 @@ pub fn init(self: *Window, app: *App) !void {
// Our actions for the menu
initActions(self);
if (adwaita.enabled(&app.config) and
if ((comptime adwaita.comptimeEnabled()) and
(comptime adwaita.versionAtLeast(1, 4, 0)) and
adwaita.enabled(&app.config) and
adwaita.versionAtLeast(1, 4, 0) and
app.config.@"gtk-titlebar" and
header != null and
comptime adwaita.versionAtLeast(1, 4, 0) and
adwaita.versionAtLeast(1, 4, 0))
header != null)
{
const toolbar_view: *c.AdwToolbarView = @ptrCast(c.adw_toolbar_view_new());

View File

@ -3,6 +3,11 @@ const c = @import("c.zig").c;
const build_options = @import("build_options");
const Config = @import("../../config.zig").Config;
/// Returns true if Ghostty is configured to build with libadwaita.
pub fn comptimeEnabled() bool {
return build_options.libadwaita;
}
/// Returns true if Ghostty is configured to build with libadwaita and
/// the configuration has enabled adwaita.
pub fn enabled(config: *const Config) bool {

View File

@ -1,50 +1,32 @@
const std = @import("std");
const assert = std.debug.assert;
const c = @import("c.zig").c;
const build_options = @import("build_options");
const Window = @import("./Window.zig");
const Tab = @import("./Tab.zig");
const Window = @import("Window.zig");
const Tab = @import("Tab.zig");
const adwaita = @import("adwaita.zig");
const log = std.log.scoped(.gtk);
const AdwTabView = if (build_options.libadwaita) c.AdwTabView else anyopaque;
const AdwTabView = if (adwaita.comptimeEnabled()) c.AdwTabView else anyopaque;
/// An abstraction over the GTK notebook and Adwaita tab view to manage
/// all the terminal tabs in a window.
pub const Notebook = union(enum) {
adw_tab_view: *AdwTabView,
gtk_notebook: *c.GtkNotebook,
pub fn create(window: *Window, box: *c.GtkWidget) @This() {
const app = window.app;
if (adwaita.enabled(&app.config)) return initAdw(window, box);
return initGtk(window, box);
}
const adwaita = build_options.libadwaita and app.config.@"gtk-adwaita";
if (adwaita) {
const tab_view = c.adw_tab_view_new().?;
c.gtk_box_append(@ptrCast(box), @ptrCast(@alignCast(tab_view)));
if (!window.app.config.@"gtk-titlebar" or c.ADW_MINOR_VERSION < 4) {
const tab_bar = c.adw_tab_bar_new();
switch (app.config.@"gtk-tabs-location") {
// left and right is not supported in libadwaita.
.top, .left, .right => c.gtk_box_prepend(@ptrCast(box), @ptrCast(@alignCast(tab_bar))),
.bottom => c.gtk_box_append(@ptrCast(box), @ptrCast(@alignCast(tab_bar))),
}
c.adw_tab_bar_set_view(tab_bar, tab_view);
if (!window.app.config.@"gtk-wide-tabs")
c.adw_tab_bar_set_expand_tabs(tab_bar, 0);
}
_ = c.g_signal_connect_data(tab_view, "page-attached", c.G_CALLBACK(&adwPageAttached), window, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(tab_view, "create-window", c.G_CALLBACK(&adwTabViewCreateWindow), window, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(tab_view, "notify::selected-page", c.G_CALLBACK(&adwSelectPage), window, null, c.G_CONNECT_DEFAULT);
return .{ .adw_tab_view = tab_view };
}
fn initGtk(window: *Window, box: *c.GtkWidget) Notebook {
const app = window.app;
// Create a notebook to hold our tabs.
const notebook_widget = c.gtk_notebook_new();
const notebook_widget: *c.GtkWidget = c.gtk_notebook_new();
const notebook: *c.GtkNotebook = @ptrCast(notebook_widget);
const notebook_tab_pos: c_uint = switch (app.config.@"gtk-tabs-location") {
.top => c.GTK_POS_TOP,
@ -75,44 +57,74 @@ pub const Notebook = union(enum) {
return .{ .gtk_notebook = notebook };
}
pub fn asWidget(self: Notebook) *c.GtkWidget {
return switch (self) {
.adw_tab_view => |ptr| @ptrCast(@alignCast(ptr)),
.gtk_notebook => |ptr| @ptrCast(@alignCast(ptr)),
};
fn initAdw(window: *Window, box: *c.GtkWidget) Notebook {
const app = window.app;
assert(adwaita.enabled(&app.config));
const tab_view: *c.AdwTabView = c.adw_tab_view_new().?;
c.gtk_box_append(@ptrCast(box), @ptrCast(@alignCast(tab_view)));
if (comptime !adwaita.versionAtLeast(1, 4, 0) or
!adwaita.versionAtLeast(1, 4, 0) or
!app.config.@"gtk-titlebar")
{
const tab_bar: *c.AdwTabBar = c.adw_tab_bar_new().?;
switch (app.config.@"gtk-tabs-location") {
// left and right is not supported in libadwaita.
.top,
.left,
.right,
=> c.gtk_box_prepend(@ptrCast(box), @ptrCast(@alignCast(tab_bar))),
.bottom => c.gtk_box_append(@ptrCast(box), @ptrCast(@alignCast(tab_bar))),
}
c.adw_tab_bar_set_view(tab_bar, tab_view);
if (!app.config.@"gtk-wide-tabs") {
c.adw_tab_bar_set_expand_tabs(tab_bar, 0);
}
}
_ = c.g_signal_connect_data(tab_view, "page-attached", c.G_CALLBACK(&adwPageAttached), window, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(tab_view, "create-window", c.G_CALLBACK(&adwTabViewCreateWindow), window, null, c.G_CONNECT_DEFAULT);
_ = c.g_signal_connect_data(tab_view, "notify::selected-page", c.G_CALLBACK(&adwSelectPage), window, null, c.G_CONNECT_DEFAULT);
return .{ .adw_tab_view = tab_view };
}
pub fn nPages(self: Notebook) c_int {
return switch (self) {
.adw_tab_view => |tab_view| if (build_options.libadwaita) c.adw_tab_view_get_n_pages(tab_view) else unreachable,
.gtk_notebook => |notebook| c.gtk_notebook_get_n_pages(notebook),
.adw_tab_view => |tab_view| if (comptime adwaita.comptimeEnabled())
c.adw_tab_view_get_n_pages(tab_view)
else
unreachable,
};
}
pub fn currentPage(self: Notebook) c_int {
switch (self) {
.adw_tab_view => |tab_view| {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page = c.adw_tab_view_get_selected_page(tab_view);
return c.adw_tab_view_get_page_position(tab_view, page);
},
.gtk_notebook => |notebook| return c.gtk_notebook_get_current_page(notebook),
}
}
pub fn currentTab(self: Notebook) ?*Tab {
log.info("self = {}", .{self});
const child = switch (self) {
.adw_tab_view => |tab_view| child: {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page = c.adw_tab_view_get_selected_page(tab_view) orelse return null;
const child = c.adw_tab_page_get_child(page);
break :child child;
},
.gtk_notebook => |notebook| child: {
const page = self.currentPage();
if (page == -1) return null;
log.info("currentPage_page_idx = {}", .{page});
break :child c.gtk_notebook_get_nth_page(notebook, page);
},
};
@ -124,7 +136,7 @@ pub const Notebook = union(enum) {
pub fn gotoNthTab(self: Notebook, position: c_int) void {
switch (self) {
.adw_tab_view => |tab_view| {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page_to_select = c.adw_tab_view_get_nth_page(tab_view, position);
c.adw_tab_view_set_selected_page(tab_view, page_to_select);
},
@ -135,7 +147,7 @@ pub const Notebook = union(enum) {
pub fn getTabPosition(self: Notebook, tab: *Tab) ?c_int {
return switch (self) {
.adw_tab_view => |tab_view| page_idx: {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page = c.adw_tab_view_get_page(tab_view, @ptrCast(tab.box)) orelse return null;
break :page_idx c.adw_tab_view_get_page_position(tab_view, page);
},
@ -174,7 +186,7 @@ pub const Notebook = union(enum) {
pub fn setTabLabel(self: Notebook, tab: *Tab, title: [:0]const u8) void {
switch (self) {
.adw_tab_view => |tab_view| {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page = c.adw_tab_view_get_page(tab_view, @ptrCast(tab.box));
c.adw_tab_page_set_title(page, title.ptr);
},
@ -186,7 +198,7 @@ pub const Notebook = union(enum) {
const box_widget: *c.GtkWidget = @ptrCast(tab.box);
switch (self) {
.adw_tab_view => |tab_view| {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page = c.adw_tab_view_append(tab_view, box_widget);
c.adw_tab_page_set_title(page, title.ptr);
@ -257,7 +269,7 @@ pub const Notebook = union(enum) {
const window = tab.window;
switch (self) {
.adw_tab_view => |tab_view| {
if (!build_options.libadwaita) unreachable;
if (comptime !adwaita.comptimeEnabled()) unreachable;
const page = c.adw_tab_view_get_page(tab_view, @ptrCast(tab.box)) orelse return;
c.adw_tab_view_close_page(tab_view, page);