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