Skip to main content

open_gpui_macos/
gpui_macos.rs

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}