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