gardesk/ers / f34604f

Browse files

Switch overlay click-through from SLSSetWindowTags to SLSSetWindowEventShape

The kCGSIgnoreForEvents tag bit poisons the shared SLS connection's
SLSNewWindow path during stack-cycle recreates, dropping border
overlays on the inactive stack windows. An empty event shape achieves
the same click-through without mutating tags.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
f34604f322977aa876452baff62f3d22dfad9afd
Parents
0003875
Tree
47afeef

2 changed files

StatusFile+-
M src/main.rs 15 6
M src/skylight.rs 9 0
src/main.rsmodified
@@ -1235,12 +1235,21 @@ fn create_overlay(
12351235
         SLSFlushWindowContentRegion(cid, wid, ptr::null());
12361236
         CGContextRelease(ctx);
12371237
 
1238
-        // Click-through. Without this the overlay window swallows mouse
1239
-        // clicks and scroll-wheel/trackpad gestures inside the target
1240
-        // window's bounds. Bit 1 of the SLS tag word is kCGSIgnoreForEvents.
1241
-        // Must run AFTER drawing — see CLAUDE.md "Draw before setting tags".
1242
-        let tags: u64 = 1 << 1;
1243
-        SLSSetWindowTags(cid, wid, &tags, 64);
1238
+        // Click-through. Setting an empty event/hit-test shape makes mouse
1239
+        // events pass through the overlay to the window beneath. We use
1240
+        // SLSSetWindowEventShape rather than SLSSetWindowTags(kCGSIgnoreForEvents)
1241
+        // because tag mutation in the event-driven recreate path poisons
1242
+        // subsequent SLSNewWindow calls on the shared connection.
1243
+        // SLSSetWindowEventMask alone was insufficient on Tahoe.
1244
+        let empty = CGRect::new(0.0, 0.0, 0.0, 0.0);
1245
+        let mut empty_region: CFTypeRef = ptr::null();
1246
+        if CGSNewRegionWithRect(&empty, &mut empty_region) == kCGErrorSuccess
1247
+            && !empty_region.is_null()
1248
+        {
1249
+            SLSSetWindowEventShape(cid, wid, empty_region);
1250
+            CFRelease(empty_region);
1251
+        }
1252
+        SLSSetWindowEventMask(cid, wid, 0);
12441253
 
12451254
         Some((cid, wid, bounds, scale))
12461255
     }
src/skylight.rsmodified
@@ -199,6 +199,15 @@ unsafe extern "C" {
199199
     ) -> CGError;
200200
     pub fn SLSSetWindowResolution(cid: CGSConnectionID, wid: u32, res: f64) -> CGError;
201201
     pub fn SLSSetWindowOpacity(cid: CGSConnectionID, wid: u32, is_opaque: bool) -> CGError;
202
+    /// Mask of events the SLS window captures. Set to 0 to make the window
203
+    /// click-through (mouse events pass to the window beneath). Used by
204
+    /// border overlays so the user can still click/scroll the underlying
205
+    /// app window.
206
+    pub fn SLSSetWindowEventMask(cid: CGSConnectionID, wid: u32, mask: u32) -> CGError;
207
+    /// Hit-test/input shape. An empty region passes all mouse events
208
+    /// through to the window beneath. Equivalent to NSWindow's
209
+    /// `setIgnoresMouseEvents(true)` at the SLS layer.
210
+    pub fn SLSSetWindowEventShape(cid: CGSConnectionID, wid: u32, shape: CFTypeRef) -> CGError;
202211
     pub fn SLSSetWindowAlpha(cid: CGSConnectionID, wid: u32, alpha: f32) -> CGError;
203212
     pub fn SLSSetWindowBackgroundBlurRadius(cid: CGSConnectionID, wid: u32, radius: u32)
204213
     -> CGError;