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