gardesk/ers / cd9587f

Browse files

Exclude overlays from screenshots via SLS tag bit 9

Sets tag bits (1<<1) | (1<<9) on every overlay window: bit 1 is
kCGSIgnoreForEvents (click-through), bit 9 hides the window from
ScreenCaptureKit, the screenshot picker, and screen recordings.
Mirrors JankyBorders&#39; approach (.refs/JankyBorders/src/border.c:290
and .refs/JankyBorders/src/misc/window.h:266).

Tags are now set BEFORE SLWindowContextCreate / drawing, which is the
critical difference from the prior tag-based attempt that poisoned
SLSNewWindow on stack-cycle recreates. Removes the now-redundant
SLSSetWindowEventShape/Mask, SLSSetWindowSharingState, and
SLSSetWindowClientPerceivedType bindings.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
cd9587f96bedc37cd8bd887715fc5815094f4834
Parents
24073c1
Tree
d0fedce

2 changed files

StatusFile+-
M src/main.rs 13 22
M src/skylight.rs 0 25
src/main.rsmodified
@@ -1227,6 +1227,19 @@ fn create_overlay(
12271227
         );
12281228
 
12291229
         SLSSetWindowResolution(cid, wid, scale);
1230
+
1231
+        // Tag bit 1 (kCGSIgnoreForEvents) makes the overlay click/scroll
1232
+        // through; tag bit 9 hides it from ScreenCaptureKit (cmd+shift+4
1233
+        // + space, screen recordings, the picker). Mirrors JankyBorders'
1234
+        // ordering: tags MUST be set before SLWindowContextCreate /
1235
+        // drawing — setting them post-draw poisons subsequent SLSNewWindow
1236
+        // calls on the shared connection during stack-cycle recreates.
1237
+        // tag_size 64 (0x40) is the SLS-documented length.
1238
+        let set_tags: u64 = (1u64 << 1) | (1u64 << 9);
1239
+        let clear_tags: u64 = 0;
1240
+        SLSSetWindowTags(cid, wid, &set_tags, 64);
1241
+        SLSClearWindowTags(cid, wid, &clear_tags, 64);
1242
+
12301243
         SLSSetWindowOpacity(cid, wid, false);
12311244
         SLSSetWindowLevel(cid, wid, 0);
12321245
         SLSOrderWindow(cid, wid, 1, target_wid);
@@ -1243,28 +1256,6 @@ fn create_overlay(
12431256
         SLSFlushWindowContentRegion(cid, wid, ptr::null());
12441257
         CGContextRelease(ctx);
12451258
 
1246
-        // Click-through. Setting an empty event/hit-test shape makes mouse
1247
-        // events pass through the overlay to the window beneath. We use
1248
-        // SLSSetWindowEventShape rather than SLSSetWindowTags(kCGSIgnoreForEvents)
1249
-        // because tag mutation in the event-driven recreate path poisons
1250
-        // subsequent SLSNewWindow calls on the shared connection.
1251
-        // SLSSetWindowEventMask alone was insufficient on Tahoe.
1252
-        let empty = CGRect::new(0.0, 0.0, 0.0, 0.0);
1253
-        let mut empty_region: CFTypeRef = ptr::null();
1254
-        if CGSNewRegionWithRect(&empty, &mut empty_region) == kCGErrorSuccess
1255
-            && !empty_region.is_null()
1256
-        {
1257
-            SLSSetWindowEventShape(cid, wid, empty_region);
1258
-            CFRelease(empty_region);
1259
-        }
1260
-        SLSSetWindowEventMask(cid, wid, 0);
1261
-
1262
-        // Capture-exclusion advisories. Tahoe's screen-capture picker
1263
-        // ignores both for SLS overlays but they're harmless and may help
1264
-        // capture clients that do honor them.
1265
-        SLSSetWindowSharingState(cid, wid, 0);
1266
-        SLSSetWindowClientPerceivedType(cid, wid, 2);
1267
-
12681259
         Some((cid, wid, bounds, scale))
12691260
     }
12701261
 }
src/skylight.rsmodified
@@ -199,31 +199,6 @@ 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;
211
-    /// NSWindowSharingType for the SLS window: 0 = None (excluded from
212
-    /// screen capture / picker / recording), 1 = ReadOnly, 2 = ReadWrite.
213
-    /// Tahoe's exported symbol is `SLSSetWindowSharingState` (not `Type`).
214
-    /// Setting 0 makes the overlay invisible to ScreenCaptureKit, the
215
-    /// cmd+shift+4 + space picker, etc., so user screenshots fall through
216
-    /// to the underlying app window.
217
-    pub fn SLSSetWindowSharingState(cid: CGSConnectionID, wid: u32, state: u32) -> CGError;
218
-    /// Marks the SLS window as a non-standard "perceived type" so that
219
-    /// screen-capture clients can choose to skip it. Yabai/skhd use this
220
-    /// to keep borders out of screenshots without poisoning SLSNewWindow
221
-    /// (unlike tag bits). Type 2 = "popup", 13/14 = system overlays.
222
-    pub fn SLSSetWindowClientPerceivedType(
223
-        cid: CGSConnectionID,
224
-        wid: u32,
225
-        kind: u32,
226
-    ) -> CGError;
227202
     pub fn SLSSetWindowAlpha(cid: CGSConnectionID, wid: u32, alpha: f32) -> CGError;
228203
     pub fn SLSSetWindowBackgroundBlurRadius(cid: CGSConnectionID, wid: u32, radius: u32)
229204
     -> CGError;