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