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}