1//! Macos screen have a y axis that goings up from the bottom of the screen and
2//! an origin at the bottom left of the main display.
3mod dispatcher;
4mod display;
5mod display_link;
6mod events;
7mod screen_capture;
8
9#[cfg(not(feature = "macos-blade"))]
10mod metal_atlas;
11#[cfg(not(feature = "macos-blade"))]
12pub mod metal_renderer;
13
14use core_video::image_buffer::CVImageBuffer;
15#[cfg(not(feature = "macos-blade"))]
16use metal_renderer as renderer;
17
18#[cfg(feature = "macos-blade")]
19use crate::platform::blade as renderer;
20
21mod attributed_string;
22
23#[cfg(feature = "font-kit")]
24mod open_type;
25
26#[cfg(feature = "font-kit")]
27mod text_system;
28
29mod platform;
30mod window;
31mod window_appearance;
32
33use crate::{DevicePixels, Pixels, Size, px, size};
34use cocoa::{
35 base::{id, nil},
36 foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger},
37};
38
39use objc::runtime::{BOOL, NO, YES};
40use std::{
41 ffi::{CStr, c_char},
42 ops::Range,
43};
44
45pub(crate) use dispatcher::*;
46pub(crate) use display::*;
47pub(crate) use display_link::*;
48pub(crate) use platform::*;
49pub(crate) use window::*;
50
51#[cfg(feature = "font-kit")]
52pub(crate) use text_system::*;
53
54/// A frame of video captured from a screen.
55pub(crate) type PlatformScreenCaptureFrame = CVImageBuffer;
56
57trait BoolExt {
58 fn to_objc(self) -> BOOL;
59}
60
61impl BoolExt for bool {
62 fn to_objc(self) -> BOOL {
63 if self { YES } else { NO }
64 }
65}
66
67trait NSStringExt {
68 unsafe fn to_str(&self) -> &str;
69}
70
71impl NSStringExt for id {
72 unsafe fn to_str(&self) -> &str {
73 unsafe {
74 let cstr = self.UTF8String();
75 if cstr.is_null() {
76 ""
77 } else {
78 CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
79 }
80 }
81 }
82}
83
84#[repr(C)]
85#[derive(Copy, Clone, Debug)]
86struct NSRange {
87 pub location: NSUInteger,
88 pub length: NSUInteger,
89}
90
91impl NSRange {
92 fn invalid() -> Self {
93 Self {
94 location: NSNotFound as NSUInteger,
95 length: 0,
96 }
97 }
98
99 fn is_valid(&self) -> bool {
100 self.location != NSNotFound as NSUInteger
101 }
102
103 fn to_range(self) -> Option<Range<usize>> {
104 if self.is_valid() {
105 let start = self.location as usize;
106 let end = start + self.length as usize;
107 Some(start..end)
108 } else {
109 None
110 }
111 }
112}
113
114impl From<Range<usize>> for NSRange {
115 fn from(range: Range<usize>) -> Self {
116 NSRange {
117 location: range.start as NSUInteger,
118 length: range.len() as NSUInteger,
119 }
120 }
121}
122
123unsafe impl objc::Encode for NSRange {
124 fn encode() -> objc::Encoding {
125 let encoding = format!(
126 "{{NSRange={}{}}}",
127 NSUInteger::encode().as_str(),
128 NSUInteger::encode().as_str()
129 );
130 unsafe { objc::Encoding::from_str(&encoding) }
131 }
132}
133
134unsafe fn ns_string(string: &str) -> id {
135 unsafe { NSString::alloc(nil).init_str(string).autorelease() }
136}
137
138impl From<NSSize> for Size<Pixels> {
139 fn from(value: NSSize) -> Self {
140 Size {
141 width: px(value.width as f32),
142 height: px(value.height as f32),
143 }
144 }
145}
146
147impl From<NSRect> for Size<Pixels> {
148 fn from(rect: NSRect) -> Self {
149 let NSSize { width, height } = rect.size;
150 size(width.into(), height.into())
151 }
152}
153
154impl From<NSRect> for Size<DevicePixels> {
155 fn from(rect: NSRect) -> Self {
156 let NSSize { width, height } = rect.size;
157 size(DevicePixels(width as i32), DevicePixels(height as i32))
158 }
159}