From ccde429bde0c36dc0725cdddd75fc89ed8b111bd Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 26 Jul 2025 12:29:07 -0700 Subject: [PATCH 1/9] apprt/gtk-ng: toasts --- src/apprt/gtk-ng/class/surface.zig | 7 +++-- src/apprt/gtk-ng/class/window.zig | 42 +++++++++++++++++++++++++++++- src/apprt/gtk-ng/ui/1.5/window.blp | 11 +++++--- src/apprt/structs.zig | 19 +++++++++++++- 4 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 7d162b4e9..0cefebc63 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -275,7 +275,10 @@ pub const Surface = extern struct { const impl = gobject.ext.defineSignal( name, Self, - &.{}, + &.{ + apprt.Clipboard, + [*:0]const u8, + }, void, ); }; @@ -2236,7 +2239,7 @@ const Clipboard = struct { Surface.signals.@"clipboard-write".impl.emit( self, null, - .{}, + .{ clipboard_type, val.ptr }, null, ); diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index 875fad9b6..ac5555391 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -8,6 +8,7 @@ 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"); @@ -122,7 +123,8 @@ pub const Window = extern struct { config: ?*Config = null, // Template bindings - surface: *Surface = undefined, + surface: *Surface, + toast_overlay: *adw.ToastOverlay, pub var offset: c_int = 0; }; @@ -227,6 +229,18 @@ pub const Window = extern struct { }; } + /// Queue a simple text-based toast. All text-based toasts share the + /// same timeout for consistency. + /// + // This is not `pub` because we should be using signals emitted by + // other widgets to trigger our toasts. Other objects should not + // trigger toasts directly. + fn addToast(self: *Window, title: [*:0]const u8) void { + const toast = adw.Toast.new(title); + toast.setTimeout(3); + self.private().toast_overlay.addToast(toast); + } + //--------------------------------------------------------------- // Properties @@ -264,6 +278,7 @@ pub const Window = extern struct { _: *gobject.ParamSpec, self: *Self, ) callconv(.c) void { + self.addToast(i18n._("Reloaded the configuration")); self.syncAppearance(); } @@ -377,6 +392,29 @@ pub const Window = extern struct { self.as(gtk.Window).destroy(); } + fn surfaceClipboardWrite( + _: *Surface, + clipboard_type: apprt.Clipboard, + text: [*:0]const u8, + self: *Self, + ) callconv(.c) void { + // We only toast for the standard clipboard. + if (clipboard_type != .standard) return; + + // We only toast if configured to + const priv = self.private(); + const config_obj = priv.config orelse return; + const config = config_obj.get(); + if (!config.@"app-notifications".@"clipboard-copy") { + return; + } + + if (text[0] != 0) + self.addToast(i18n._("Copied to clipboard")) + else + self.addToast(i18n._("Cleared clipboard")); + } + fn surfaceCloseRequest( surface: *Surface, scope: *const Surface.CloseScope, @@ -542,9 +580,11 @@ pub const Window = extern struct { // Bindings class.bindTemplateChildPrivate("surface", .{}); + class.bindTemplateChildPrivate("toast_overlay", .{}); // Template Callbacks class.bindTemplateCallback("close_request", &windowCloseRequest); + class.bindTemplateCallback("surface_clipboard_write", &surfaceClipboardWrite); class.bindTemplateCallback("surface_close_request", &surfaceCloseRequest); class.bindTemplateCallback("surface_toggle_fullscreen", &surfaceToggleFullscreen); class.bindTemplateCallback("surface_toggle_maximize", &surfaceToggleMaximize); diff --git a/src/apprt/gtk-ng/ui/1.5/window.blp b/src/apprt/gtk-ng/ui/1.5/window.blp index c8ffdade3..1e2345d95 100644 --- a/src/apprt/gtk-ng/ui/1.5/window.blp +++ b/src/apprt/gtk-ng/ui/1.5/window.blp @@ -43,10 +43,13 @@ template $GhosttyWindow: Adw.ApplicationWindow { visible: bind template.debug; } - $GhosttySurface surface { - close-request => $surface_close_request(); - toggle-fullscreen => $surface_toggle_fullscreen(); - toggle-maximize => $surface_toggle_maximize(); + Adw.ToastOverlay toast_overlay { + $GhosttySurface surface { + close-request => $surface_close_request(); + clipboard-write => $surface_clipboard_write(); + toggle-fullscreen => $surface_toggle_fullscreen(); + toggle-maximize => $surface_toggle_maximize(); + } } }; } diff --git a/src/apprt/structs.zig b/src/apprt/structs.zig index 1c3b28723..c9948f3ee 100644 --- a/src/apprt/structs.zig +++ b/src/apprt/structs.zig @@ -29,10 +29,27 @@ pub const IMEPos = struct { /// The clipboard type. /// /// If this is changed, you must also update ghostty.h -pub const Clipboard = enum(u2) { +pub const Clipboard = enum(Backing) { standard = 0, // ctrl+c/v selection = 1, primary = 2, + + // Our backing isn't is as small as we can in Zig, but a full + // C int if we're binding to C APIs. + const Backing = switch (build_config.app_runtime) { + .gtk, .@"gtk-ng" => c_int, + else => u2, + }; + + /// Make this a valid gobject if we're in a GTK environment. + pub const getGObjectType = switch (build_config.app_runtime) { + .gtk, .@"gtk-ng" => @import("gobject").ext.defineEnum( + Clipboard, + .{ .name = "GhosttyApprtClipboard" }, + ), + + .none => void, + }; }; pub const ClipboardRequestType = enum(u8) { From 53c7b8922fc6a8927596ae0ea34161febc42ba8a Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 27 Jul 2025 13:46:24 -0700 Subject: [PATCH 2/9] apprt/gtk-ng: reload config --- src/apprt/gtk-ng/class/application.zig | 142 ++++++++++++++++++------- src/apprt/gtk-ng/class/surface.zig | 8 ++ 2 files changed, 111 insertions(+), 39 deletions(-) diff --git a/src/apprt/gtk-ng/class/application.zig b/src/apprt/gtk-ng/class/application.zig index 3682c5ba6..d27210b5c 100644 --- a/src/apprt/gtk-ng/class/application.zig +++ b/src/apprt/gtk-ng/class/application.zig @@ -508,6 +508,8 @@ pub const Application = extern struct { .progress_report => return Action.progressReport(target, value), + .reload_config => try Action.reloadConfig(self, target, value), + .render => Action.render(target), .ring_bell => Action.ringBell(target), @@ -530,7 +532,6 @@ pub const Application = extern struct { .equalize_splits, .goto_split, .open_config, - .reload_config, .inspector, .desktop_notification, .present_terminal, @@ -573,29 +574,6 @@ pub const Application = extern struct { return true; } - /// Reload the configuration for the application and propagate it - /// across the entire application and all terminals. - pub fn reloadConfig(self: *Self) !void { - const alloc = self.allocator(); - - // Read our new config. We can always deinit this because - // we'll clone and store it if libghostty accepts it and - // emits a `config_change` action. - var config = try CoreConfig.load(alloc); - defer config.deinit(); - - // Notify the app that we've updated. - const priv = self.private(); - try priv.core_app.updateConfig(priv.rt_app, &config); - } - - /// Returns the configuration for this application. - /// - /// The reference count is increased. - pub fn getConfig(self: *Self) *Config { - return self.private().config.ref(); - } - /// Returns the core app associated with this application. This is /// not a reference-counted type so you should not store this. pub fn core(self: *Self) *CoreApp { @@ -662,6 +640,31 @@ pub const Application = extern struct { } } + //--------------------------------------------------------------- + // Properties + + /// Returns the configuration for this application. + /// + /// The reference count is increased. + pub fn getConfig(self: *Self) *Config { + return self.private().config.ref(); + } + + /// Set the configuration for this application. The reference count + /// is increased on the new configuration and the old one is + /// unreferenced. + /// + /// If the config has errors this may show the config errors dialog. + fn setConfig(self: *Self, config: *Config) void { + const priv = self.private(); + priv.config.unref(); + priv.config = config.ref(); + self.as(gobject.Object).notifyByPspec(properties.config.impl.param_spec); + + // Show our errors if we have any + self.showConfigErrorsDialog(); + } + //--------------------------------------------------------------- // Libghostty Callbacks @@ -794,9 +797,10 @@ pub const Application = extern struct { // For action names: // https://docs.gtk.org/gio/type_func.Action.name_is_valid.html const actions = .{ - .{ "quit", actionQuit, null }, .{ "new-window", actionNewWindow, null }, .{ "new-window-command", actionNewWindow, as_variant_type }, + .{ "quit", actionQuit, null }, + .{ "reload-config", actionReloadConfig, null }, }; const action_map = self.as(gio.ActionMap); @@ -961,7 +965,12 @@ pub const Application = extern struct { const priv = self.private(); priv.config_errors_dialog.set(null); - self.reloadConfig() catch |err| { + // Reload our config as if the app reloaded. + Action.reloadConfig( + self, + .app, + .{}, + ) catch |err| { // If we fail to reload the configuration, then we want the // user to know it. For now we log but we should show another // GUI. @@ -1016,6 +1025,17 @@ pub const Application = extern struct { dialog.present(null); } + fn actionReloadConfig( + _: *gio.SimpleAction, + _: ?*glib.Variant, + self: *Self, + ) callconv(.c) void { + const priv = self.private(); + priv.core_app.performAction(self.rt(), .reload_config) catch |err| { + log.warn("error reloading config err={}", .{err}); + }; + } + fn actionQuit( _: *gio.SimpleAction, _: ?*glib.Variant, @@ -1138,21 +1158,11 @@ const Action = struct { // Wrap our config in a GObject. This will clone it. const alloc = self.allocator(); const config_obj: *Config = try .new(alloc, new_config); - errdefer config_obj.unref(); + defer config_obj.unref(); switch (target) { - // TODO: when we implement surfaces in gtk-ng - .surface => @panic("TODO"), - - .app => { - // Set it on our private - const priv = self.private(); - priv.config.unref(); - priv.config = config_obj; - - // Show our errors if we have any - self.showConfigErrorsDialog(); - }, + .surface => |core| core.rt_surface.surface.setConfig(config_obj), + .app => self.setConfig(config_obj), } } @@ -1219,6 +1229,19 @@ const Action = struct { parent: ?*CoreSurface, ) !void { const win = Window.new(self, parent); + + // Setup a binding so that whenever our config changes so does the + // window. There's never a time when the window config should be out + // of sync with the application config. + _ = gobject.Object.bindProperty( + self.as(gobject.Object), + "config", + win.as(gobject.Object), + "config", + .{}, + ); + + // Show the window gtk.Window.present(win.as(gtk.Window)); } @@ -1263,6 +1286,47 @@ const Action = struct { }; } + /// Reload the configuration for the application and propagate it + /// across the entire application and all terminals. + pub fn reloadConfig( + self: *Application, + target: apprt.Target, + opts: apprt.action.ReloadConfig, + ) !void { + // Tell systemd that reloading has started. + systemd.notify.reloading(); + + // When we exit this function tell systemd that reloading has finished. + defer systemd.notify.ready(); + + // Get our config object. + const config: *Config = config: { + // Soft-reloading applies conditional logic to the existing loaded + // config so we return that as-is (but take a reference). + if (opts.soft) { + break :config self.private().config.ref(); + } + + // Hard reload, load a new config completely. + const alloc = self.allocator(); + var config = try CoreConfig.load(alloc); + defer config.deinit(); + break :config try .new(alloc, &config); + }; + defer config.unref(); + + // Update the proper target. This will trigger a `confige_change` + // apprt action which will propagate the config properly to our + // property system. + switch (target) { + .app => try self.core().updateConfig( + self.rt(), + config.get(), + ), + .surface => |core| try core.updateConfig(config.get()), + } + } + pub fn render(target: apprt.Target) void { switch (target) { .app => {}, diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 0cefebc63..98c470764 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -1193,6 +1193,14 @@ pub const Surface = extern struct { return self.private().pwd; } + /// Change the configuration for this surface. + pub fn setConfig(self: *Self, config: *Config) void { + const priv = self.private(); + if (priv.config) |c| c.unref(); + priv.config = config.ref(); + self.as(gobject.Object).notifyByPspec(properties.config.impl.param_spec); + } + fn propConfig( self: *Self, _: *gobject.ParamSpec, From b011706aad44cde9c99e428dc8d85495becaeac5 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 27 Jul 2025 14:12:26 -0700 Subject: [PATCH 3/9] suppressions --- valgrind.supp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/valgrind.supp b/valgrind.supp index 7f48b580a..c80530663 100644 --- a/valgrind.supp +++ b/valgrind.supp @@ -353,8 +353,7 @@ match-leak-kinds: possible fun:*alloc fun:FcFontSet* - fun:FcFontSet* - fun:sort_in_thread.isra.0 + ... fun:fc_thread_func fun:g_thread_proxy fun:start_thread From c4de0010232ce8d5127f33322573fb34ab784f84 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 27 Jul 2025 14:27:40 -0700 Subject: [PATCH 4/9] apprt/gtk-ng: avoid reading corrupt memory in event loop --- src/apprt/gtk-ng/class/application.zig | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/apprt/gtk-ng/class/application.zig b/src/apprt/gtk-ng/class/application.zig index d27210b5c..3b4250956 100644 --- a/src/apprt/gtk-ng/class/application.zig +++ b/src/apprt/gtk-ng/class/application.zig @@ -361,11 +361,15 @@ pub const Application = extern struct { // // https://gitlab.gnome.org/GNOME/glib/-/blob/bd2ccc2f69ecfd78ca3f34ab59e42e2b462bad65/gio/gapplication.c#L2302 const priv = self.private(); - const config = priv.config.get(); - if (config.@"initial-window") switch (config.@"launched-from".?) { - .desktop, .cli => self.as(gio.Application).activate(), - .dbus, .systemd => {}, - }; + { + // We need to scope any config access because once we run our + // event loop, this can change out from underneath us. + const config = priv.config.get(); + if (config.@"initial-window") switch (config.@"launched-from".?) { + .desktop, .cli => self.as(gio.Application).activate(), + .dbus, .systemd => {}, + }; + } // If we are NOT the primary instance, then we never want to run. // This means that another instance of the GTK app is running and @@ -393,6 +397,7 @@ pub const Application = extern struct { // Check if we must quit based on the current state. const must_quit = q: { // If we are configured to always stay running, don't quit. + const config = priv.config.get(); if (!config.@"quit-after-last-window-closed") break :q false; // If the quit timer has expired, quit. From bf61f29f570208cf6e70e665e4334547c4b18f09 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 27 Jul 2025 15:07:12 -0700 Subject: [PATCH 5/9] apprt/gtk-ng: create the privateObjFieldAccessor helper to unref --- src/apprt/gtk-ng/class.zig | 78 +++++++++++++++++++ .../class/clipboard_confirmation_dialog.zig | 14 +--- src/apprt/gtk-ng/class/surface.zig | 14 +--- .../gtk-ng/class/surface_child_exited.zig | 7 +- src/apprt/gtk-ng/class/window.zig | 7 +- 5 files changed, 84 insertions(+), 36 deletions(-) diff --git a/src/apprt/gtk-ng/class.zig b/src/apprt/gtk-ng/class.zig index 427789560..dc024c5cf 100644 --- a/src/apprt/gtk-ng/class.zig +++ b/src/apprt/gtk-ng/class.zig @@ -46,6 +46,84 @@ pub fn Common( } }).private else {}; + /// A helper that can be used to create a property that reads and + /// writes a private boxed gobject field type. + /// + /// Reading the property will result in allocating a pointer and + /// setting it will free the previous pointer. + /// + /// The object class (Self) must still free the private field + /// in finalize! + pub fn privateBoxedFieldAccessor( + comptime name: []const u8, + ) gobject.ext.Accessor( + Self, + @FieldType(Private.?, name), + ) { + return .{ + .getter = &struct { + fn get(self: *Self, value: *gobject.Value) void { + gobject.ext.Value.set( + value, + @field(private(self), name), + ); + } + }.get, + .setter = &struct { + fn set(self: *Self, value: *const gobject.Value) void { + const priv = private(self); + if (@field(priv, name)) |v| { + glib.ext.destroy(v); + } + + const T = @TypeOf(@field(priv, name)); + @field( + priv, + name, + ) = gobject.ext.Value.dup(value, T); + } + }.set, + }; + } + + /// A helper that can be used to create a property that reads and + /// writes a private field gobject field type (reference counted). + /// + /// Reading the property will result in taking a reference to the + /// value and writing the property will unref the previous value. + /// + /// The object class (Self) must still free the private field + /// in finalize! + pub fn privateObjFieldAccessor( + comptime name: []const u8, + ) gobject.ext.Accessor( + Self, + @FieldType(Private.?, name), + ) { + return .{ + .getter = &struct { + fn get(self: *Self, value: *gobject.Value) void { + gobject.ext.Value.set( + value, + @field(private(self), name), + ); + } + }.get, + .setter = &struct { + fn set(self: *Self, value: *const gobject.Value) void { + const priv = private(self); + if (@field(priv, name)) |v| v.unref(); + + const T = @TypeOf(@field(priv, name)); + @field( + priv, + name, + ) = gobject.ext.Value.dup(value, T); + } + }.set, + }; + } + /// A helper that can be used to create a property that reads and /// writes a private `?[:0]const u8` field type. /// diff --git a/src/apprt/gtk-ng/class/clipboard_confirmation_dialog.zig b/src/apprt/gtk-ng/class/clipboard_confirmation_dialog.zig index 7769d8935..cb9a27444 100644 --- a/src/apprt/gtk-ng/class/clipboard_confirmation_dialog.zig +++ b/src/apprt/gtk-ng/class/clipboard_confirmation_dialog.zig @@ -59,12 +59,7 @@ pub const ClipboardConfirmationDialog = extern struct { .{ .nick = "Request", .blurb = "The clipboard request.", - .accessor = gobject.ext.privateFieldAccessor( - Self, - Private, - &Private.offset, - "request", - ), + .accessor = C.privateBoxedFieldAccessor("request"), }, ); }; @@ -78,12 +73,7 @@ pub const ClipboardConfirmationDialog = extern struct { .{ .nick = "Clipboard Contents", .blurb = "The clipboard contents being read/written.", - .accessor = gobject.ext.privateFieldAccessor( - Self, - Private, - &Private.offset, - "clipboard_contents", - ), + .accessor = C.privateObjFieldAccessor("clipboard_contents"), }, ); }; diff --git a/src/apprt/gtk-ng/class/surface.zig b/src/apprt/gtk-ng/class/surface.zig index 98c470764..bb432cf6f 100644 --- a/src/apprt/gtk-ng/class/surface.zig +++ b/src/apprt/gtk-ng/class/surface.zig @@ -50,12 +50,7 @@ pub const Surface = extern struct { .{ .nick = "Config", .blurb = "The configuration that this surface is using.", - .accessor = gobject.ext.privateFieldAccessor( - Self, - Private, - &Private.offset, - "config", - ), + .accessor = C.privateObjFieldAccessor("config"), }, ); }; @@ -89,12 +84,7 @@ pub const Surface = extern struct { .{ .nick = "Desired Font Size", .blurb = "The desired font size, only affects initialization.", - .accessor = gobject.ext.privateFieldAccessor( - Self, - Private, - &Private.offset, - "font_size_request", - ), + .accessor = C.privateBoxedFieldAccessor("font_size_request"), }, ); }; diff --git a/src/apprt/gtk-ng/class/surface_child_exited.zig b/src/apprt/gtk-ng/class/surface_child_exited.zig index 693425c09..3bf29285f 100644 --- a/src/apprt/gtk-ng/class/surface_child_exited.zig +++ b/src/apprt/gtk-ng/class/surface_child_exited.zig @@ -42,12 +42,7 @@ const SurfaceChildExitedBanner = extern struct { .{ .nick = "Data", .blurb = "The child exit data.", - .accessor = gobject.ext.privateFieldAccessor( - Self, - Private, - &Private.offset, - "data", - ), + .accessor = C.privateBoxedFieldAccessor("data"), }, ); }; diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index ac5555391..d822bfd49 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -69,12 +69,7 @@ pub const Window = extern struct { .{ .nick = "Config", .blurb = "The configuration that this surface is using.", - .accessor = gobject.ext.privateFieldAccessor( - Self, - Private, - &Private.offset, - "config", - ), + .accessor = C.privateObjFieldAccessor("config"), }, ); }; From b5a34f5f3c2e47a890e0b0ba6d76e97ca7887a9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 01:05:10 +0000 Subject: [PATCH 6/9] build(deps): bump cachix/install-nix-action from 31.5.1 to 31.5.2 Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.5.1 to 31.5.2. - [Release notes](https://github.com/cachix/install-nix-action/releases) - [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md) - [Commits](https://github.com/cachix/install-nix-action/compare/c134e4c9e34bac6cab09cf239815f9339aaaf84e...fc6e360bedc9ee72d75e701397f0bb30dce77568) --- updated-dependencies: - dependency-name: cachix/install-nix-action dependency-version: 31.5.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/nix.yml | 2 +- .github/workflows/release-pr.yml | 4 +- .github/workflows/release-tag.yml | 4 +- .github/workflows/release-tip.yml | 8 ++-- .github/workflows/test.yml | 46 +++++++++++------------ .github/workflows/update-colorschemes.yml | 2 +- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index 003a3f593..2a1c98d48 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -42,7 +42,7 @@ jobs: /nix /zig - name: Setup Nix - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 diff --git a/.github/workflows/release-pr.yml b/.github/workflows/release-pr.yml index 3b653cedd..d920b92f1 100644 --- a/.github/workflows/release-pr.yml +++ b/.github/workflows/release-pr.yml @@ -57,7 +57,7 @@ jobs: fetch-depth: 0 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -211,7 +211,7 @@ jobs: fetch-depth: 0 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index f695d08a2..ba1095896 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -89,7 +89,7 @@ jobs: /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable @@ -130,7 +130,7 @@ jobs: - name: Checkout code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 diff --git a/.github/workflows/release-tip.yml b/.github/workflows/release-tip.yml index 6440c8fe1..03f6076a3 100644 --- a/.github/workflows/release-tip.yml +++ b/.github/workflows/release-tip.yml @@ -112,7 +112,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -164,7 +164,7 @@ jobs: fetch-depth: 0 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -384,7 +384,7 @@ jobs: fetch-depth: 0 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -564,7 +564,7 @@ jobs: fetch-depth: 0 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d2a66b77a..d2a6ea8f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -77,7 +77,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -108,7 +108,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -144,7 +144,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -173,7 +173,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -206,7 +206,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -250,7 +250,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -279,7 +279,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -362,7 +362,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -516,7 +516,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -561,7 +561,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -610,7 +610,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -658,7 +658,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -678,7 +678,7 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -711,7 +711,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -739,7 +739,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -766,7 +766,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -793,7 +793,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -820,7 +820,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -847,7 +847,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -881,7 +881,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -908,7 +908,7 @@ jobs: path: | /nix /zig - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -945,7 +945,7 @@ jobs: /zig # Install Nix and use that to run our tests so our environment matches exactly. - - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + - uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 @@ -1002,7 +1002,7 @@ jobs: /nix /zig - name: Setup Nix - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 diff --git a/.github/workflows/update-colorschemes.yml b/.github/workflows/update-colorschemes.yml index 71f94131f..80d99b23f 100644 --- a/.github/workflows/update-colorschemes.yml +++ b/.github/workflows/update-colorschemes.yml @@ -29,7 +29,7 @@ jobs: /zig - name: Setup Nix - uses: cachix/install-nix-action@c134e4c9e34bac6cab09cf239815f9339aaaf84e # v31.5.1 + uses: cachix/install-nix-action@fc6e360bedc9ee72d75e701397f0bb30dce77568 # v31.5.2 with: nix_path: nixpkgs=channel:nixos-unstable - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v16 From 92c004cb25cfa6c3a09b39688802e8294eade123 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sun, 27 Jul 2025 22:05:16 -0500 Subject: [PATCH 7/9] gtk-ng: add/remove 'background' css class from window depending on opacity --- src/apprt/gtk-ng/class/window.zig | 45 ++++++++++++++++++++++++++++++ src/apprt/gtk-ng/ui/1.5/window.blp | 1 + 2 files changed, 46 insertions(+) diff --git a/src/apprt/gtk-ng/class/window.zig b/src/apprt/gtk-ng/class/window.zig index d822bfd49..ce40462f8 100644 --- a/src/apprt/gtk-ng/class/window.zig +++ b/src/apprt/gtk-ng/class/window.zig @@ -111,6 +111,23 @@ pub const Window = extern struct { }, ); }; + + pub const @"background-opaque" = struct { + pub const name = "background-opaque"; + const impl = gobject.ext.defineProperty( + name, + Self, + bool, + .{ + .nick = "Background Opaque", + .blurb = "True if the background should be opaque.", + .default = true, + .accessor = gobject.ext.typedAccessor(Self, bool, .{ + .getter = Self.getBackgroundOpaque, + }), + }, + ); + }; }; const Private = struct { @@ -209,6 +226,16 @@ pub const Window = extern struct { // Trigger our headerbar visibility to refresh self.as(gobject.Object).notifyByPspec(properties.@"headerbar-visible".impl.param_spec); + // Trigger background opacity to refresh + self.as(gobject.Object).notifyByPspec(properties.@"background-opaque".impl.param_spec); + } + + fn toggleCssClass(self: *Window, class: [:0]const u8, value: bool) void { + const widget = self.as(gtk.Widget); + if (value) + widget.addCssClass(class.ptr) + else + widget.removeCssClass(class.ptr); } /// Perform a binding action on the window's active surface. @@ -268,6 +295,12 @@ pub const Window = extern struct { return config.@"gtk-titlebar"; } + fn getBackgroundOpaque(self: *Self) bool { + const priv = self.private(); + const config = (priv.config orelse return true).get(); + return config.@"background-opacity" >= 1.0; + } + fn propConfig( _: *adw.ApplicationWindow, _: *gobject.ParamSpec, @@ -325,6 +358,16 @@ pub const Window = extern struct { action.setEnabled(@intFromBool(has_selection)); } + /// Add or remove "background" CSS class depending on if the background + /// should be opaque. + fn propBackgroundOpaque( + _: *adw.ApplicationWindow, + _: *gobject.ParamSpec, + self: *Self, + ) callconv(.c) void { + self.toggleCssClass("background", self.getBackgroundOpaque()); + } + //--------------------------------------------------------------- // Virtual methods @@ -571,6 +614,7 @@ pub const Window = extern struct { properties.config.impl, properties.debug.impl, properties.@"headerbar-visible".impl, + properties.@"background-opaque".impl, }); // Bindings @@ -587,6 +631,7 @@ pub const Window = extern struct { class.bindTemplateCallback("notify_fullscreened", &propFullscreened); class.bindTemplateCallback("notify_maximized", &propMaximized); class.bindTemplateCallback("notify_menu_active", &propMenuActive); + class.bindTemplateCallback("notify_background_opaque", &propBackgroundOpaque); // Virtual methods gobject.Object.virtual_methods.dispose.implement(class, &dispose); diff --git a/src/apprt/gtk-ng/ui/1.5/window.blp b/src/apprt/gtk-ng/ui/1.5/window.blp index 1e2345d95..a7f5d82e0 100644 --- a/src/apprt/gtk-ng/ui/1.5/window.blp +++ b/src/apprt/gtk-ng/ui/1.5/window.blp @@ -10,6 +10,7 @@ template $GhosttyWindow: Adw.ApplicationWindow { notify::config => $notify_config(); notify::fullscreened => $notify_fullscreened(); notify::maximized => $notify_maximized(); + notify::background-opaque => $notify_background_opaque(); default-width: 800; default-height: 600; // GTK4 grabs F10 input by default to focus the menubar icon. We want From 4c01d776c5356485b63d351860194057aa54322b Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sun, 27 Jul 2025 21:08:13 -0700 Subject: [PATCH 8/9] valgrind: make some GSK renderer supressions less strict --- valgrind.supp | 1 - 1 file changed, 1 deletion(-) diff --git a/valgrind.supp b/valgrind.supp index c80530663..3b074607d 100644 --- a/valgrind.supp +++ b/valgrind.supp @@ -133,7 +133,6 @@ fun:gsk_gpu_frame_do_upload_texture fun:gsk_gpu_lookup_texture ... - fun:gsk_gpu_node_processor_add_first_node fun:gsk_gpu_node_processor_process fun:gsk_gpu_frame_render fun:gsk_gpu_renderer_render From 96573917a06cde0a5c7c02d8c22aac3fd4ed10f2 Mon Sep 17 00:00:00 2001 From: "Jeffrey C. Ollie" Date: Sun, 27 Jul 2025 23:26:05 -0500 Subject: [PATCH 9/9] gtk-ng: fix up background of resize and url overlays PR #8088 had the unexpected side-effect of making the resize and url overlays transparent as well. This PR fixes that. --- src/apprt/gtk-ng/css/style.css | 4 ++-- src/apprt/gtk-ng/ui/1.2/resize-overlay.blp | 5 +++++ src/apprt/gtk-ng/ui/1.2/surface.blp | 8 +++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/apprt/gtk-ng/css/style.css b/src/apprt/gtk-ng/css/style.css index 314a96fae..4aa03c598 100644 --- a/src/apprt/gtk-ng/css/style.css +++ b/src/apprt/gtk-ng/css/style.css @@ -29,12 +29,12 @@ label.url-overlay.right { /* * GhosttySurface resize overlay */ -.size-overlay label { +label.resize-overlay { padding: 4px 8px 4px 8px; border-radius: 6px 6px 6px 6px; outline-style: solid; - outline-width: 1px; outline-color: #555555; + outline-width: 1px; } /* diff --git a/src/apprt/gtk-ng/ui/1.2/resize-overlay.blp b/src/apprt/gtk-ng/ui/1.2/resize-overlay.blp index a80b63fb3..5c4a94a8f 100644 --- a/src/apprt/gtk-ng/ui/1.2/resize-overlay.blp +++ b/src/apprt/gtk-ng/ui/1.2/resize-overlay.blp @@ -11,6 +11,11 @@ template $GhosttyResizeOverlay: Adw.Bin { // See surface.blp for why we need to wrap this. Adw.Bin { Label label { + styles [ + "background", + "resize-overlay", + ] + focusable: false; focus-on-click: false; justify: center; diff --git a/src/apprt/gtk-ng/ui/1.2/surface.blp b/src/apprt/gtk-ng/ui/1.2/surface.blp index 3bf856c48..4cbbef097 100644 --- a/src/apprt/gtk-ng/ui/1.2/surface.blp +++ b/src/apprt/gtk-ng/ui/1.2/surface.blp @@ -47,15 +47,12 @@ template $GhosttySurface: Adw.Bin { } [overlay] - $GhosttyResizeOverlay resize_overlay { - styles [ - "size-overlay", - ] - } + $GhosttyResizeOverlay resize_overlay {} [overlay] Label url_left { styles [ + "background", "url-overlay", ] @@ -73,6 +70,7 @@ template $GhosttySurface: Adw.Bin { [overlay] Label url_right { styles [ + "background", "url-overlay", ]