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 display;
8mod display_link;
9mod events;
10mod keyboard;
11mod pasteboard;
12mod system_notifications;
13
14#[cfg(feature = "screen-capture")]
15mod screen_capture;
16
17use gpui_apple::metal_renderer as renderer;
18
19pub mod metal_renderer {
20    pub use gpui_apple::metal_renderer::{PathRasterizationVertex, PathSprite, SurfaceBounds};
21
22    #[cfg(any(test, feature = "bench-support", feature = "test-support"))]
23    pub use gpui_apple::metal_renderer::MetalHeadlessRenderer;
24}
25
26mod platform;
27mod window;
28mod window_appearance;
29
30use objc2::{
31    Encode, Encoding, RefEncode,
32    rc::Retained,
33    runtime::{AnyObject, Bool},
34};
35use objc2_foundation::{NSNotFound, NSString, NSUInteger};
36use std::{ffi::CStr, ops::Range};
37
38pub(crate) use display::*;
39pub(crate) use display_link::*;
40pub(crate) use gpui_apple::{AppleActivity, AppleDispatcher, main_thread_marker};
41pub(crate) use keyboard::*;
42pub(crate) use platform::*;
43pub(crate) use window::*;
44
45pub use platform::MacPlatform;
46
47trait BoolExt {
48    fn to_objc(self) -> Bool;
49}
50
51impl BoolExt for bool {
52    fn to_objc(self) -> Bool {
53        Bool::new(self)
54    }
55}
56
57trait NSStringExt {
58    unsafe fn to_str(&self) -> &str;
59}
60
61impl NSStringExt for *mut AnyObject {
62    unsafe fn to_str(&self) -> &str {
63        unsafe {
64            let Some(string) = self.cast::<NSString>().as_ref() else {
65                return "";
66            };
67            let cstr = string.UTF8String();
68            if cstr.is_null() {
69                ""
70            } else {
71                CStr::from_ptr(cstr).to_str().unwrap()
72            }
73        }
74    }
75}
76
77#[repr(C)]
78#[derive(Copy, Clone, Debug)]
79struct NSRange {
80    pub location: NSUInteger,
81    pub length: NSUInteger,
82}
83
84impl NSRange {
85    fn invalid() -> Self {
86        Self {
87            location: NSNotFound as NSUInteger,
88            length: 0,
89        }
90    }
91
92    fn is_valid(&self) -> bool {
93        self.location != NSNotFound as NSUInteger
94    }
95
96    fn to_range(self) -> Option<Range<usize>> {
97        if self.is_valid() {
98            let start = self.location;
99            let end = start + self.length;
100            Some(start..end)
101        } else {
102            None
103        }
104    }
105}
106
107impl From<Range<usize>> for NSRange {
108    fn from(range: Range<usize>) -> Self {
109        NSRange {
110            location: range.start as NSUInteger,
111            length: range.len() as NSUInteger,
112        }
113    }
114}
115
116unsafe impl Encode for NSRange {
117    const ENCODING: Encoding = objc2_foundation::NSRange::ENCODING;
118}
119
120unsafe impl RefEncode for NSRange {
121    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
122}
123
124fn ns_string(string: &str) -> *mut AnyObject {
125    Retained::autorelease_ptr(NSString::from_str(string)).cast()
126}