apprt/gtk: abstract AdwHeaderBar and GtkHeaderBar (#2749)

This will make further changes a little bit more readable.
This commit is contained in:
Mitchell Hashimoto
2024-12-15 14:05:03 -08:00
committed by GitHub
2 changed files with 78 additions and 17 deletions

View File

@ -23,6 +23,7 @@ const c = @import("c.zig").c;
const adwaita = @import("adwaita.zig"); const adwaita = @import("adwaita.zig");
const gtk_key = @import("key.zig"); const gtk_key = @import("key.zig");
const Notebook = @import("notebook.zig").Notebook; const Notebook = @import("notebook.zig").Notebook;
const HeaderBar = @import("headerbar.zig").HeaderBar;
const version = @import("version.zig"); const version = @import("version.zig");
const log = std.log.scoped(.gtk); const log = std.log.scoped(.gtk);
@ -35,7 +36,7 @@ window: *c.GtkWindow,
/// The header bar for the window. This is possibly null since it can be /// The header bar for the window. This is possibly null since it can be
/// disabled using gtk-titlebar. This is either an AdwHeaderBar or /// disabled using gtk-titlebar. This is either an AdwHeaderBar or
/// GtkHeaderBar depending on if adw is enabled and linked. /// GtkHeaderBar depending on if adw is enabled and linked.
header: ?*c.GtkWidget, header: ?HeaderBar,
/// The tab overview for the window. This is possibly null since there is no /// The tab overview for the window. This is possibly null since there is no
/// taboverview without a AdwApplicationWindow (libadwaita >= 1.4.0). /// taboverview without a AdwApplicationWindow (libadwaita >= 1.4.0).
@ -153,20 +154,14 @@ pub fn init(self: *Window, app: *App) !void {
// are decorated or not because we can have a keybind to toggle the // are decorated or not because we can have a keybind to toggle the
// decorations. // decorations.
if (app.config.@"gtk-titlebar") { if (app.config.@"gtk-titlebar") {
const header: *c.GtkWidget = if (self.isAdwWindow()) const header = HeaderBar.init(self);
@ptrCast(c.adw_header_bar_new())
else
@ptrCast(c.gtk_header_bar_new());
{ {
const btn = c.gtk_menu_button_new(); const btn = c.gtk_menu_button_new();
c.gtk_widget_set_tooltip_text(btn, "Main Menu"); c.gtk_widget_set_tooltip_text(btn, "Main Menu");
c.gtk_menu_button_set_icon_name(@ptrCast(btn), "open-menu-symbolic"); c.gtk_menu_button_set_icon_name(@ptrCast(btn), "open-menu-symbolic");
c.gtk_menu_button_set_menu_model(@ptrCast(btn), @ptrCast(@alignCast(app.menu))); c.gtk_menu_button_set_menu_model(@ptrCast(btn), @ptrCast(@alignCast(app.menu)));
if (self.isAdwWindow()) { header.packEnd(btn);
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
c.adw_header_bar_pack_end(@ptrCast(header), btn);
} else c.gtk_header_bar_pack_end(@ptrCast(header), btn);
} }
// If we're using an AdwWindow then we can support the tab overview. // If we're using an AdwWindow then we can support the tab overview.
@ -198,17 +193,14 @@ pub fn init(self: *Window, app: *App) !void {
}; };
c.gtk_widget_set_focus_on_click(btn, c.FALSE); c.gtk_widget_set_focus_on_click(btn, c.FALSE);
c.adw_header_bar_pack_end(@ptrCast(header), btn); header.packEnd(btn);
} }
{ {
const btn = c.gtk_button_new_from_icon_name("tab-new-symbolic"); const btn = c.gtk_button_new_from_icon_name("tab-new-symbolic");
c.gtk_widget_set_tooltip_text(btn, "New Tab"); c.gtk_widget_set_tooltip_text(btn, "New Tab");
_ = c.g_signal_connect_data(btn, "clicked", c.G_CALLBACK(&gtkTabNewClick), self, null, c.G_CONNECT_DEFAULT); _ = c.g_signal_connect_data(btn, "clicked", c.G_CALLBACK(&gtkTabNewClick), self, null, c.G_CONNECT_DEFAULT);
if (self.isAdwWindow()) header.packEnd(btn);
c.adw_header_bar_pack_end(@ptrCast(header), btn)
else
c.gtk_header_bar_pack_end(@ptrCast(header), btn);
} }
self.header = header; self.header = header;
@ -291,7 +283,7 @@ pub fn init(self: *Window, app: *App) !void {
if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable; if (comptime !adwaita.versionAtLeast(1, 4, 0)) unreachable;
const toolbar_view: *c.AdwToolbarView = @ptrCast(c.adw_toolbar_view_new()); const toolbar_view: *c.AdwToolbarView = @ptrCast(c.adw_toolbar_view_new());
const header_widget: *c.GtkWidget = @ptrCast(@alignCast(self.header.?)); const header_widget: *c.GtkWidget = self.header.?.asWidget();
c.adw_toolbar_view_add_top_bar(toolbar_view, header_widget); c.adw_toolbar_view_add_top_bar(toolbar_view, header_widget);
if (self.app.config.@"gtk-tabs-location" != .hidden) { if (self.app.config.@"gtk-tabs-location" != .hidden) {
@ -374,7 +366,7 @@ pub fn init(self: *Window, app: *App) !void {
// The box is our main child // The box is our main child
c.gtk_window_set_child(gtk_window, box); c.gtk_window_set_child(gtk_window, box);
if (self.header) |h| c.gtk_window_set_titlebar(gtk_window, @ptrCast(@alignCast(h))); if (self.header) |h| c.gtk_window_set_titlebar(gtk_window, h.asWidget());
} }
// Show the window // Show the window
@ -525,7 +517,7 @@ pub fn toggleWindowDecorations(self: *Window) void {
// and hides it with decorations, but libadwaita doesn't. This makes it // and hides it with decorations, but libadwaita doesn't. This makes it
// explicit. // explicit.
if (self.header) |v| { if (self.header) |v| {
const widget: *c.GtkWidget = @alignCast(@ptrCast(v)); const widget = v.asWidget();
c.gtk_widget_set_visible(widget, @intFromBool(new_decorated)); c.gtk_widget_set_visible(widget, @intFromBool(new_decorated));
} }
} }

View File

@ -0,0 +1,69 @@
const std = @import("std");
const c = @import("c.zig").c;
const Window = @import("Window.zig");
const adwaita = @import("adwaita.zig");
const AdwHeaderBar = if (adwaita.versionAtLeast(0, 0, 0)) c.AdwHeaderBar else void;
pub const HeaderBar = union(enum) {
adw: *AdwHeaderBar,
gtk: *c.GtkHeaderBar,
pub fn init(window: *Window) HeaderBar {
if ((comptime adwaita.versionAtLeast(1, 4, 0)) and
adwaita.enabled(&window.app.config))
{
return initAdw();
}
return initGtk();
}
fn initAdw() HeaderBar {
const headerbar = c.adw_header_bar_new();
return .{ .adw = @ptrCast(headerbar) };
}
fn initGtk() HeaderBar {
const headerbar = c.gtk_header_bar_new();
return .{ .gtk = @ptrCast(headerbar) };
}
pub fn asWidget(self: HeaderBar) *c.GtkWidget {
return switch (self) {
.adw => |headerbar| @ptrCast(@alignCast(headerbar)),
.gtk => |headerbar| @ptrCast(@alignCast(headerbar)),
};
}
pub fn packEnd(self: HeaderBar, widget: *c.GtkWidget) void {
switch (self) {
.adw => |headerbar| if (comptime adwaita.versionAtLeast(0, 0, 0)) {
c.adw_header_bar_pack_end(
@ptrCast(@alignCast(headerbar)),
widget,
);
},
.gtk => |headerbar| c.gtk_header_bar_pack_end(
@ptrCast(@alignCast(headerbar)),
widget,
),
}
}
pub fn packStart(self: HeaderBar, widget: *c.GtkWidget) void {
switch (self) {
.adw => |headerbar| if (comptime adwaita.versionAtLeast(0, 0, 0)) {
c.adw_header_bar_pack_start(
@ptrCast(@alignCast(headerbar)),
widget,
);
},
.gtk => |headerbar| c.gtk_header_bar_pack_start(
@ptrCast(@alignCast(headerbar)),
widget,
),
}
}
};