Rust · 24302 bytes Raw Blame History
1 //! ers — window border renderer
2
3 mod events;
4 mod skylight;
5
6 use events::Event;
7 use skylight::*;
8 use std::collections::HashMap;
9 use std::ptr;
10 use std::sync::mpsc;
11
12 /// Per-overlay state: the connection it was created on + its wid.
13 struct Overlay {
14 cid: CGSConnectionID,
15 wid: u32,
16 }
17
18 /// Tracks overlays for target windows.
19 struct BorderMap {
20 overlays: HashMap<u32, Overlay>,
21 main_cid: CGSConnectionID,
22 own_pid: i32,
23 border_width: f64,
24 focused_wid: u32,
25 active_color: (f64, f64, f64, f64),
26 inactive_color: (f64, f64, f64, f64),
27 }
28
29 impl BorderMap {
30 fn new(cid: CGSConnectionID, own_pid: i32, border_width: f64) -> Self {
31 Self {
32 overlays: HashMap::new(),
33 main_cid: cid,
34 own_pid,
35 border_width,
36 focused_wid: 0,
37 active_color: (0.32, 0.58, 0.89, 1.0), // #5294e2
38 inactive_color: (0.35, 0.35, 0.35, 0.8), // dim gray
39 }
40 }
41
42 fn color_for(&self, target_wid: u32) -> (f64, f64, f64, f64) {
43 if target_wid == self.focused_wid { self.active_color } else { self.inactive_color }
44 }
45
46 fn is_overlay(&self, wid: u32) -> bool {
47 self.overlays.values().any(|o| o.wid == wid)
48 }
49
50 /// Add border (batch mode, uses main cid).
51 fn add_batch(&mut self, target_wid: u32) {
52 if self.overlays.contains_key(&target_wid) { return; }
53 let color = self.color_for(target_wid);
54 if let Some((cid, wid)) = create_overlay(self.main_cid, target_wid, self.border_width, color) {
55 self.overlays.insert(target_wid, Overlay { cid, wid });
56 }
57 }
58
59 /// Add border (event mode). Uses main_cid — fresh connections create
60 /// invisible windows on Tahoe.
61 fn add_fresh(&mut self, target_wid: u32) {
62 if self.overlays.contains_key(&target_wid) { return; }
63 let color = self.color_for(target_wid);
64 if let Some((cid, wid)) = create_overlay(self.main_cid, target_wid, self.border_width, color) {
65 self.overlays.insert(target_wid, Overlay { cid, wid });
66 }
67 }
68
69 fn remove(&mut self, target_wid: u32) {
70 if let Some(overlay) = self.overlays.remove(&target_wid) {
71 unsafe {
72 // Move off-screen first (most reliable hide on Tahoe)
73 let offscreen = CGPoint { x: -99999.0, y: -99999.0 };
74 SLSMoveWindow(overlay.cid, overlay.wid, &offscreen);
75 SLSSetWindowAlpha(overlay.cid, overlay.wid, 0.0);
76 SLSOrderWindow(overlay.cid, overlay.wid, 0, 0);
77 SLSReleaseWindow(overlay.cid, overlay.wid);
78 if overlay.cid != self.main_cid {
79 SLSReleaseConnection(overlay.cid);
80 }
81 }
82 }
83 }
84
85 /// Move overlay to match target's current position (no recreate).
86 fn reposition(&self, target_wid: u32) {
87 if let Some(overlay) = self.overlays.get(&target_wid) {
88 unsafe {
89 let mut bounds = CGRect::default();
90 if SLSGetWindowBounds(overlay.cid, target_wid, &mut bounds) != kCGErrorSuccess {
91 return;
92 }
93 let bw = self.border_width;
94 let origin = CGPoint {
95 x: bounds.origin.x - bw,
96 y: bounds.origin.y - bw,
97 };
98 SLSMoveWindow(overlay.cid, overlay.wid, &origin);
99 }
100 }
101 }
102
103 /// Recreate overlay at new size. Uses fresh connection.
104 fn recreate(&mut self, target_wid: u32) {
105 if !self.overlays.contains_key(&target_wid) { return; }
106 self.remove(target_wid);
107 self.add_fresh(target_wid);
108 self.subscribe_target(target_wid);
109 }
110
111 fn hide(&self, target_wid: u32) {
112 if let Some(o) = self.overlays.get(&target_wid) {
113 unsafe { SLSOrderWindow(o.cid, o.wid, 0, 0); }
114 }
115 }
116
117 fn unhide(&self, target_wid: u32) {
118 if let Some(o) = self.overlays.get(&target_wid) {
119 unsafe {
120 SLSSetWindowLevel(o.cid, o.wid, 25);
121 SLSOrderWindow(o.cid, o.wid, 1, 0);
122 }
123 }
124 }
125
126 fn apply_tags_all(&self) {
127 unsafe {
128 let tags: u64 = 1 << 1;
129 for o in self.overlays.values() {
130 SLSSetWindowTags(o.cid, o.wid, &tags, 64);
131 disable_shadow(o.wid);
132 }
133 }
134 }
135
136 fn subscribe_target(&self, target_wid: u32) {
137 unsafe {
138 SLSRequestNotificationsForWindows(self.main_cid, &target_wid, 1);
139 }
140 }
141
142 fn subscribe_all(&self) {
143 let target_wids: Vec<u32> = self.overlays.keys().copied().collect();
144 if target_wids.is_empty() { return; }
145 unsafe {
146 SLSRequestNotificationsForWindows(
147 self.main_cid,
148 target_wids.as_ptr(),
149 target_wids.len() as i32,
150 );
151 }
152 }
153
154 /// Redraw an existing overlay with a new color (no destroy/recreate).
155 fn redraw(&self, target_wid: u32) {
156 if let Some(overlay) = self.overlays.get(&target_wid) {
157 unsafe {
158 let mut bounds = CGRect::default();
159 if SLSGetWindowBounds(overlay.cid, target_wid, &mut bounds) != kCGErrorSuccess {
160 return;
161 }
162 let bw = self.border_width;
163 let ow = bounds.size.width + 2.0 * bw;
164 let oh = bounds.size.height + 2.0 * bw;
165
166 let ctx = SLWindowContextCreate(overlay.cid, overlay.wid, ptr::null());
167 if ctx.is_null() { return; }
168
169 let full = CGRect::new(0.0, 0.0, ow, oh);
170 CGContextClearRect(ctx, full);
171
172 let color = self.color_for(target_wid);
173 let stroke_rect = CGRect::new(bw / 2.0, bw / 2.0, ow - bw, oh - bw);
174 let radius = 10.0_f64;
175 let max_r = (stroke_rect.size.width.min(stroke_rect.size.height) / 2.0).max(0.0);
176 let r = radius.min(max_r);
177
178 CGContextSetRGBStrokeColor(ctx, color.0, color.1, color.2, color.3);
179 CGContextSetLineWidth(ctx, bw);
180 let path = CGPathCreateWithRoundedRect(stroke_rect, r, r, ptr::null());
181 if !path.is_null() {
182 CGContextAddPath(ctx, path);
183 CGContextStrokePath(ctx);
184 CGPathRelease(path);
185 }
186
187 CGContextFlush(ctx);
188 SLSFlushWindowContentRegion(overlay.cid, overlay.wid, ptr::null());
189 CGContextRelease(ctx);
190 }
191 }
192 }
193
194 /// Detect focused window and update border colors if focus changed.
195 /// Returns true if focus changed (callers should resubscribe).
196 fn update_focus(&mut self) -> bool {
197 let front = get_front_window(self.own_pid);
198 if front == 0 || front == self.focused_wid { return false; }
199
200 let old = self.focused_wid;
201 self.focused_wid = front;
202 eprintln!("[focus] {} -> {} (tracked={})", old, front, self.overlays.contains_key(&front));
203
204 // Recreate overlays with new colors — re-obtaining a CGContext
205 // for an existing window is unreliable on Tahoe
206 if self.overlays.contains_key(&old) {
207 self.recreate(old);
208 }
209 if self.overlays.contains_key(&front) {
210 self.recreate(front);
211 }
212 true
213 }
214 }
215
216 /// Get the front (focused) window ID using CGWindowListCopyWindowInfo.
217 /// Avoids all SLS display/space queries which poison SLSNewWindow globally.
218 fn get_front_window(own_pid: i32) -> u32 {
219 unsafe {
220 let list = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
221 if list.is_null() { return 0; }
222
223 let count = CFArrayGetCount(list);
224 let wid_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowNumber\0".as_ptr(), kCFStringEncodingUTF8);
225 let pid_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowOwnerPID\0".as_ptr(), kCFStringEncodingUTF8);
226 let layer_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowLayer\0".as_ptr(), kCFStringEncodingUTF8);
227
228 // CGWindowListCopyWindowInfo returns windows in front-to-back order.
229 // First layer-0 window not owned by us is the focused window.
230 let mut front_wid: u32 = 0;
231 for i in 0..count {
232 let dict = CFArrayGetValueAtIndex(list, i);
233 if dict.is_null() { continue; }
234
235 let mut v: CFTypeRef = ptr::null();
236
237 let mut layer: i32 = -1;
238 if CFDictionaryGetValueIfPresent(dict, layer_key as CFTypeRef, &mut v) {
239 CFNumberGetValue(v, kCFNumberSInt32Type, &mut layer as *mut _ as *mut _);
240 }
241 if layer != 0 { continue; }
242
243 let mut pid: i32 = 0;
244 if CFDictionaryGetValueIfPresent(dict, pid_key as CFTypeRef, &mut v) {
245 CFNumberGetValue(v, kCFNumberSInt32Type, &mut pid as *mut _ as *mut _);
246 }
247 if pid == own_pid { continue; }
248
249 let mut wid: u32 = 0;
250 if CFDictionaryGetValueIfPresent(dict, wid_key as CFTypeRef, &mut v) {
251 CFNumberGetValue(v, kCFNumberSInt32Type, &mut wid as *mut _ as *mut _);
252 }
253 if wid != 0 {
254 front_wid = wid;
255 break;
256 }
257 }
258
259 CFRelease(wid_key as CFTypeRef);
260 CFRelease(pid_key as CFTypeRef);
261 CFRelease(layer_key as CFTypeRef);
262 CFRelease(list);
263 front_wid
264 }
265 }
266
267 fn main() {
268 let args: Vec<String> = std::env::args().collect();
269
270 if args.get(1).is_some_and(|s| s == "--list") {
271 list_windows();
272 return;
273 }
274
275 let border_width: f64 = args
276 .iter()
277 .position(|s| s == "--width" || s == "-w")
278 .and_then(|i| args.get(i + 1)?.parse().ok())
279 .unwrap_or(4.0);
280
281 let cid = unsafe { SLSMainConnectionID() };
282 let own_pid = unsafe {
283 let mut pid: i32 = 0;
284 pid_for_task(mach_task_self(), &mut pid);
285 pid
286 };
287
288 // Event channel
289 let (tx, rx) = mpsc::channel();
290 events::init(tx, own_pid);
291 events::register(cid);
292 setup_event_port(cid);
293
294 // Discover and create borders
295 let mut borders = BorderMap::new(cid, own_pid, border_width);
296
297 if let Some(target) = args.get(1).and_then(|s| s.parse::<u32>().ok()) {
298 borders.add_batch(target);
299 } else {
300 let wids = discover_windows(cid, own_pid);
301 eprintln!("{} windows discovered", wids.len());
302 for &wid in &wids {
303 borders.add_batch(wid);
304 }
305 eprintln!("{} borders created", borders.overlays.len());
306 }
307
308 borders.subscribe_all();
309
310 if borders.update_focus() {
311 borders.subscribe_all();
312 }
313
314 eprintln!("{} overlays tracked", borders.overlays.len());
315
316 // Process events on background thread with coalescing
317 std::thread::spawn(move || {
318 use std::collections::HashSet;
319
320 // Persist across batches: windows we know about but haven't bordered yet
321 let mut pending: HashSet<u32> = HashSet::new();
322
323 loop {
324 let first = match rx.recv() {
325 Ok(e) => e,
326 Err(_) => break,
327 };
328
329 std::thread::sleep(std::time::Duration::from_millis(150));
330
331 let mut events = vec![first];
332 while let Ok(e) = rx.try_recv() {
333 events.push(e);
334 }
335
336 let mut moved: HashSet<u32> = HashSet::new();
337 let mut resized: HashSet<u32> = HashSet::new();
338 let mut destroyed: HashSet<u32> = HashSet::new();
339 let mut needs_resubscribe = false;
340
341 for event in events {
342 match event {
343 Event::Move(wid) => {
344 if !borders.is_overlay(wid) {
345 moved.insert(wid);
346 }
347 }
348 Event::Resize(wid) => {
349 if !borders.is_overlay(wid) {
350 resized.insert(wid);
351 }
352 }
353 Event::Close(wid) | Event::Destroy(wid) => {
354 if !borders.is_overlay(wid) {
355 destroyed.insert(wid);
356 pending.remove(&wid);
357 }
358 }
359 Event::Create(wid) => {
360 if !borders.is_overlay(wid) {
361 pending.insert(wid);
362 borders.subscribe_target(wid);
363 }
364 }
365 Event::Hide(wid) => borders.hide(wid),
366 Event::Unhide(wid) => borders.unhide(wid),
367 Event::FrontChange => {
368 needs_resubscribe = true; // focus change may need resubscribe
369 }
370 Event::SpaceChange => {}
371 }
372 }
373
374 // Destroys
375 for wid in &destroyed {
376 borders.remove(*wid);
377 }
378
379 // Promote ALL pending creates that weren't destroyed
380 // (the 150ms debounce is enough for tarmac to position them)
381 let ready: Vec<u32> = pending.iter()
382 .filter(|wid| !destroyed.contains(wid))
383 .copied()
384 .collect();
385 // Filter overlapping creates: if two windows overlap, keep smaller one
386 let mut bounds_map: Vec<(u32, CGRect)> = Vec::new();
387 for &wid in &ready {
388 unsafe {
389 let mut b = CGRect::default();
390 SLSGetWindowBounds(borders.main_cid, wid, &mut b);
391 bounds_map.push((wid, b));
392 }
393 }
394
395 // If two new windows overlap closely, skip the larger one (container)
396 let mut skip: std::collections::HashSet<u32> = HashSet::new();
397 for i in 0..bounds_map.len() {
398 for j in (i+1)..bounds_map.len() {
399 let (wid_a, a) = &bounds_map[i];
400 let (wid_b, b) = &bounds_map[j];
401 // Check if centers are close (within 30px)
402 let cx_a = a.origin.x + a.size.width / 2.0;
403 let cy_a = a.origin.y + a.size.height / 2.0;
404 let cx_b = b.origin.x + b.size.width / 2.0;
405 let cy_b = b.origin.y + b.size.height / 2.0;
406 if (cx_a - cx_b).abs() < 30.0 && (cy_a - cy_b).abs() < 30.0 {
407 // Skip the larger one
408 let area_a = a.size.width * a.size.height;
409 let area_b = b.size.width * b.size.height;
410 if area_a > area_b {
411 skip.insert(*wid_a);
412 } else {
413 skip.insert(*wid_b);
414 }
415 }
416 }
417 }
418
419 for &wid in &ready {
420 pending.remove(&wid);
421 if !skip.contains(&wid) {
422 borders.add_fresh(wid);
423 needs_resubscribe = true;
424 }
425 }
426
427 // Moves and resizes: recreate at new position/size
428 let changed: HashSet<u32> = moved.union(&resized).copied().collect();
429 for wid in &changed {
430 if borders.overlays.contains_key(wid) {
431 borders.recreate(*wid);
432 needs_resubscribe = true;
433 }
434 }
435
436 // Update focus (detects front window, recreates borders if changed)
437 if borders.update_focus() {
438 needs_resubscribe = true;
439 }
440
441 // Re-subscribe ALL tracked windows (SLSRequestNotificationsForWindows replaces, not appends)
442 if needs_resubscribe || !destroyed.is_empty() {
443 borders.subscribe_all();
444 }
445 }
446 });
447
448 unsafe { CFRunLoopRun() };
449 }
450
451 fn setup_event_port(cid: CGSConnectionID) {
452 unsafe {
453 let mut port: u32 = 0;
454 if SLSGetEventPort(cid, &mut port) != kCGErrorSuccess { return; }
455 let cf_port = CFMachPortCreateWithPort(ptr::null(), port, drain_events as *const _, ptr::null(), false);
456 if cf_port.is_null() { return; }
457 _CFMachPortSetOptions(cf_port, 0x40);
458 let source = CFMachPortCreateRunLoopSource(ptr::null(), cf_port, 0);
459 if !source.is_null() {
460 CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
461 CFRelease(source);
462 }
463 CFRelease(cf_port);
464 }
465 }
466
467 unsafe extern "C" fn drain_events(_: CFMachPortRef, _: *mut std::ffi::c_void, _: i64, _: *mut std::ffi::c_void) {
468 unsafe {
469 let cid = SLSMainConnectionID();
470 let mut ev = SLEventCreateNextEvent(cid);
471 while !ev.is_null() {
472 CFRelease(ev as CFTypeRef);
473 ev = SLEventCreateNextEvent(cid);
474 }
475 }
476 }
477
478 fn discover_windows(cid: CGSConnectionID, own_pid: i32) -> Vec<u32> {
479 unsafe {
480 let list = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
481 if list.is_null() { return vec![]; }
482
483 let count = CFArrayGetCount(list);
484 let wid_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowNumber\0".as_ptr(), kCFStringEncodingUTF8);
485 let pid_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowOwnerPID\0".as_ptr(), kCFStringEncodingUTF8);
486 let layer_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowLayer\0".as_ptr(), kCFStringEncodingUTF8);
487
488 let mut wids = Vec::new();
489 for i in 0..count {
490 let dict = CFArrayGetValueAtIndex(list, i);
491 if dict.is_null() { continue; }
492
493 let mut v: CFTypeRef = ptr::null();
494 let mut wid: u32 = 0;
495 if CFDictionaryGetValueIfPresent(dict, wid_key as CFTypeRef, &mut v) {
496 CFNumberGetValue(v, kCFNumberSInt32Type, &mut wid as *mut _ as *mut _);
497 }
498 if wid == 0 { continue; }
499
500 let mut pid: i32 = 0;
501 if CFDictionaryGetValueIfPresent(dict, pid_key as CFTypeRef, &mut v) {
502 CFNumberGetValue(v, kCFNumberSInt32Type, &mut pid as *mut _ as *mut _);
503 }
504 if pid == own_pid { continue; }
505
506 let mut layer: i32 = -1;
507 if CFDictionaryGetValueIfPresent(dict, layer_key as CFTypeRef, &mut v) {
508 CFNumberGetValue(v, kCFNumberSInt32Type, &mut layer as *mut _ as *mut _);
509 }
510 if layer != 0 { continue; }
511
512 wids.push(wid);
513 }
514
515 CFRelease(wid_key as CFTypeRef);
516 CFRelease(pid_key as CFTypeRef);
517 CFRelease(layer_key as CFTypeRef);
518 CFRelease(list);
519 wids
520 }
521 }
522
523 fn create_overlay(
524 cid: CGSConnectionID,
525 target_wid: u32,
526 border_width: f64,
527 color: (f64, f64, f64, f64),
528 ) -> Option<(CGSConnectionID, u32)> {
529 unsafe {
530 let mut bounds = CGRect::default();
531 let rc = SLSGetWindowBounds(cid, target_wid, &mut bounds);
532 if rc != kCGErrorSuccess {
533 eprintln!("[create_overlay] SLSGetWindowBounds failed for wid={target_wid} rc={rc}");
534 return None;
535 }
536 if bounds.size.width < 10.0 || bounds.size.height < 10.0 {
537 eprintln!("[create_overlay] wid={target_wid} too small: {}x{}", bounds.size.width, bounds.size.height);
538 return None;
539 }
540
541 let bw = border_width;
542 let ow = bounds.size.width + 2.0 * bw;
543 let oh = bounds.size.height + 2.0 * bw;
544 let ox = bounds.origin.x - bw;
545 let oy = bounds.origin.y - bw;
546
547 let frame = CGRect::new(0.0, 0.0, ow, oh);
548 let mut region: CFTypeRef = ptr::null();
549 CGSNewRegionWithRect(&frame, &mut region);
550 if region.is_null() {
551 eprintln!("[create_overlay] CGSNewRegionWithRect failed for wid={target_wid}");
552 return None;
553 }
554
555 let mut wid: u32 = 0;
556 SLSNewWindow(cid, 2, ox as f32, oy as f32, region, &mut wid);
557 CFRelease(region);
558 if wid == 0 {
559 eprintln!("[create_overlay] SLSNewWindow returned 0 for target={target_wid} cid={cid}");
560 return None;
561 }
562
563 eprintln!("[create_overlay] created overlay wid={wid} for target={target_wid} color=({:.2},{:.2},{:.2},{:.2})",
564 color.0, color.1, color.2, color.3);
565
566 SLSSetWindowResolution(cid, wid, 2.0);
567 SLSSetWindowOpacity(cid, wid, false);
568 SLSSetWindowLevel(cid, wid, 25);
569 SLSOrderWindow(cid, wid, 1, 0);
570
571 // Draw border (point coordinates)
572 let ctx = SLWindowContextCreate(cid, wid, ptr::null());
573 if ctx.is_null() {
574 eprintln!("[create_overlay] SLWindowContextCreate returned null for overlay wid={wid}");
575 SLSReleaseWindow(cid, wid);
576 return None;
577 }
578
579 let full = CGRect::new(0.0, 0.0, ow, oh);
580 CGContextClearRect(ctx, full);
581
582 let stroke_rect = CGRect::new(bw / 2.0, bw / 2.0, ow - bw, oh - bw);
583 let radius = 10.0_f64;
584 let max_r = (stroke_rect.size.width.min(stroke_rect.size.height) / 2.0).max(0.0);
585 let r = radius.min(max_r);
586
587 CGContextSetRGBStrokeColor(ctx, color.0, color.1, color.2, color.3);
588 CGContextSetLineWidth(ctx, bw);
589 let path = CGPathCreateWithRoundedRect(stroke_rect, r, r, ptr::null());
590 if !path.is_null() {
591 CGContextAddPath(ctx, path);
592 CGContextStrokePath(ctx);
593 CGPathRelease(path);
594 }
595
596 CGContextFlush(ctx);
597 SLSFlushWindowContentRegion(cid, wid, ptr::null());
598 CGContextRelease(ctx);
599
600 Some((cid, wid))
601 }
602 }
603
604 fn list_windows() {
605 let cid = unsafe { SLSMainConnectionID() };
606 unsafe {
607 let list = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
608 if list.is_null() { return; }
609 let count = CFArrayGetCount(list);
610 let wid_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowNumber\0".as_ptr(), kCFStringEncodingUTF8);
611 let layer_key = CFStringCreateWithCString(ptr::null(), b"kCGWindowLayer\0".as_ptr(), kCFStringEncodingUTF8);
612
613 eprintln!("{:>6} {:>8} {:>8} {:>6} {:>6}", "wid", "x", "y", "w", "h");
614 for i in 0..count {
615 let dict = CFArrayGetValueAtIndex(list, i);
616 if dict.is_null() { continue; }
617
618 let mut v: CFTypeRef = ptr::null();
619 let mut wid: u32 = 0;
620 let mut layer: i32 = -1;
621 if CFDictionaryGetValueIfPresent(dict, wid_key as CFTypeRef, &mut v) {
622 CFNumberGetValue(v, kCFNumberSInt32Type, &mut wid as *mut _ as *mut _);
623 }
624 if CFDictionaryGetValueIfPresent(dict, layer_key as CFTypeRef, &mut v) {
625 CFNumberGetValue(v, kCFNumberSInt32Type, &mut layer as *mut _ as *mut _);
626 }
627 if layer != 0 || wid == 0 { continue; }
628
629 let mut bounds = CGRect::default();
630 SLSGetWindowBounds(cid, wid, &mut bounds);
631 eprintln!("{wid:>6} {:>8.0} {:>8.0} {:>6.0} {:>6.0}",
632 bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
633 }
634 CFRelease(wid_key as CFTypeRef);
635 CFRelease(layer_key as CFTypeRef);
636 CFRelease(list);
637 }
638 }
639
640 unsafe fn disable_shadow(wid: u32) {
641 let density: i64 = 0;
642 let density_cf = CFNumberCreate(ptr::null(), kCFNumberCFIndexType, &density as *const _ as *const _);
643 let key = CFStringCreateWithCString(ptr::null(), b"com.apple.WindowShadowDensity\0".as_ptr(), kCFStringEncodingUTF8);
644 let keys = [key as CFTypeRef];
645 let values = [density_cf as CFTypeRef];
646 let dict = CFDictionaryCreate(
647 ptr::null(), keys.as_ptr(), values.as_ptr(), 1,
648 &kCFTypeDictionaryKeyCallBacks as *const _ as *const _,
649 &kCFTypeDictionaryValueCallBacks as *const _ as *const _,
650 );
651 SLSWindowSetShadowProperties(wid, dict);
652 CFRelease(dict);
653 CFRelease(density_cf);
654 CFRelease(key as CFTypeRef);
655 }
656