maverick_os 2.0.3

Maverick OS
Documentation
use image::RgbaImage;
use objc2::rc::autoreleasepool;
use objc2::{class, msg_send};
use objc2_foundation::{NSArray, NSObject, NSString, NSRect, NSPoint, NSSize};
use objc2::rc::Retained;

#[derive(Clone)]
pub struct OsShare;

impl OsShare {
    pub fn new() -> Self {
        Self
    }

    pub fn share(&self, text: &str) {
        autoreleasepool(|_| {
            let ns_string = NSString::from_str(text);
            let items = NSArray::from_slice(&[&*ns_string]);

            let cls = class!(NSSharingServicePicker);
            let picker: *mut NSObject = unsafe { msg_send![cls, alloc] };
            let picker: *mut NSObject = unsafe {
                msg_send![picker, initWithItems: &*items]
            };

            let app: *mut NSObject = unsafe { msg_send![class!(NSApplication), sharedApplication] };
            let key_window: *mut NSObject = unsafe { msg_send![app, keyWindow] };
            let content_view: *mut NSObject = unsafe { msg_send![key_window, contentView] };

            let anchor_rect = NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(1.0, 1.0));

            let _: () = unsafe {
                msg_send![
                    picker,
                    showRelativeToRect: anchor_rect,
                    ofView: content_view,
                    preferredEdge: 2u64
                ]
            };
        });
    }

    pub fn share_image(&self, rgba_image: RgbaImage) {
        autoreleasepool(|_| {
            use objc2_core_graphics::{
                CGImageAlphaInfo,
                CGBitmapContextCreate,
                CGBitmapContextCreateImage,
                CGImage,
            };

            let width = rgba_image.width();
            let height = rgba_image.height();
            let bytes_per_pixel = 4usize;
            let bytes_per_row = bytes_per_pixel * width as usize;
            let bits_per_component = 8usize;

            let buffer = rgba_image.as_raw();
            let color_space = objc2_core_graphics::CGColorSpace::new_device_rgb();

            let context = unsafe {
                CGBitmapContextCreate(
                    buffer.as_ptr() as *mut _,
                    width as usize,
                    height as usize,
                    bits_per_component,
                    bytes_per_row,
                    color_space.as_deref(),
                    CGImageAlphaInfo::PremultipliedLast.0,
                )
            }
            .expect("Failed to create bitmap context");

            let cg_image: Retained<CGImage> = CGBitmapContextCreateImage(Some(&context))
                .expect("Could not create image from context")
                .into();

            let ns_image_cls = class!(NSImage);
            let ns_image: *mut NSObject = unsafe { msg_send![ns_image_cls, alloc] };
            let ns_image: *mut NSObject = unsafe {
                msg_send![ns_image, initWithCGImage: &*cg_image, size: NSSize::new(width as f64, height as f64)]
            };

            let items = NSArray::from_slice(unsafe {
                std::slice::from_raw_parts(&ns_image as *const _ as *const &NSObject, 1)
            });

            let cls = class!(NSSharingServicePicker);
            let picker: *mut NSObject = unsafe { msg_send![cls, alloc] };
            let picker: *mut NSObject = unsafe {
                msg_send![picker, initWithItems: &*items]
            };

            let app: *mut NSObject = unsafe { msg_send![class!(NSApplication), sharedApplication] };
            let key_window: *mut NSObject = unsafe { msg_send![app, keyWindow] };
            let content_view: *mut NSObject = unsafe { msg_send![key_window, contentView] };

            let anchor_rect = NSRect::new(NSPoint::new(0.0, 0.0), NSSize::new(1.0, 1.0));

            let _: () = unsafe {
                msg_send![
                    picker,
                    showRelativeToRect: anchor_rect,
                    ofView: content_view,
                    preferredEdge: 2u64
                ]
            };
        });
    }
}