@@ -3,21 +3,24 @@ const std = @import("std");
33const Allocator = std .mem .Allocator ;
44
55const gtk = @import ("gtk" );
6+ const Window = @import ("../winproto.zig" ).Window ;
67
78pub const Region = struct {
89 slices : std .ArrayList (Slice ),
910
1011 /// A rectangular slice of the blur region.
1112 // Marked `extern` since we want to be able to use this in X11 directly,
12- // and we use `c_long`s as, while XLib *says* they should be 32 bit integers,
13- // in actuality they are architecture-dependent. I love legacy cruft
1413 pub const Slice = extern struct {
15- x : c_long ,
16- y : c_long ,
17- width : c_long ,
18- height : c_long ,
14+ x : Pos ,
15+ y : Pos ,
16+ width : Pos ,
17+ height : Pos ,
1918 };
2019
20+ // X11 compatibility. Ideally this should just be an `i32` like Wayland,
21+ // but XLib sucks
22+ const Pos = c_long ;
23+
2124 pub const empty : Region = .{
2225 .slices = .empty ,
2326 };
@@ -30,48 +33,45 @@ pub const Region = struct {
3033 self .slices .deinit (alloc );
3134 }
3235
33- // Calculate the blur regions for a window.
36+ // Calculate the blur region for a window.
3437 //
3538 // Since we have rounded corners by default, we need to carve out the
3639 // pixels on each corner to avoid the "korners bug".
37- // (cf. https://github.com/cutefishos/fishui/blob/41d4ba194063a3c7fff4675619b57e6ac0504f06/src/platforms/linux/blurhelper/windowblur.cpp#L134)
38- pub fn calcForWindow (alloc : Allocator , window : * gtk.Window ) Allocator.Error ! Region {
39- const native = window .as (gtk .Native );
40+ pub fn calcForWindow (window : * Window ) Allocator.Error ! Region {
41+ const native = window .apprt_window .as (gtk .Native );
4042 const surface = native .getSurface () orelse return .empty ;
4143
42- var slices : std .ArrayList (Slice ) = .empty ;
43- errdefer slices .deinit (alloc );
44-
45- // Calculate the primary blur region
46- // (the one that covers most of the screen).
47- // It's easier to do this inside a vector since we have to scale
48- // everything by the scale factor anyways.
49-
5044 // NOTE(pluiedev): CSDs are a f--king mistake.
5145 // Please, GNOME, stop this nonsense of making a window ~30% bigger
5246 // internally than how they really are just for your shadows and
5347 // rounded corners and all that fluff. Please. I beg of you.
54- var x : f64 = 0 ;
55- var y : f64 = 0 ;
56- native .getSurfaceTransform (& x , & y );
48+ const x : Pos , const y : Pos = off : {
49+ var x : f64 = 0 ;
50+ var y : f64 = 0 ;
51+ native .getSurfaceTransform (& x , & y );
52+ break :off .{ @intFromFloat (x ), @intFromFloat (y ) };
53+ };
5754
58- var width : f64 = @floatFromInt ( surface .getWidth ());
59- var height : f64 = @floatFromInt ( surface .getHeight ());
55+ var width = @as ( Pos , surface .getWidth ());
56+ var height = @as ( Pos , surface .getHeight ());
6057
6158 // Trim off the offsets. Be careful not to get negative.
62- width = @max (0 , width - x * 2 );
63- height = @max (0 , height - y * 2 );
59+ width -= x * 2 ;
60+ height -= y * 2 ;
61+ if (width <= 0 or height <= 0 ) return .empty ;
6462
65- // TODO: Add more regions to mitigate the "korners bug".
66- try slices .append (alloc , .{
67- .x = @intFromFloat (x ),
68- .y = @intFromFloat (y ),
69- .width = @intFromFloat (width ),
70- .height = @intFromFloat (height ),
71- });
63+ // Empirically determined.
64+ const radius : Pos = if (window .clientSideDecorationEnabled ()) 12 else 0 ;
7265
7366 return .{
74- .slices = slices ,
67+ .slices = try approxRoundedRect (
68+ window .alloc ,
69+ x ,
70+ y ,
71+ width ,
72+ height ,
73+ radius ,
74+ ),
7575 };
7676 }
7777
@@ -83,4 +83,61 @@ pub const Region = struct {
8383 }
8484 return true ;
8585 }
86+
87+ /// Approximate a rounded rectangle with many smaller rectangles.
88+ fn approxRoundedRect (
89+ alloc : Allocator ,
90+ x : Pos ,
91+ y : Pos ,
92+ width : Pos ,
93+ height : Pos ,
94+ radius : Pos ,
95+ ) Allocator.Error ! std. ArrayList (Slice ) {
96+ const r_f : f32 = @floatFromInt (radius );
97+
98+ var slices : std .ArrayList (Slice ) = .empty ;
99+ errdefer slices .deinit (alloc );
100+
101+ // Add the central rectangle
102+ try slices .append (alloc , .{
103+ .x = x ,
104+ .y = y + radius ,
105+ .width = width ,
106+ .height = height - 2 * radius ,
107+ });
108+
109+ // Add the corner rows. This is honestly quite cursed.
110+ var row : Pos = 0 ;
111+ while (row < radius ) : (row += 1 ) {
112+ // y distance from this row to the center corner circle
113+ const dy = @as (f32 , @floatFromInt (radius - row )) - 0.5 ;
114+
115+ // x distance - as given by the definition of a circle
116+ const dx = @sqrt (r_f * r_f - dy * dy );
117+
118+ // How much each row should be offset, rounded to an integer
119+ const row_x : Pos = @intFromFloat (r_f - dx + 0.5 );
120+
121+ // Remove the offset from both ends
122+ const row_w = width - 2 * row_x ;
123+
124+ // Top slice
125+ try slices .append (alloc , .{
126+ .x = x + row_x ,
127+ .y = y + row ,
128+ .width = row_w ,
129+ .height = 1 ,
130+ });
131+
132+ // Bottom slice
133+ try slices .append (alloc , .{
134+ .x = x + row_x ,
135+ .y = y + height - 1 - row ,
136+ .width = row_w ,
137+ .height = 1 ,
138+ });
139+ }
140+
141+ return slices ;
142+ }
86143};
0 commit comments