Rust · 17804 bytes Raw Blame History
1 //! FFI bindings for SkyLight, CoreGraphics, and CoreFoundation.
2 //!
3 //! These are private/undocumented APIs used by the WindowServer compositor.
4 //! Signatures sourced from JankyBorders and yabai reverse engineering.
5
6 #![allow(non_snake_case, non_upper_case_globals, dead_code)]
7
8 use std::ffi::c_void;
9
10 // --- Core types ---
11
12 pub type CGError = i32;
13 pub type CGSConnectionID = i32;
14 pub const kCGErrorSuccess: CGError = 0;
15 pub const kCGBackingStoreBuffered: i32 = 2;
16
17 #[repr(C)]
18 #[derive(Debug, Clone, Copy, Default)]
19 pub struct CGPoint {
20 pub x: f64,
21 pub y: f64,
22 }
23
24 #[repr(C)]
25 #[derive(Debug, Clone, Copy, Default)]
26 pub struct CGSize {
27 pub width: f64,
28 pub height: f64,
29 }
30
31 #[repr(C)]
32 #[derive(Debug, Clone, Copy, Default)]
33 pub struct CGRect {
34 pub origin: CGPoint,
35 pub size: CGSize,
36 }
37
38 impl CGRect {
39 pub fn new(x: f64, y: f64, w: f64, h: f64) -> Self {
40 Self {
41 origin: CGPoint { x, y },
42 size: CGSize {
43 width: w,
44 height: h,
45 },
46 }
47 }
48
49 pub fn inset(&self, dx: f64, dy: f64) -> Self {
50 Self::new(
51 self.origin.x + dx,
52 self.origin.y + dy,
53 self.size.width - 2.0 * dx,
54 self.size.height - 2.0 * dy,
55 )
56 }
57 }
58
59 #[repr(C)]
60 #[derive(Debug, Clone, Copy)]
61 pub struct CGAffineTransform {
62 pub a: f64,
63 pub b: f64,
64 pub c: f64,
65 pub d: f64,
66 pub tx: f64,
67 pub ty: f64,
68 }
69
70 impl Default for CGAffineTransform {
71 fn default() -> Self {
72 Self::IDENTITY
73 }
74 }
75
76 impl CGAffineTransform {
77 pub const IDENTITY: Self = Self {
78 a: 1.0,
79 b: 0.0,
80 c: 0.0,
81 d: 1.0,
82 tx: 0.0,
83 ty: 0.0,
84 };
85 }
86
87 #[repr(C)]
88 #[derive(Debug, Clone, Copy)]
89 pub struct ProcessSerialNumber {
90 pub high: u32,
91 pub low: u32,
92 }
93
94 // --- Opaque CF types ---
95
96 pub type CFTypeRef = *const c_void;
97 pub type CFArrayRef = *const c_void;
98 pub type CFStringRef = *const c_void;
99 pub type CFDictionaryRef = *const c_void;
100 pub type CFNumberRef = *const c_void;
101 pub type CFMachPortRef = *const c_void;
102 pub type CFRunLoopSourceRef = *const c_void;
103 pub type CFRunLoopRef = *const c_void;
104 pub type CFRunLoopTimerRef = *const c_void;
105 pub type CFAllocatorRef = *const c_void;
106
107 #[repr(C)]
108 pub struct CFRunLoopTimerContext {
109 pub version: i64,
110 pub info: *mut c_void,
111 pub retain: Option<extern "C" fn(*const c_void) -> *const c_void>,
112 pub release: Option<extern "C" fn(*const c_void)>,
113 pub copy_description: Option<extern "C" fn(*const c_void) -> CFStringRef>,
114 }
115 pub type CGContextRef = *mut c_void;
116 pub type CGPathRef = *const c_void;
117 pub type CGMutablePathRef = *mut c_void;
118 pub type CGEventRef = *const c_void;
119 pub type CGDisplayModeRef = *const c_void;
120
121 // CF constants
122 pub const kCFNumberSInt32Type: i32 = 3;
123 pub const kCFNumberSInt64Type: i32 = 4;
124 pub const kCFNumberCFIndexType: i32 = 14;
125 pub const kCFBooleanFalse: *const c_void = std::ptr::null(); // placeholder
126
127 // --- SkyLight / CGS functions ---
128
129 unsafe extern "C" {
130 // Connection
131 pub fn SLSMainConnectionID() -> CGSConnectionID;
132 pub fn SLSNewConnection(zero: i32, cid: *mut CGSConnectionID) -> CGError;
133 pub fn SLSReleaseConnection(cid: CGSConnectionID) -> CGError;
134
135 // Event port
136 pub fn SLSGetEventPort(cid: CGSConnectionID, port_out: *mut u32) -> CGError;
137 pub fn SLEventCreateNextEvent(cid: CGSConnectionID) -> CGEventRef;
138 pub fn _CFMachPortSetOptions(mach_port: CFMachPortRef, options: i32);
139
140 // Event registration
141 pub fn SLSRegisterNotifyProc(
142 handler: *const c_void,
143 event: u32,
144 context: *mut c_void,
145 ) -> CGError;
146
147 pub fn SLSRequestNotificationsForWindows(
148 cid: CGSConnectionID,
149 window_list: *const u32,
150 window_count: i32,
151 ) -> CGError;
152
153 // Window queries
154 pub fn SLSGetWindowOwner(
155 cid: CGSConnectionID,
156 wid: u32,
157 out_cid: *mut CGSConnectionID,
158 ) -> CGError;
159 pub fn SLSConnectionGetPID(cid: CGSConnectionID, pid: *mut i32) -> CGError;
160 pub fn SLSGetWindowBounds(cid: CGSConnectionID, wid: u32, frame: *mut CGRect) -> CGError;
161 pub fn SLSWindowIsOrderedIn(cid: CGSConnectionID, wid: u32, shown: *mut bool) -> CGError;
162 pub fn SLSGetWindowLevel(cid: CGSConnectionID, wid: u32, level_out: *mut i64) -> CGError;
163
164 // Window iterator queries
165 pub fn SLSWindowQueryWindows(
166 cid: CGSConnectionID,
167 windows: CFArrayRef,
168 options: u32,
169 ) -> CFTypeRef;
170 pub fn SLSWindowQueryResultCopyWindows(window_query: CFTypeRef) -> CFTypeRef;
171 pub fn SLSWindowIteratorGetCount(iterator: CFTypeRef) -> i32;
172 pub fn SLSWindowIteratorAdvance(iterator: CFTypeRef) -> bool;
173 pub fn SLSWindowIteratorGetParentID(iterator: CFTypeRef) -> u32;
174 pub fn SLSWindowIteratorGetWindowID(iterator: CFTypeRef) -> u32;
175 pub fn SLSWindowIteratorGetTags(iterator: CFTypeRef) -> u64;
176 pub fn SLSWindowIteratorGetAttributes(iterator: CFTypeRef) -> u64;
177 pub fn SLSWindowIteratorGetLevel(iterator: CFTypeRef) -> i32;
178
179 // Window lifecycle
180 pub fn SLSNewWindow(
181 cid: CGSConnectionID,
182 window_type: i32,
183 x: f32,
184 y: f32,
185 region: CFTypeRef,
186 wid_out: *mut u32,
187 ) -> CGError;
188 /// JankyBorders' `SLSNewWindowWithOpaqueShapeAndContext` — creates a
189 /// window with a custom hit-test shape and tag bits applied at
190 /// creation. Used so that screenshot-exclusion tag bit 9 lands on
191 /// the window before macOS Tahoe's compositor classifies it; setting
192 /// the bit post-creation is unreliable on Tahoe.
193 /// Reference: .refs/JankyBorders/src/misc/window.h:239
194 /// Reference: .refs/JankyBorders/src/misc/extern.h
195 pub fn SLSNewWindowWithOpaqueShapeAndContext(
196 cid: CGSConnectionID,
197 window_type: i32,
198 region: CFTypeRef,
199 opaque_shape: CFTypeRef,
200 options: i32,
201 tags: *mut u64,
202 x: f32,
203 y: f32,
204 tag_size: i32,
205 wid_out: *mut u32,
206 context: *mut std::ffi::c_void,
207 ) -> CGError;
208 pub fn SLSReleaseWindow(cid: CGSConnectionID, wid: u32) -> CGError;
209
210 // Window properties
211 pub fn SLSSetWindowTags(
212 cid: CGSConnectionID,
213 wid: u32,
214 tags: *const u64,
215 tag_size: i32,
216 ) -> CGError;
217 pub fn SLSClearWindowTags(
218 cid: CGSConnectionID,
219 wid: u32,
220 tags: *const u64,
221 tag_size: i32,
222 ) -> CGError;
223 pub fn CGSGetWindowTags(
224 cid: CGSConnectionID,
225 wid: u32,
226 tags: *mut u64,
227 tag_size: i32,
228 ) -> CGError;
229 pub fn SLSSetWindowShape(
230 cid: CGSConnectionID,
231 wid: u32,
232 x_offset: f32,
233 y_offset: f32,
234 shape: CFTypeRef,
235 ) -> CGError;
236 pub fn SLSSetWindowResolution(cid: CGSConnectionID, wid: u32, res: f64) -> CGError;
237 pub fn SLSSetWindowOpacity(cid: CGSConnectionID, wid: u32, is_opaque: bool) -> CGError;
238 /// SLS-level NSWindow.sharingType. Values: 0 = None (excluded from
239 /// screen capture / picker / recording — equivalent to
240 /// kCGWindowSharingNone), 1 = ReadOnly, 2 = ReadWrite.
241 pub fn SLSSetWindowSharingState(cid: CGSConnectionID, wid: u32, state: u32) -> CGError;
242 pub fn SLSGetWindowSharingState(
243 cid: CGSConnectionID,
244 wid: u32,
245 state_out: *mut u32,
246 ) -> CGError;
247 /// Mask of events the SLS window captures. Set to 0 to make the window
248 /// click-through (mouse events pass to the window beneath).
249 pub fn SLSSetWindowEventMask(cid: CGSConnectionID, wid: u32, mask: u32) -> CGError;
250 /// Hit-test/input shape. An empty region passes all mouse events
251 /// through to the window beneath. Equivalent to NSWindow's
252 /// `setIgnoresMouseEvents(true)` at the SLS layer.
253 pub fn SLSSetWindowEventShape(cid: CGSConnectionID, wid: u32, shape: CFTypeRef) -> CGError;
254 pub fn SLSSetWindowAlpha(cid: CGSConnectionID, wid: u32, alpha: f32) -> CGError;
255 pub fn SLSSetWindowBackgroundBlurRadius(cid: CGSConnectionID, wid: u32, radius: u32)
256 -> CGError;
257 pub fn SLSSetWindowLevel(cid: CGSConnectionID, wid: u32, level: i32) -> CGError;
258 pub fn SLSOrderWindow(cid: CGSConnectionID, wid: u32, mode: i32, relative_to: u32) -> CGError;
259 pub fn SLSMoveWindow(cid: CGSConnectionID, wid: u32, point: *const CGPoint) -> CGError;
260
261 // Shadow
262 pub fn SLSWindowSetShadowProperties(wid: u32, properties: CFDictionaryRef) -> CGError;
263
264 // Drawing context
265 pub fn SLWindowContextCreate(
266 cid: CGSConnectionID,
267 wid: u32,
268 options: CFDictionaryRef,
269 ) -> CGContextRef;
270
271 // Transactions
272 pub fn SLSTransactionCreate(cid: CGSConnectionID) -> CFTypeRef;
273 pub fn SLSTransactionSetWindowLevel(transaction: CFTypeRef, wid: u32, level: i32) -> CGError;
274 pub fn SLSTransactionMoveWindowWithGroup(
275 transaction: CFTypeRef,
276 wid: u32,
277 point: CGPoint,
278 ) -> CGError;
279 pub fn SLSTransactionOrderWindow(
280 transaction: CFTypeRef,
281 wid: u32,
282 order: i32,
283 rel_wid: u32,
284 ) -> CGError;
285 pub fn SLSTransactionSetWindowAlpha(transaction: CFTypeRef, wid: u32, alpha: f32) -> CGError;
286 pub fn SLSTransactionSetWindowTransform(
287 transaction: CFTypeRef,
288 wid: u32,
289 not: i32,
290 important: i32,
291 transform: CGAffineTransform,
292 ) -> CGError;
293 pub fn SLSTransactionCommit(transaction: CFTypeRef, synchronous: i32) -> CGError;
294 pub fn SLSTransactionSetWindowShape(
295 transaction: CFTypeRef,
296 wid: u32,
297 x_offset: f32,
298 y_offset: f32,
299 shape: CFTypeRef,
300 ) -> CGError;
301
302 // Flicker suppression
303 pub fn SLSDisableUpdate(cid: CGSConnectionID) -> CGError;
304 pub fn SLSReenableUpdate(cid: CGSConnectionID) -> CGError;
305 pub fn SLSFlushWindowContentRegion(
306 cid: CGSConnectionID,
307 wid: u32,
308 dirty: *const c_void,
309 ) -> CGError;
310
311 // Space management
312 pub fn SLSCopySpacesForWindows(
313 cid: CGSConnectionID,
314 selector: i32,
315 window_list: CFArrayRef,
316 ) -> CFArrayRef;
317 pub fn SLSCopyManagedDisplays(cid: CGSConnectionID) -> CFArrayRef;
318 pub fn SLSCopyManagedDisplaySpaces(cid: CGSConnectionID) -> CFArrayRef;
319 pub fn SLSCopyManagedDisplayForWindow(cid: CGSConnectionID, wid: u32) -> CFStringRef;
320 pub fn SLSManagedDisplayGetCurrentSpace(cid: CGSConnectionID, uuid: CFStringRef) -> u64;
321 pub fn SLSCopyActiveMenuBarDisplayIdentifier(cid: CGSConnectionID) -> CFStringRef;
322 pub fn SLSMoveWindowsToManagedSpace(
323 cid: CGSConnectionID,
324 window_list: CFArrayRef,
325 sid: u64,
326 ) -> CGError;
327
328 // Window enumeration
329 pub fn SLSCopyWindowsWithOptionsAndTags(
330 cid: CGSConnectionID,
331 owner: u32,
332 spaces: CFArrayRef,
333 options: u32,
334 set_tags: *const u64,
335 clear_tags: *const u64,
336 ) -> CFArrayRef;
337
338 // Front process detection
339 pub fn _SLPSGetFrontProcess(psn: *mut ProcessSerialNumber) -> i32;
340 pub fn SLSGetConnectionIDForPSN(
341 cid: CGSConnectionID,
342 psn: *mut ProcessSerialNumber,
343 psn_cid: *mut CGSConnectionID,
344 ) -> CGError;
345
346 // Region
347 pub fn CGSNewRegionWithRect(rect: *const CGRect, region: *mut CFTypeRef) -> CGError;
348 }
349
350 // --- CoreGraphics drawing ---
351
352 // --- CGWindowList (public CoreGraphics API) ---
353
354 pub const kCGWindowListOptionOnScreenOnly: u32 = 1 << 0;
355 pub const kCGWindowListOptionAll: u32 = 0;
356 pub const kCGNullWindowID: u32 = 0;
357
358 unsafe extern "C" {
359 pub fn CGWindowListCopyWindowInfo(option: u32, relative_to: u32) -> CFArrayRef;
360 pub fn CGGetDisplaysWithPoint(
361 point: CGPoint,
362 max_displays: u32,
363 displays: *mut u32,
364 count: *mut u32,
365 ) -> CGError;
366 pub fn CGDisplayCopyDisplayMode(display: u32) -> CGDisplayModeRef;
367 pub fn CGDisplayModeGetWidth(mode: CGDisplayModeRef) -> usize;
368 pub fn CGDisplayModeGetHeight(mode: CGDisplayModeRef) -> usize;
369 pub fn CGDisplayModeGetPixelWidth(mode: CGDisplayModeRef) -> usize;
370 pub fn CGDisplayModeGetPixelHeight(mode: CGDisplayModeRef) -> usize;
371 pub fn CFDictionaryGetValueIfPresent(
372 dict: CFDictionaryRef,
373 key: CFTypeRef,
374 value_out: *mut CFTypeRef,
375 ) -> bool;
376 pub fn CFStringCreateWithCString(
377 alloc: CFAllocatorRef,
378 c_str: *const u8,
379 encoding: u32,
380 ) -> CFStringRef;
381 }
382
383 pub const kCFStringEncodingUTF8: u32 = 0x0800_0100;
384
385 // --- CoreGraphics drawing ---
386
387 unsafe extern "C" {
388 pub fn CGContextSetRGBStrokeColor(ctx: CGContextRef, r: f64, g: f64, b: f64, a: f64);
389 pub fn CGContextSetRGBFillColor(ctx: CGContextRef, r: f64, g: f64, b: f64, a: f64);
390 pub fn CGContextSetLineWidth(ctx: CGContextRef, width: f64);
391 pub fn CGContextClearRect(ctx: CGContextRef, rect: CGRect);
392 pub fn CGContextEOFillPath(ctx: CGContextRef);
393 pub fn CGContextAddPath(ctx: CGContextRef, path: CGPathRef);
394 pub fn CGContextStrokePath(ctx: CGContextRef);
395 pub fn CGContextFillPath(ctx: CGContextRef);
396 pub fn CGContextFlush(ctx: CGContextRef);
397 pub fn CGContextRelease(ctx: CGContextRef);
398 pub fn CGContextSaveGState(ctx: CGContextRef);
399 pub fn CGContextRestoreGState(ctx: CGContextRef);
400 pub fn CGContextSetInterpolationQuality(ctx: CGContextRef, quality: i32);
401 pub fn CGContextClip(ctx: CGContextRef);
402 pub fn CGContextEOClip(ctx: CGContextRef);
403 pub fn CGPathCreateWithRoundedRect(
404 rect: CGRect,
405 rx: f64,
406 ry: f64,
407 transform: *const CGAffineTransform,
408 ) -> CGPathRef;
409 pub fn CGPathCreateMutable() -> CGMutablePathRef;
410 pub fn CGPathAddRoundedRect(
411 path: CGMutablePathRef,
412 transform: *const CGAffineTransform,
413 rect: CGRect,
414 rx: f64,
415 ry: f64,
416 );
417 pub fn CGPathAddRect(path: CGMutablePathRef, transform: *const CGAffineTransform, rect: CGRect);
418 pub fn CGPathAddPath(
419 path: CGMutablePathRef,
420 transform: *const CGAffineTransform,
421 other: CGPathRef,
422 );
423 pub fn CGPathRelease(path: CGPathRef);
424 }
425
426 // --- CoreFoundation ---
427
428 unsafe extern "C" {
429 pub fn CFRelease(cf: CFTypeRef);
430 pub fn CFRetain(cf: CFTypeRef) -> CFTypeRef;
431
432 pub fn CFArrayGetCount(array: CFArrayRef) -> i64;
433 pub fn CFArrayGetValueAtIndex(array: CFArrayRef, idx: i64) -> CFTypeRef;
434 pub fn CFArrayCreate(
435 allocator: CFAllocatorRef,
436 values: *const CFTypeRef,
437 count: i64,
438 callbacks: *const c_void,
439 ) -> CFArrayRef;
440
441 pub fn CFNumberCreate(
442 allocator: CFAllocatorRef,
443 the_type: i32,
444 value_ptr: *const c_void,
445 ) -> CFNumberRef;
446 pub fn CFNumberGetValue(number: CFNumberRef, the_type: i32, value_ptr: *mut c_void) -> bool;
447 pub fn CFNumberGetType(number: CFNumberRef) -> i32;
448
449 pub fn CFDictionaryCreate(
450 allocator: CFAllocatorRef,
451 keys: *const CFTypeRef,
452 values: *const CFTypeRef,
453 count: i64,
454 key_callbacks: *const c_void,
455 value_callbacks: *const c_void,
456 ) -> CFDictionaryRef;
457 pub fn CFDictionaryGetValue(dict: CFDictionaryRef, key: CFTypeRef) -> CFTypeRef;
458
459 pub fn CFMachPortCreateWithPort(
460 allocator: CFAllocatorRef,
461 port: u32,
462 callback: *const c_void,
463 context: *const c_void,
464 should_free: bool,
465 ) -> CFMachPortRef;
466
467 pub fn CFMachPortCreateRunLoopSource(
468 allocator: CFAllocatorRef,
469 port: CFMachPortRef,
470 order: i64,
471 ) -> CFRunLoopSourceRef;
472
473 pub fn CFRunLoopGetCurrent() -> CFRunLoopRef;
474 pub fn CFRunLoopGetMain() -> CFRunLoopRef;
475 pub fn CFRunLoopAddSource(rl: CFRunLoopRef, source: CFRunLoopSourceRef, mode: CFStringRef);
476 pub fn CFRunLoopRun();
477 pub fn CFRunLoopStop(rl: CFRunLoopRef);
478 pub fn CFRunLoopWakeUp(rl: CFRunLoopRef);
479
480 pub fn CFRunLoopTimerCreate(
481 allocator: CFAllocatorRef,
482 fire_date: f64,
483 interval: f64,
484 flags: u64,
485 order: i64,
486 callout: extern "C" fn(*mut c_void, *mut c_void),
487 context: *mut CFRunLoopTimerContext,
488 ) -> CFRunLoopTimerRef;
489 pub fn CFRunLoopAddTimer(rl: CFRunLoopRef, timer: CFRunLoopTimerRef, mode: CFStringRef);
490 pub fn CFAbsoluteTimeGetCurrent() -> f64;
491
492 pub static kCFAllocatorDefault: CFAllocatorRef;
493 pub static kCFTypeDictionaryKeyCallBacks: c_void;
494 pub static kCFTypeDictionaryValueCallBacks: c_void;
495 pub static kCFTypeArrayCallBacks: c_void;
496 pub static kCFRunLoopDefaultMode: CFStringRef;
497 }
498
499 // --- macOS process ---
500
501 unsafe extern "C" {
502 pub fn getpid() -> i32;
503 pub fn pid_for_task(task: u32, pid: *mut i32) -> i32;
504 pub static mach_task_self_: u32;
505 }
506
507 // --- CGDisplay hotplug callback ---
508
509 unsafe extern "C" {
510 pub fn CGDisplayRegisterReconfigurationCallback(
511 callback: Option<
512 unsafe extern "C" fn(display: u32, flags: u32, user_info: *mut std::ffi::c_void),
513 >,
514 user_info: *mut std::ffi::c_void,
515 ) -> i32;
516 }
517
518 pub fn mach_task_self() -> u32 {
519 unsafe { mach_task_self_ }
520 }
521
522 // --- Helper: create CFArray of CFNumbers ---
523
524 pub unsafe fn cfarray_of_cfnumbers(
525 values: *const c_void,
526 size: usize,
527 count: i32,
528 num_type: i32,
529 ) -> CFArrayRef {
530 unsafe {
531 let mut temp: Vec<CFNumberRef> = Vec::with_capacity(count as usize);
532 for i in 0..count {
533 let ptr = (values as *const u8).add(size * i as usize) as *const c_void;
534 temp.push(CFNumberCreate(std::ptr::null(), num_type, ptr));
535 }
536 let array = CFArrayCreate(
537 std::ptr::null(),
538 temp.as_ptr() as *const CFTypeRef,
539 count as i64,
540 &kCFTypeArrayCallBacks as *const _,
541 );
542 for n in &temp {
543 CFRelease(*n);
544 }
545 array
546 }
547 }
548