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