mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-09-05 19:08:17 +00:00
Compare commits
1 Commits
d316449ebf
...
tristan957
Author | SHA1 | Date | |
---|---|---|---|
![]() |
721ab5d134 |
@@ -39,10 +39,18 @@ pub fn cgroup(self: *Self) ?[]const u8 {
|
||||
return self.surface.cgroupPath();
|
||||
}
|
||||
|
||||
pub fn setPwd(self: *Self, pwd: [:0]const u8) void {
|
||||
return self.surface.setPwd(pwd);
|
||||
}
|
||||
|
||||
pub fn getTitle(self: *Self) ?[:0]const u8 {
|
||||
return self.surface.getTitle();
|
||||
}
|
||||
|
||||
pub fn setTitle(self: *Self, title: [:0]const u8) void {
|
||||
return self.surface.setTitle(title);
|
||||
}
|
||||
|
||||
pub fn getContentScale(self: *const Self) !apprt.ContentScale {
|
||||
return self.surface.getContentScale();
|
||||
}
|
||||
|
@@ -1086,6 +1086,7 @@ const Action = struct {
|
||||
|
||||
const win = Window.new(self);
|
||||
gtk.Window.present(win.as(gtk.Window));
|
||||
win.setupInitialFocus();
|
||||
}
|
||||
|
||||
pub fn pwd(
|
||||
@@ -1095,13 +1096,7 @@ const Action = struct {
|
||||
switch (target) {
|
||||
.app => log.warn("pwd to app is unexpected", .{}),
|
||||
.surface => |surface| {
|
||||
var v = gobject.ext.Value.newFrom(value.pwd);
|
||||
defer v.unset();
|
||||
gobject.Object.setProperty(
|
||||
surface.rt_surface.gobj().as(gobject.Object),
|
||||
"pwd",
|
||||
&v,
|
||||
);
|
||||
surface.rt_surface.setPwd(value.pwd);
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1130,13 +1125,7 @@ const Action = struct {
|
||||
switch (target) {
|
||||
.app => log.warn("set_title to app is unexpected", .{}),
|
||||
.surface => |surface| {
|
||||
var v = gobject.ext.Value.newFrom(value.title);
|
||||
defer v.unset();
|
||||
gobject.Object.setProperty(
|
||||
surface.rt_surface.gobj().as(gobject.Object),
|
||||
"title",
|
||||
&v,
|
||||
);
|
||||
surface.rt_surface.setTitle(value.title);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@@ -52,6 +52,24 @@ pub const Config = extern struct {
|
||||
},
|
||||
);
|
||||
|
||||
pub const @"gtk-wide-tabs" = gobject.ext.defineProperty(
|
||||
"gtk-wide-tabs",
|
||||
Self,
|
||||
bool,
|
||||
.{
|
||||
.nick = "gtk-wide-tabs",
|
||||
.blurb = null,
|
||||
.default = false,
|
||||
.accessor = gobject.ext.typedAccessor(
|
||||
Self,
|
||||
bool,
|
||||
.{
|
||||
.getter = Self.gtkWideTabs,
|
||||
},
|
||||
),
|
||||
},
|
||||
);
|
||||
|
||||
pub const @"has-diagnostics" = gobject.ext.defineProperty(
|
||||
"has-diagnostics",
|
||||
Self,
|
||||
@@ -105,6 +123,12 @@ pub const Config = extern struct {
|
||||
return &self.private().config;
|
||||
}
|
||||
|
||||
/// Returns the current value of gtk-wide-tabs.
|
||||
pub fn gtkWideTabs(self: *Self) bool {
|
||||
const config = self.get();
|
||||
return config.@"gtk-wide-tabs";
|
||||
}
|
||||
|
||||
/// Returns whether this configuration has any diagnostics.
|
||||
pub fn hasDiagnostics(self: *Self) bool {
|
||||
const config = self.get();
|
||||
@@ -163,6 +187,7 @@ pub const Config = extern struct {
|
||||
gobject.Object.virtual_methods.finalize.implement(class, &finalize);
|
||||
gobject.ext.registerProperties(class, &.{
|
||||
properties.@"diagnostics-buffer",
|
||||
properties.@"gtk-wide-tabs",
|
||||
properties.@"has-diagnostics",
|
||||
});
|
||||
}
|
||||
|
@@ -1085,11 +1085,42 @@ pub const Surface = extern struct {
|
||||
//---------------------------------------------------------------
|
||||
// Properties
|
||||
|
||||
/// Returns the pwd property without a copy.
|
||||
pub fn getPwd(self: *Self) ?[:0]const u8 {
|
||||
return self.private().pwd;
|
||||
}
|
||||
|
||||
/// Set the pwd property.
|
||||
pub fn setPwd(self: *Self, pwd: [:0]const u8) void {
|
||||
const priv = self.private();
|
||||
|
||||
if (priv.title) |v| {
|
||||
glib.free(@constCast(@ptrCast(v)));
|
||||
priv.title = null;
|
||||
}
|
||||
|
||||
priv.pwd = std.mem.span(glib.strdup(pwd));
|
||||
self.as(gobject.Object).notifyByPspec(properties.pwd.impl.param_spec);
|
||||
}
|
||||
|
||||
/// Returns the title property without a copy.
|
||||
pub fn getTitle(self: *Self) ?[:0]const u8 {
|
||||
return self.private().title;
|
||||
}
|
||||
|
||||
/// Set the title property.
|
||||
pub fn setTitle(self: *Self, title: [:0]const u8) void {
|
||||
const priv = self.private();
|
||||
|
||||
if (priv.title) |v| {
|
||||
glib.free(@constCast(@ptrCast(v)));
|
||||
priv.title = null;
|
||||
}
|
||||
|
||||
priv.title = std.mem.span(glib.strdup(title));
|
||||
self.as(gobject.Object).notifyByPspec(properties.title.impl.param_spec);
|
||||
}
|
||||
|
||||
fn propConfig(
|
||||
self: *Self,
|
||||
_: *gobject.ParamSpec,
|
||||
|
@@ -8,6 +8,7 @@ const gresource = @import("../build/gresource.zig");
|
||||
const Common = @import("../class.zig").Common;
|
||||
const Application = @import("application.zig").Application;
|
||||
const Surface = @import("surface.zig").Surface;
|
||||
const Config = @import("config.zig").Config;
|
||||
|
||||
const log = std.log.scoped(.gtk_ghostty_window);
|
||||
|
||||
@@ -23,7 +24,34 @@ pub const Window = extern struct {
|
||||
.private = .{ .Type = Private, .offset = &Private.offset },
|
||||
});
|
||||
|
||||
pub const properties = struct {
|
||||
pub const config = struct {
|
||||
pub const name = "config";
|
||||
const impl = gobject.ext.defineProperty(
|
||||
name,
|
||||
Self,
|
||||
?*Config,
|
||||
.{
|
||||
.nick = "Config",
|
||||
.blurb = "The configuration that this window is using.",
|
||||
.accessor = gobject.ext.privateFieldAccessor(
|
||||
Self,
|
||||
Private,
|
||||
&Private.offset,
|
||||
"config",
|
||||
),
|
||||
},
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const Private = struct {
|
||||
/// The configuration that this window is using.
|
||||
config: ?*Config = null,
|
||||
|
||||
/// The window title widget.
|
||||
window_title: *adw.WindowTitle = undefined,
|
||||
|
||||
/// The surface in the view.
|
||||
surface: *Surface = undefined,
|
||||
|
||||
@@ -34,10 +62,19 @@ pub const Window = extern struct {
|
||||
return gobject.ext.newInstance(Self, .{ .application = app });
|
||||
}
|
||||
|
||||
pub fn setupInitialFocus(self: *Self) void {
|
||||
_ = self.private().surface.as(gtk.Widget).grabFocus();
|
||||
}
|
||||
|
||||
fn init(self: *Self, _: *Class) callconv(.C) void {
|
||||
gtk.Widget.initTemplate(self.as(gtk.Widget));
|
||||
|
||||
const surface = self.private().surface;
|
||||
const priv = self.private();
|
||||
|
||||
const app = Application.default();
|
||||
priv.config = app.getConfig();
|
||||
|
||||
const surface = priv.surface;
|
||||
_ = Surface.signals.@"close-request".connect(
|
||||
surface,
|
||||
*Self,
|
||||
@@ -45,6 +82,32 @@ pub const Window = extern struct {
|
||||
self,
|
||||
.{},
|
||||
);
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
surface,
|
||||
*Self,
|
||||
&surfaceNotifyHasFocus,
|
||||
self,
|
||||
.{ .detail = "has-focus" },
|
||||
);
|
||||
self.setupSurfacePropertyConnections(surface);
|
||||
}
|
||||
|
||||
fn setupSurfacePropertyConnections(self: *Self, surface: *Surface) void {
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
surface,
|
||||
*Self,
|
||||
&surfaceNotifyTitle,
|
||||
self,
|
||||
.{ .detail = "title" },
|
||||
);
|
||||
|
||||
_ = gobject.Object.signals.notify.connect(
|
||||
surface,
|
||||
*Self,
|
||||
&surfaceNotifyPwd,
|
||||
self,
|
||||
.{ .detail = "pwd" },
|
||||
);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
@@ -56,12 +119,30 @@ pub const Window = extern struct {
|
||||
getGObjectType(),
|
||||
);
|
||||
|
||||
const priv = self.private();
|
||||
if (priv.config) |v| {
|
||||
v.unref();
|
||||
priv.config = null;
|
||||
}
|
||||
|
||||
gobject.Object.virtual_methods.dispose.call(
|
||||
Class.parent,
|
||||
self.as(Parent),
|
||||
);
|
||||
}
|
||||
|
||||
/// Set the title of the window.
|
||||
fn setTitle(self: *Self, title: [:0]const u8) void {
|
||||
const window_title = self.private().window_title;
|
||||
window_title.setTitle(title);
|
||||
}
|
||||
|
||||
/// Set the subtitle of the window.
|
||||
fn setSubtitle(self: *Self, subtitle: [:0]const u8) void {
|
||||
const window_title = self.private().window_title;
|
||||
window_title.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Signal handlers
|
||||
|
||||
@@ -77,6 +158,42 @@ pub const Window = extern struct {
|
||||
self.as(gtk.Window).close();
|
||||
}
|
||||
|
||||
fn surfaceNotifyHasFocus(surface: *Surface, _: *gobject.ParamSpec, self: *Self) callconv(.c) void {
|
||||
assert(surface == self.private().surface);
|
||||
|
||||
self.setTitle(surface.getTitle().?);
|
||||
|
||||
const subtitle: [:0]const u8 = switch (Application.default().getConfig().get().@"window-subtitle") {
|
||||
.@"working-directory" => surface.getPwd() orelse "",
|
||||
.false => "",
|
||||
};
|
||||
self.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
fn surfaceNotifyTitle(surface: *Surface, _: *gobject.ParamSpec, self: *Self) callconv(.c) void {
|
||||
assert(surface == self.private().surface);
|
||||
|
||||
if (surface.as(gtk.Widget).grabFocus() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.setTitle(surface.getTitle().?);
|
||||
}
|
||||
|
||||
fn surfaceNotifyPwd(surface: *Surface, _: *gobject.ParamSpec, self: *Self) callconv(.c) void {
|
||||
assert(surface == self.private().surface);
|
||||
|
||||
if (surface.as(gtk.Widget).grabFocus() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.default().getConfig().get().@"window-subtitle" != .@"working-directory") {
|
||||
return;
|
||||
}
|
||||
|
||||
self.setSubtitle(surface.getPwd() orelse "");
|
||||
}
|
||||
|
||||
const C = Common(Self, Private);
|
||||
pub const as = C.as;
|
||||
pub const ref = C.ref;
|
||||
@@ -100,8 +217,14 @@ pub const Window = extern struct {
|
||||
);
|
||||
|
||||
// Bindings
|
||||
class.bindTemplateChildPrivate("window_title", .{});
|
||||
class.bindTemplateChildPrivate("surface", .{});
|
||||
|
||||
// Properties
|
||||
gobject.ext.registerProperties(class, &.{
|
||||
properties.config.impl,
|
||||
});
|
||||
|
||||
// Virtual methods
|
||||
gobject.Object.virtual_methods.dispose.implement(class, &dispose);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
template $GhosttySurface: Adw.Bin {
|
||||
focusable: true;
|
||||
// We need to wrap our Overlay one more time because if you bind a
|
||||
// direct child of your widget to a property, it will double free:
|
||||
// https://gitlab.gnome.org/GNOME/gtk/-/blob/847571a1e314aba79260e4ef282e2ed9ba91a0d9/gtk/gtkwidget.c#L11423-11425
|
||||
|
@@ -1,9 +1,192 @@
|
||||
using Gtk 4.0;
|
||||
using Adw 1;
|
||||
|
||||
menu split_menu {
|
||||
item {
|
||||
label: _("Split Up");
|
||||
action: "win.split-up";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Down");
|
||||
action: "win.split-down";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Left");
|
||||
action: "win.split-left";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Right");
|
||||
action: "win.split-right";
|
||||
}
|
||||
}
|
||||
|
||||
menu main_menu {
|
||||
section {
|
||||
item {
|
||||
label: _("Copy");
|
||||
action: "win.copy";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Paste");
|
||||
action: "win.paste";
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
item {
|
||||
label: _("New Window");
|
||||
action: "win.new-window";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Close Window");
|
||||
action: "win.close";
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
item {
|
||||
label: _("New Tab");
|
||||
action: "win.new-tab";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Close Tab");
|
||||
action: "win.close-tab";
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
submenu {
|
||||
label: _("Split");
|
||||
|
||||
item {
|
||||
label: _("Change Title…");
|
||||
action: "win.prompt-title";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Up");
|
||||
action: "win.split-up";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Down");
|
||||
action: "win.split-down";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Left");
|
||||
action: "win.split-left";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Split Right");
|
||||
action: "win.split-right";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
item {
|
||||
label: _("Clear");
|
||||
action: "win.clear";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Reset");
|
||||
action: "win.reset";
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
item {
|
||||
label: _("Command Palette");
|
||||
action: "win.toggle-command-palette";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Terminal Inspector");
|
||||
action: "win.toggle-inspector";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Open Configuration");
|
||||
action: "app.open-config";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Reload Configuration");
|
||||
action: "app.reload-config";
|
||||
}
|
||||
}
|
||||
|
||||
section {
|
||||
item {
|
||||
label: _("About Ghostty");
|
||||
action: "win.about";
|
||||
}
|
||||
|
||||
item {
|
||||
label: _("Quit");
|
||||
action: "app.quit";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template $GhosttyWindow: Adw.ApplicationWindow {
|
||||
default-width: 800;
|
||||
default-height: 600;
|
||||
|
||||
content: $GhosttySurface surface {};
|
||||
content: Adw.TabOverview tab_overview {
|
||||
view: tab_view;
|
||||
|
||||
child: Adw.ToolbarView {
|
||||
content: Gtk.Box {
|
||||
orientation: vertical;
|
||||
|
||||
Adw.HeaderBar {
|
||||
title-widget: Adw.WindowTitle window_title {
|
||||
title: "Ghostty";
|
||||
};
|
||||
|
||||
[start]
|
||||
Adw.SplitButton {
|
||||
icon-name: "tab-new-symbolic";
|
||||
menu-model: split_menu;
|
||||
tooltip-text: _("New Tab");
|
||||
dropdown-tooltip: _("New Split");
|
||||
}
|
||||
|
||||
[end]
|
||||
Gtk.Box {
|
||||
Gtk.ToggleButton {
|
||||
icon-name: "view-grid-symbolic";
|
||||
tooltip-text: _("View Open Tabs");
|
||||
active: bind tab_overview.open bidirectional;
|
||||
}
|
||||
|
||||
Gtk.MenuButton {
|
||||
icon-name: "open-menu-symbolic";
|
||||
menu-model: main_menu;
|
||||
tooltip-text: _("Main Menu");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Adw.TabBar {
|
||||
view: tab_view;
|
||||
expand-tabs: bind (template.config as <$GhosttyConfig>).gtk-wide-tabs;
|
||||
}
|
||||
|
||||
Adw.TabView tab_view {
|
||||
$GhosttySurface surface {}
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user