Skip to main content

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;
13mod system_notifications;
14
15#[cfg(feature = "screen-capture")]
16mod screen_capture;
17
18use gpui_apple::metal_renderer as renderer;
19
20pub mod metal_renderer {
21    pub use gpui_apple::metal_renderer::{PathRasterizationVertex, PathSprite, SurfaceBounds};
22
23    #[cfg(any(test, feature = "bench-support", feature = "test-support"))]
24    pub use gpui_apple::metal_renderer::MetalHeadlessRenderer;
25}
26
27#[cfg(feature = "font-kit")]
28mod open_type;
29
30#[cfg(feature = "font-kit")]
31mod text_system;
32
33mod platform;
34mod window;
35mod window_appearance;
36
37use cocoa::{
38    base::{id, nil},
39    foundation::{NSAutoreleasePool, NSNotFound, 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
58pub use platform::MacPlatform;
59
60trait BoolExt {
61    fn to_objc(self) -> BOOL;
62}
63
64impl BoolExt for bool {
65    fn to_objc(self) -> BOOL {
66        if self { YES } else { NO }
67    }
68}
69
70trait NSStringExt {
71    unsafe fn to_str(&self) -> &str;
72}
73
74impl NSStringExt for id {
75    unsafe fn to_str(&self) -> &str {
76        unsafe {
77            let cstr = self.UTF8String();
78            if cstr.is_null() {
79                ""
80            } else {
81                CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
82            }
83        }
84    }
85}
86
87#[repr(C)]
88#[derive(Copy, Clone, Debug)]
89struct NSRange {
90    pub location: NSUInteger,
91    pub length: NSUInteger,
92}
93
94impl NSRange {
95    fn invalid() -> Self {
96        Self {
97            location: NSNotFound as NSUInteger,
98            length: 0,
99        }
100    }
101
102    fn is_valid(&self) -> bool {
103        self.location != NSNotFound as NSUInteger
104    }
105
106    fn to_range(self) -> Option<Range<usize>> {
107        if self.is_valid() {
108            let start = self.location as usize;
109            let end = start + self.length as usize;
110            Some(start..end)
111        } else {
112            None
113        }
114    }
115}
116
117impl From<Range<usize>> for NSRange {
118    fn from(range: Range<usize>) -> Self {
119        NSRange {
120            location: range.start as NSUInteger,
121            length: range.len() as NSUInteger,
122        }
123    }
124}
125
126unsafe impl objc::Encode for NSRange {
127    fn encode() -> objc::Encoding {
128        let encoding = format!(
129            "{{NSRange={}{}}}",
130            NSUInteger::encode().as_str(),
131            NSUInteger::encode().as_str()
132        );
133        unsafe { objc::Encoding::from_str(&encoding) }
134    }
135}
136
137/// Allow NSString::alloc use here because it sets autorelease
138#[allow(clippy::disallowed_methods)]
139unsafe fn ns_string(string: &str) -> id {
140    unsafe { NSString::alloc(nil).init_str(string).autorelease() }
141}