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