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#[cfg(all(feature = "screen-capture", any(test, feature = "test-support")))]
 12pub use screen_capture::{
 13    capture_window_screenshot, cv_pixel_buffer_to_rgba_image, screen_capture_frame_to_rgba_image,
 14};
 15
 16#[cfg(not(feature = "macos-blade"))]
 17mod metal_atlas;
 18#[cfg(not(feature = "macos-blade"))]
 19pub mod metal_renderer;
 20
 21use core_video::image_buffer::CVImageBuffer;
 22#[cfg(not(feature = "macos-blade"))]
 23use metal_renderer as renderer;
 24
 25#[cfg(feature = "macos-blade")]
 26use crate::platform::blade as renderer;
 27
 28mod attributed_string;
 29
 30#[cfg(feature = "font-kit")]
 31mod open_type;
 32
 33#[cfg(feature = "font-kit")]
 34mod text_system;
 35
 36mod platform;
 37mod window;
 38mod window_appearance;
 39
 40use crate::{DevicePixels, Pixels, Size, px, size};
 41use cocoa::{
 42    base::{id, nil},
 43    foundation::{NSAutoreleasePool, NSNotFound, NSRect, NSSize, NSString, NSUInteger},
 44};
 45
 46use objc::runtime::{BOOL, NO, YES};
 47use std::{
 48    ffi::{CStr, c_char},
 49    ops::Range,
 50};
 51
 52pub(crate) use dispatcher::*;
 53pub(crate) use display::*;
 54pub(crate) use display_link::*;
 55pub(crate) use keyboard::*;
 56pub(crate) use platform::*;
 57pub(crate) use window::*;
 58
 59#[cfg(feature = "font-kit")]
 60pub(crate) use text_system::*;
 61
 62/// A frame of video captured from a screen.
 63pub(crate) type PlatformScreenCaptureFrame = CVImageBuffer;
 64
 65trait BoolExt {
 66    fn to_objc(self) -> BOOL;
 67}
 68
 69impl BoolExt for bool {
 70    fn to_objc(self) -> BOOL {
 71        if self { YES } else { NO }
 72    }
 73}
 74
 75trait NSStringExt {
 76    unsafe fn to_str(&self) -> &str;
 77}
 78
 79impl NSStringExt for id {
 80    unsafe fn to_str(&self) -> &str {
 81        unsafe {
 82            let cstr = self.UTF8String();
 83            if cstr.is_null() {
 84                ""
 85            } else {
 86                CStr::from_ptr(cstr as *mut c_char).to_str().unwrap()
 87            }
 88        }
 89    }
 90}
 91
 92#[repr(C)]
 93#[derive(Copy, Clone, Debug)]
 94struct NSRange {
 95    pub location: NSUInteger,
 96    pub length: NSUInteger,
 97}
 98
 99impl NSRange {
100    fn invalid() -> Self {
101        Self {
102            location: NSNotFound as NSUInteger,
103            length: 0,
104        }
105    }
106
107    fn is_valid(&self) -> bool {
108        self.location != NSNotFound as NSUInteger
109    }
110
111    fn to_range(self) -> Option<Range<usize>> {
112        if self.is_valid() {
113            let start = self.location as usize;
114            let end = start + self.length as usize;
115            Some(start..end)
116        } else {
117            None
118        }
119    }
120}
121
122impl From<Range<usize>> for NSRange {
123    fn from(range: Range<usize>) -> Self {
124        NSRange {
125            location: range.start as NSUInteger,
126            length: range.len() as NSUInteger,
127        }
128    }
129}
130
131unsafe impl objc::Encode for NSRange {
132    fn encode() -> objc::Encoding {
133        let encoding = format!(
134            "{{NSRange={}{}}}",
135            NSUInteger::encode().as_str(),
136            NSUInteger::encode().as_str()
137        );
138        unsafe { objc::Encoding::from_str(&encoding) }
139    }
140}
141
142/// Allow NSString::alloc use here because it sets autorelease
143#[allow(clippy::disallowed_methods)]
144unsafe fn ns_string(string: &str) -> id {
145    unsafe { NSString::alloc(nil).init_str(string).autorelease() }
146}
147
148impl From<NSSize> for Size<Pixels> {
149    fn from(value: NSSize) -> Self {
150        Size {
151            width: px(value.width as f32),
152            height: px(value.height as f32),
153        }
154    }
155}
156
157impl From<NSRect> for Size<Pixels> {
158    fn from(rect: NSRect) -> Self {
159        let NSSize { width, height } = rect.size;
160        size(width.into(), height.into())
161    }
162}
163
164impl From<NSRect> for Size<DevicePixels> {
165    fn from(rect: NSRect) -> Self {
166        let NSSize { width, height } = rect.size;
167        size(DevicePixels(width as i32), DevicePixels(height as i32))
168    }
169}