diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index d8e64a980..5fcb0d42b 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -281,6 +281,15 @@ pub fn init(self: *Window, app: *App) !void { .detail = "is-active", }, ); + _ = gobject.Object.signals.notify.connect( + self.window, + *Window, + gtkWindowUpdateScaleFactor, + self, + .{ + .detail = "scale-factor", + }, + ); // If Adwaita is enabled and is older than 1.4.0 we don't have the tab overview and so we // need to stick the headerbar into the content box. @@ -784,6 +793,24 @@ fn gtkWindowNotifyIsActive( } } +fn gtkWindowUpdateScaleFactor( + _: *adw.ApplicationWindow, + _: *gobject.ParamSpec, + self: *Window, +) callconv(.c) void { + // On some platforms (namely X11) we need to refresh our appearance when + // the scale factor changes. In theory this could be more fine-grained as + // a full refresh could be expensive, but a) this *should* be rare, and + // b) quite noticeable visual bugs would occur if this is not present. + self.winproto.syncAppearance() catch |err| { + log.err( + "failed to sync appearance after scale factor has been updated={}", + .{err}, + ); + return; + }; +} + // Note: we MUST NOT use the GtkButton parameter because gtkActionNewTab // sends an undefined value. fn gtkTabNewClick(_: *gtk.Button, self: *Window) callconv(.c) void { diff --git a/src/apprt/gtk/winproto/x11.zig b/src/apprt/gtk/winproto/x11.zig index 6d6950f74..c2b6bf416 100644 --- a/src/apprt/gtk/winproto/x11.zig +++ b/src/apprt/gtk/winproto/x11.zig @@ -219,13 +219,12 @@ pub const Window = struct { pub fn resizeEvent(self: *Window) !void { // The blur region must update with window resizes - const gtk_widget = self.gtk_window.as(gtk.Widget); - self.blur_region.width = gtk_widget.getWidth(); - self.blur_region.height = gtk_widget.getHeight(); try self.syncBlur(); } pub fn syncAppearance(self: *Window) !void { + // The user could have toggled between CSDs and SSDs, + // therefore we need to recalculate the blur region offset. self.blur_region = blur: { // NOTE(pluiedev): CSDs are a f--king mistake. // Please, GNOME, stop this nonsense of making a window ~30% bigger @@ -236,6 +235,11 @@ pub const Window = struct { self.gtk_window.as(gtk.Native).getSurfaceTransform(&x, &y); + // Transform surface coordinates to device coordinates. + const scale: f64 = @floatFromInt(self.gtk_window.as(gtk.Widget).getScaleFactor()); + x *= scale; + y *= scale; + break :blur .{ .x = @intFromFloat(x), .y = @intFromFloat(y), @@ -265,6 +269,13 @@ pub const Window = struct { // and I think it's not really noticeable enough to justify the effort. // (Wayland also has this visual artifact anyway...) + const gtk_widget = self.gtk_window.as(gtk.Widget); + + // Transform surface coordinates to device coordinates. + const scale = self.gtk_window.as(gtk.Widget).getScaleFactor(); + self.blur_region.width = gtk_widget.getWidth() * scale; + self.blur_region.height = gtk_widget.getHeight() * scale; + const blur = self.config.background_blur; log.debug("set blur={}, window xid={}, region={}", .{ blur,