Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@
.lazy = true,
},
.wayland_protocols = .{
.url = "https://deps.files.ghostty.org/wayland-protocols-258d8f88f2c8c25a830c6316f87d23ce1a0f12d9.tar.gz",
.hash = "N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
.url = "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Freedesktop has terrible reliability, so when this is good to go let me know and I'll fix this before we merge.

I approve otherwise.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good idea to push the zip to S3 in any case since the ext-bg-effect commit will likely be merged regardless of the other two

.hash = "N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
.lazy = true,
},
.plasma_wayland_protocols = .{
Expand Down
5 changes: 5 additions & 0 deletions build.zig.zon.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions build.zig.zon.nix

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions build.zig.zon.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions flatpak/zig-packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@
"dest": "vendor/p/N-V-__8AAKw-DAAaV8bOAAGqA0-oD7o-HNIlPFYKRXSPT03S",
"sha256": "5cedcadde81b75e60f23e5e83b5dd2b8eb4efb9f8f79bd7a347d148aeb0530f8"
},
{
"type": "archive",
"url": "https://gitlab.freedesktop.org/wayland/wayland-protocols/-/archive/1.47/wayland-protocols-1.47.tar.gz",
"dest": "vendor/p/N-V-__8AAFdWDwA0ktbNUi9pFBHCRN4weXIgIfCrVjfGxqgA",
"sha256": "dd2df14ab5f41038257aaedcc4b5fb9ac0ee018f3f0f94af9097028e60d33223"
},
{
"type": "archive",
"url": "https://deps.files.ghostty.org/wuffs-122037b39d577ec2db3fd7b2130e7b69ef6cc1807d68607a7c232c958315d381b5cd.tar.gz",
Expand Down
32 changes: 10 additions & 22 deletions src/apprt/gtk/class/window.zig
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,11 @@ pub const Window = extern struct {

// We initialize our windowing protocol to none because we can't
// actually initialize this until we get realized.
priv.winproto = .none;
priv.winproto = .{
.alloc = Application.default().allocator(),
.apprt_window = self,
.inner = .none,
};

// Add our dev CSS class if we're in debug mode.
if (comptime build_config.is_debug) {
Expand Down Expand Up @@ -1005,14 +1009,13 @@ pub const Window = extern struct {
self.syncAppearance();
}

fn propGdkSurfaceHeight(
fn propGdkSurfaceDims(
_: *gdk.Surface,
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
// X11 needs to fix blurring on resize, but winproto implementations
// could do anything.
self.private().winproto.resizeEvent() catch |err| {
// Update the background blur
self.private().winproto.updateBlur() catch |err| {
log.warn(
"winproto resize event failed error={}",
.{err},
Expand Down Expand Up @@ -1045,21 +1048,6 @@ pub const Window = extern struct {
};
}

fn propGdkSurfaceWidth(
_: *gdk.Surface,
_: *gobject.ParamSpec,
self: *Self,
) callconv(.c) void {
// X11 needs to fix blurring on resize, but winproto implementations
// could do anything.
self.private().winproto.resizeEvent() catch |err| {
log.warn(
"winproto resize event failed error={}",
.{err},
);
};
}

fn propFullscreened(
_: *adw.ApplicationWindow,
_: *gobject.ParamSpec,
Expand Down Expand Up @@ -1216,14 +1204,14 @@ pub const Window = extern struct {
_ = gobject.Object.signals.notify.connect(
gdk_surface,
*Self,
propGdkSurfaceWidth,
propGdkSurfaceDims,
self,
.{ .detail = "width" },
);
_ = gobject.Object.signals.notify.connect(
gdk_surface,
*Self,
propGdkSurfaceHeight,
propGdkSurfaceDims,
self,
.{ .detail = "height" },
);
Expand Down
104 changes: 74 additions & 30 deletions src/apprt/gtk/winproto.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const std = @import("std");
const build_options = @import("build_options");
const Allocator = std.mem.Allocator;

const gtk = @import("gtk");
const gdk = @import("gdk");

const Config = @import("../../config.zig").Config;
Expand All @@ -12,6 +13,7 @@ const ApprtWindow = @import("class/window.zig").Window;
pub const noop = @import("winproto/noop.zig");
pub const x11 = @import("winproto/x11.zig");
pub const wayland = @import("winproto/wayland.zig");
const blur = @import("winproto/blur.zig");

pub const Protocol = enum {
none,
Expand Down Expand Up @@ -86,69 +88,111 @@ pub const App = union(Protocol) {
/// really "Surface"-specific state. But Ghostty uses the term "Surface"
/// heavily to mean something completely different, so we use "Window" here
/// to better match what it generally maps to in the Ghostty codebase.
pub const Window = union(Protocol) {
none: noop.Window,
wayland: if (build_options.wayland) wayland.Window else noop.Window,
x11: if (build_options.x11) x11.Window else noop.Window,
pub const Window = struct {
alloc: Allocator,

apprt_window: *ApprtWindow,

// Remember the current blur region to avoid redundant X11 property updates.
// Redundant property updates seem to cause some visual glitches
// with some window managers: https://github.com/ghostty-org/ghostty/pull/8075
blur_region: blur.Region = .empty,

inner: Inner,

const Inner = union(Protocol) {
none: noop.Window,
wayland: if (build_options.wayland) wayland.Window else noop.Window,
x11: if (build_options.x11) x11.Window else noop.Window,
};

pub fn init(
alloc: Allocator,
app: *App,
apprt_window: *ApprtWindow,
) !Window {
return switch (app.*) {
inline else => |*v, tag| {
inline for (@typeInfo(Window).@"union".fields) |field| {
if (comptime std.mem.eql(
u8,
field.name,
@tagName(tag),
)) return @unionInit(
Window,
field.name,
try field.type.init(
alloc,
v,
apprt_window,
),
);
}
},
const inner = inner: {
switch (app.*) {
inline else => |*v, tag| {
inline for (@typeInfo(Inner).@"union".fields) |field| {
if (comptime std.mem.eql(
u8,
field.name,
@tagName(tag),
)) break :inner @unionInit(
Inner,
field.name,
try field.type.init(
alloc,
v,
apprt_window,
),
);
}
},
}
};

return .{
.alloc = alloc,
.apprt_window = apprt_window,
.inner = inner,
};
}

pub fn deinit(self: *Window, alloc: Allocator) void {
switch (self.*) {
self.blur_region.deinit(alloc);

switch (self.inner) {
inline else => |*v| v.deinit(alloc),
}
}

pub fn resizeEvent(self: *Window) !void {
switch (self.*) {
inline else => |*v| try v.resizeEvent(),
pub fn updateBlur(self: *Window) !void {
// Update the blur region in response to the resize.
const config = if (self.apprt_window.getConfig()) |v| v.get() else return;

// When blur is disabled, remove the property if it was previously set
const blur_config = config.@"background-blur";

if (!blur_config.enabled()) {
self.blur_region.clear();
} else {
var new_region: blur.Region = try .calcForWindow(self);
errdefer new_region.deinit(self.alloc);

if (!new_region.eql(self.blur_region)) {
self.blur_region.deinit(self.alloc);
self.blur_region = new_region;
}
}

switch (self.inner) {
inline else => |*v| try v.setBlur(self.blur_region),
}
}

pub fn syncAppearance(self: *Window) !void {
switch (self.*) {
try self.updateBlur();
switch (self.inner) {
inline else => |*v| try v.syncAppearance(),
}
}

pub fn clientSideDecorationEnabled(self: Window) bool {
return switch (self) {
return switch (self.inner) {
inline else => |v| v.clientSideDecorationEnabled(),
};
}

pub fn addSubprocessEnv(self: *Window, env: *std.process.EnvMap) !void {
switch (self.*) {
switch (self.inner) {
inline else => |*v| try v.addSubprocessEnv(env),
}
}

pub fn setUrgent(self: *Window, urgent: bool) !void {
switch (self.*) {
switch (self.inner) {
inline else => |*v| try v.setUrgent(urgent),
}
}
Expand Down
Loading