mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
apprt/gtk-ng: basic tab creation
This commit is contained in:
@ -37,12 +37,13 @@ pub const blueprints: []const Blueprint = &.{
|
||||
.{ .major = 1, .minor = 4, .name = "clipboard-confirmation-dialog" },
|
||||
.{ .major = 1, .minor = 2, .name = "close-confirmation-dialog" },
|
||||
.{ .major = 1, .minor = 2, .name = "config-errors-dialog" },
|
||||
.{ .major = 1, .minor = 2, .name = "debug-warning" },
|
||||
.{ .major = 1, .minor = 3, .name = "debug-warning" },
|
||||
.{ .major = 1, .minor = 2, .name = "resize-overlay" },
|
||||
.{ .major = 1, .minor = 2, .name = "surface" },
|
||||
.{ .major = 1, .minor = 3, .name = "surface-child-exited" },
|
||||
.{ .major = 1, .minor = 5, .name = "tab" },
|
||||
.{ .major = 1, .minor = 5, .name = "window" },
|
||||
.{ .major = 1, .minor = 2, .name = "debug-warning" },
|
||||
.{ .major = 1, .minor = 3, .name = "debug-warning" },
|
||||
};
|
||||
|
||||
/// CSS files in css_path
|
||||
|
190
src/apprt/gtk-ng/class/tab.zig
Normal file
190
src/apprt/gtk-ng/class/tab.zig
Normal file
@ -0,0 +1,190 @@
|
||||
const std = @import("std");
|
||||
const build_config = @import("../../../build_config.zig");
|
||||
const assert = std.debug.assert;
|
||||
const adw = @import("adw");
|
||||
const gio = @import("gio");
|
||||
const glib = @import("glib");
|
||||
const gobject = @import("gobject");
|
||||
const gtk = @import("gtk");
|
||||
|
||||
const i18n = @import("../../../os/main.zig").i18n;
|
||||
const apprt = @import("../../../apprt.zig");
|
||||
const input = @import("../../../input.zig");
|
||||
const CoreSurface = @import("../../../Surface.zig");
|
||||
const gtk_version = @import("../gtk_version.zig");
|
||||
const adw_version = @import("../adw_version.zig");
|
||||
const gresource = @import("../build/gresource.zig");
|
||||
const Common = @import("../class.zig").Common;
|
||||
const Config = @import("config.zig").Config;
|
||||
const Application = @import("application.zig").Application;
|
||||
const CloseConfirmationDialog = @import("close_confirmation_dialog.zig").CloseConfirmationDialog;
|
||||
const Surface = @import("surface.zig").Surface;
|
||||
|
||||
const log = std.log.scoped(.gtk_ghostty_window);
|
||||
|
||||
pub const Tab = extern struct {
|
||||
const Self = @This();
|
||||
parent_instance: Parent,
|
||||
pub const Parent = gtk.Box;
|
||||
pub const getGObjectType = gobject.ext.defineClass(Self, .{
|
||||
.name = "GhosttyTab",
|
||||
.instanceInit = &init,
|
||||
.classInit = &Class.init,
|
||||
.parent_class = &Class.parent,
|
||||
.private = .{ .Type = Private, .offset = &Private.offset },
|
||||
});
|
||||
|
||||
pub const properties = struct {
|
||||
/// The active surface is the focus that should be receiving all
|
||||
/// surface-targeted actions. This is usually the focused surface,
|
||||
/// but may also not be focused if the user has selected a non-surface
|
||||
/// widget.
|
||||
pub const @"active-surface" = struct {
|
||||
pub const name = "active-surface";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
name,
|
||||
Self,
|
||||
?*Surface,
|
||||
.{
|
||||
.nick = "Active Surface",
|
||||
.blurb = "The currently active surface.",
|
||||
.accessor = gobject.ext.typedAccessor(
|
||||
Self,
|
||||
?*Surface,
|
||||
.{
|
||||
.getter = Self.getActiveSurface,
|
||||
},
|
||||
),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
pub const config = struct {
|
||||
pub const name = "config";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
name,
|
||||
Self,
|
||||
?*Config,
|
||||
.{
|
||||
.nick = "Config",
|
||||
.blurb = "The configuration that this surface is using.",
|
||||
.accessor = C.privateObjFieldAccessor("config"),
|
||||
},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const Private = struct {
|
||||
/// The configuration that this surface is using.
|
||||
config: ?*Config = null,
|
||||
|
||||
// Template bindings
|
||||
surface: *Surface,
|
||||
|
||||
pub var offset: c_int = 0;
|
||||
};
|
||||
|
||||
/// Set the parent of this tab page. This only affects the first surface
|
||||
/// ever created for a tab. If a surface was already created this does
|
||||
/// nothing.
|
||||
pub fn setParent(
|
||||
self: *Self,
|
||||
parent: *CoreSurface,
|
||||
) void {
|
||||
const priv = self.private();
|
||||
priv.surface.setParent(parent);
|
||||
}
|
||||
|
||||
fn init(self: *Self, _: *Class) callconv(.C) void {
|
||||
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
||||
|
||||
// If our configuration is null then we get the configuration
|
||||
// from the application.
|
||||
const priv = self.private();
|
||||
if (priv.config == null) {
|
||||
const app = Application.default();
|
||||
priv.config = app.getConfig();
|
||||
}
|
||||
|
||||
// We need to do this so that the title initializes properly,
|
||||
// I think because its a dynamic getter.
|
||||
self.as(gobject.Object).notifyByPspec(properties.@"active-surface".impl.param_spec);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Properties
|
||||
|
||||
/// Get the currently active surface. See the "active-surface" property.
|
||||
/// This does not ref the value.
|
||||
pub fn getActiveSurface(self: *Self) *Surface {
|
||||
const priv = self.private();
|
||||
return priv.surface;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Virtual methods
|
||||
|
||||
fn dispose(self: *Self) callconv(.C) void {
|
||||
const priv = self.private();
|
||||
if (priv.config) |v| {
|
||||
v.unref();
|
||||
priv.config = null;
|
||||
}
|
||||
|
||||
gtk.Widget.disposeTemplate(
|
||||
self.as(gtk.Widget),
|
||||
getGObjectType(),
|
||||
);
|
||||
|
||||
gobject.Object.virtual_methods.dispose.call(
|
||||
Class.parent,
|
||||
self.as(Parent),
|
||||
);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Signal handlers
|
||||
|
||||
const C = Common(Self, Private);
|
||||
pub const as = C.as;
|
||||
pub const ref = C.ref;
|
||||
pub const unref = C.unref;
|
||||
const private = C.private;
|
||||
|
||||
pub const Class = extern struct {
|
||||
parent_class: Parent.Class,
|
||||
var parent: *Parent.Class = undefined;
|
||||
pub const Instance = Self;
|
||||
|
||||
fn init(class: *Class) callconv(.C) void {
|
||||
gobject.ext.ensureType(Surface);
|
||||
gtk.Widget.Class.setTemplateFromResource(
|
||||
class.as(gtk.Widget.Class),
|
||||
comptime gresource.blueprint(.{
|
||||
.major = 1,
|
||||
.minor = 5,
|
||||
.name = "tab",
|
||||
}),
|
||||
);
|
||||
|
||||
// Properties
|
||||
gobject.ext.registerProperties(class, &.{
|
||||
properties.@"active-surface".impl,
|
||||
properties.config.impl,
|
||||
});
|
||||
|
||||
// Bindings
|
||||
class.bindTemplateChildPrivate("surface", .{});
|
||||
|
||||
// Template Callbacks
|
||||
//class.bindTemplateCallback("close_request", &windowCloseRequest);
|
||||
|
||||
// Virtual methods
|
||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||
}
|
||||
|
||||
pub const as = C.Class.as;
|
||||
pub const bindTemplateChildPrivate = C.Class.bindTemplateChildPrivate;
|
||||
pub const bindTemplateCallback = C.Class.bindTemplateCallback;
|
||||
};
|
||||
};
|
@ -19,6 +19,7 @@ const Config = @import("config.zig").Config;
|
||||
const Application = @import("application.zig").Application;
|
||||
const CloseConfirmationDialog = @import("close_confirmation_dialog.zig").CloseConfirmationDialog;
|
||||
const Surface = @import("surface.zig").Surface;
|
||||
const Tab = @import("tab.zig").Tab;
|
||||
const DebugWarning = @import("debug_warning.zig").DebugWarning;
|
||||
|
||||
const log = std.log.scoped(.gtk_ghostty_window);
|
||||
@ -207,8 +208,8 @@ pub const Window = extern struct {
|
||||
config: ?*Config = null,
|
||||
|
||||
// Template bindings
|
||||
surface: *Surface,
|
||||
tab_bar: *adw.TabBar,
|
||||
tab_view: *adw.TabView,
|
||||
toolbar: *adw.ToolbarView,
|
||||
toast_overlay: *adw.ToastOverlay,
|
||||
|
||||
@ -220,10 +221,13 @@ pub const Window = extern struct {
|
||||
.application = app,
|
||||
});
|
||||
|
||||
if (parent_) |parent| {
|
||||
const priv = self.private();
|
||||
priv.surface.setParent(parent);
|
||||
}
|
||||
// Create our initial tab
|
||||
const priv = self.private();
|
||||
const tab = gobject.ext.newInstance(Tab, .{
|
||||
.config = priv.config,
|
||||
});
|
||||
if (parent_) |p| tab.setParent(p);
|
||||
_ = priv.tab_view.append(tab.as(gtk.Widget));
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -364,7 +368,8 @@ pub const Window = extern struct {
|
||||
/// This does not ref the value.
|
||||
fn getActiveSurface(self: *Self) ?*Surface {
|
||||
const priv = self.private();
|
||||
return priv.surface;
|
||||
_ = priv;
|
||||
return null;
|
||||
}
|
||||
|
||||
fn getHeaderbarVisible(self: *Self) bool {
|
||||
@ -595,8 +600,8 @@ pub const Window = extern struct {
|
||||
) callconv(.c) void {
|
||||
// Todo
|
||||
_ = scope;
|
||||
_ = surface;
|
||||
|
||||
assert(surface == self.private().surface);
|
||||
self.as(gtk.Window).close();
|
||||
}
|
||||
|
||||
@ -732,7 +737,6 @@ pub const Window = extern struct {
|
||||
pub const Instance = Self;
|
||||
|
||||
fn init(class: *Class) callconv(.C) void {
|
||||
gobject.ext.ensureType(Surface);
|
||||
gobject.ext.ensureType(DebugWarning);
|
||||
gtk.Widget.Class.setTemplateFromResource(
|
||||
class.as(gtk.Widget.Class),
|
||||
@ -757,8 +761,8 @@ pub const Window = extern struct {
|
||||
});
|
||||
|
||||
// Bindings
|
||||
class.bindTemplateChildPrivate("surface", .{});
|
||||
class.bindTemplateChildPrivate("tab_bar", .{});
|
||||
class.bindTemplateChildPrivate("tab_view", .{});
|
||||
class.bindTemplateChildPrivate("toolbar", .{});
|
||||
class.bindTemplateChildPrivate("toast_overlay", .{});
|
||||
|
||||
|
18
src/apprt/gtk-ng/ui/1.5/tab.blp
Normal file
18
src/apprt/gtk-ng/ui/1.5/tab.blp
Normal file
@ -0,0 +1,18 @@
|
||||
using Gtk 4.0;
|
||||
|
||||
template $GhosttyTab: Box {
|
||||
styles [
|
||||
"tab",
|
||||
]
|
||||
|
||||
hexpand: true;
|
||||
vexpand: true;
|
||||
// A tab currently just contains a surface directly. When we introduce
|
||||
// splits we probably want to replace this with the split widget type.
|
||||
$GhosttySurface surface {
|
||||
// close-request => $surface_close_request();
|
||||
// clipboard-write => $surface_clipboard_write();
|
||||
// toggle-fullscreen => $surface_toggle_fullscreen();
|
||||
// toggle-maximize => $surface_toggle_maximize();
|
||||
}
|
||||
}
|
@ -78,18 +78,7 @@ template $GhosttyWindow: Adw.ApplicationWindow {
|
||||
}
|
||||
|
||||
Adw.ToastOverlay toast_overlay {
|
||||
Adw.TabView tab_view {
|
||||
Adw.TabPage {
|
||||
title: bind (template.active-surface as <$GhosttySurface>).title;
|
||||
|
||||
child: $GhosttySurface surface {
|
||||
close-request => $surface_close_request();
|
||||
clipboard-write => $surface_clipboard_write();
|
||||
toggle-fullscreen => $surface_toggle_fullscreen();
|
||||
toggle-maximize => $surface_toggle_maximize();
|
||||
};
|
||||
}
|
||||
}
|
||||
Adw.TabView tab_view {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user