mac.rs

  1//! Macos screen have a y axis that goings up from the bottom of the screen and
  2//! an origin at the bottom left of the main display.
  3mod dispatcher;
  4mod display;
  5mod display_link;
  6mod events;
  7mod keyboard;
  8
  9#[cfg(feature = "screen-capture")]
 10mod screen_capture;
 11
 12#[cfg(not(feature = "macos-blade"))]
 13mod metal_atlas;
 14#[cfg(not(feature = "macos-blade"))]
 15pub mod metal_renderer;
 16
 17use core_video::image_buffer::CVImageBuffer;
 18#[cfg(not(feature = "macos-blade"))]
 19use metal_renderer as renderer;
 20
 21#[cfg(feature = "macos-blade")]
 22use crate::platform::blade as renderer;
 23
 24mod attributed_string;
 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
 36use crate::{DevicePixels, Pixels, Size, px, size};
 37use cocoa::{
 38    base::{id, nil},
 39    foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, 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
 58/// A frame of video captured from a screen.
 59pub(crate) type PlatformScreenCaptureFrame = CVImageBuffer;
 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
138unsafe fn ns_string(string: &str) -> id {
139    unsafe { NSString::alloc(nil).init_str(string).autorelease() }
140}
141
142impl From<NSSize> for Size<Pixels> {
143    fn from(value: NSSize) -> Self {
144        Size {
145            width: px(value.width as f32),
146            height: px(value.height as f32),
147        }
148    }
149}
150
151impl From<NSRect> for Size<Pixels> {
152    fn from(rect: NSRect) -> Self {
153        let NSSize { width, height } = rect.size;
154        size(width.into(), height.into())
155    }
156}
157
158impl From<NSRect> for Size<DevicePixels> {
159    fn from(rect: NSRect) -> Self {
160        let NSSize { width, height } = rect.size;
161        size(DevicePixels(width as i32), DevicePixels(height as i32))
162    }
163}