1#![cfg(target_os = "macos")]
2//! macOS platform implementation for GPUI.
3//!
4//! macOS screens have a y axis that goes up from the bottom of the screen and
5//! an origin at the bottom left of the main display.
6
7mod dispatcher;
8mod display;
9mod display_link;
10mod events;
11mod keyboard;
12mod pasteboard;
13
14#[cfg(feature = "screen-capture")]
15mod screen_capture;
16
17mod metal_atlas;
18pub mod metal_renderer;
19
20use metal_renderer as renderer;
21
22#[cfg(feature = "font-kit")]
23mod open_type;
24
25#[cfg(feature = "font-kit")]
26mod text_system;
27
28mod platform;
29mod window;
30mod window_appearance;
31
32use cocoa::{
33 base::{id, nil},
34 foundation::{NSAutoreleasePool, NSNotFound, NSString, NSUInteger},
35};
36
37use objc::runtime::{BOOL, NO, YES};
38use std::{
39 ffi::{CStr, c_char},
40 ops::Range,
41};
42
43pub(crate) use dispatcher::*;
44pub(crate) use display::*;
45pub(crate) use display_link::*;
46pub(crate) use keyboard::*;
47pub(crate) use platform::*;
48pub(crate) use window::*;
49
50#[cfg(feature = "font-kit")]
51pub(crate) use text_system::*;
52
53pub use platform::MacPlatform;
54
55trait BoolExt {
56 fn to_objc(self) -> BOOL;
57}
58
59impl BoolExt for bool {
60 fn to_objc(self) -> BOOL {
61 if self { YES } else { NO }
62 }
63}
64
65trait NSStringExt {
66 unsafe fn to_str(&self) -> &str;
67}
68
69impl NSStringExt for id {
70 unsafe fn to_str(&self) -> &str {
71 unsafe {
72 let cstr = self.UTF8String();
73 if cstr.is_null() {
74 ""
75 } else {
76 CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
77 }
78 }
79 }
80}
81
82#[repr(C)]
83#[derive(Copy, Clone, Debug)]
84struct NSRange {
85 pub location: NSUInteger,
86 pub length: NSUInteger,
87}
88
89impl NSRange {
90 fn invalid() -> Self {
91 Self {
92 location: NSNotFound as NSUInteger,
93 length: 0,
94 }
95 }
96
97 fn is_valid(&self) -> bool {
98 self.location != NSNotFound as NSUInteger
99 }
100
101 fn to_range(self) -> Option<Range<usize>> {
102 if self.is_valid() {
103 let start = self.location as usize;
104 let end = start + self.length as usize;
105 Some(start..end)
106 } else {
107 None
108 }
109 }
110}
111
112impl From<Range<usize>> for NSRange {
113 fn from(range: Range<usize>) -> Self {
114 NSRange {
115 location: range.start as NSUInteger,
116 length: range.len() as NSUInteger,
117 }
118 }
119}
120
121unsafe impl objc::Encode for NSRange {
122 fn encode() -> objc::Encoding {
123 let encoding = format!(
124 "{{NSRange={}{}}}",
125 NSUInteger::encode().as_str(),
126 NSUInteger::encode().as_str()
127 );
128 unsafe { objc::Encoding::from_str(&encoding) }
129 }
130}
131
132/// Allow NSString::alloc use here because it sets autorelease
133#[allow(clippy::disallowed_methods)]
134unsafe fn ns_string(string: &str) -> id {
135 unsafe { NSString::alloc(nil).init_str(string).autorelease() }
136}