Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add macOS support using Core Graphics #1

Merged
merged 2 commits into from
Jan 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ x11-dl = "2.19.1"
[target.'cfg(target_os = "windows")'.dependencies]
winapi = "0.3.9"

[target.'cfg(target_os = "macos")'.dependencies]
core-graphics = "0.22.3"
objc = "0.2.7"

[dev-dependencies]
winit = "0.26.1"
image = "0.23.14"
64 changes: 64 additions & 0 deletions src/cg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::{GraphicsContextImpl, SoftBufferError};
use raw_window_handle::{HasRawWindowHandle, AppKitHandle};
use objc::runtime::Object;
use core_graphics::base::{kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault};
use core_graphics::color_space::CGColorSpace;
use core_graphics::context::CGContext;
use core_graphics::data_provider::CGDataProvider;
use core_graphics::geometry::{CGPoint, CGSize, CGRect};
use core_graphics::image::CGImage;
use core_graphics::sys;

pub struct CGImpl {
view: *mut Object,
}

impl CGImpl {
pub unsafe fn new<W: HasRawWindowHandle>(handle: AppKitHandle) -> Result<Self, SoftBufferError<W>> {
let window = handle.ns_window as *mut Object;
let view = handle.ns_view as *mut Object;
let cls = class!(NSGraphicsContext);
let graphics_context: *mut Object = msg_send![cls, graphicsContextWithWindow:window];
if graphics_context.is_null() {
return Err(SoftBufferError::PlatformError(Some("Graphics context is null".into()), None));
}
let _: () = msg_send![cls, setCurrentContext:graphics_context];
Ok(
Self {
view,
}
)
}
}

impl GraphicsContextImpl for CGImpl {
unsafe fn set_buffer(&mut self, buffer: &[u32], width: u16, height: u16) {
let cls = class!(NSGraphicsContext);
let graphics_context: *mut Object = msg_send![cls, currentContext];
let context_ptr: *mut sys::CGContext = msg_send![graphics_context, CGContext];
let context = CGContext::from_existing_context_ptr(context_ptr);
let color_space = CGColorSpace::create_device_rgb();
let slice = std::slice::from_raw_parts(
buffer.as_ptr() as *const u8,
buffer.len() * 4);
let data_provider = CGDataProvider::from_slice(slice);
let image = CGImage::new(
width as usize,
height as usize,
8,
32,
(width * 4) as usize,
&color_space,
kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
&data_provider,
false,
kCGRenderingIntentDefault,
);
let frame: CGRect = msg_send![self.view, frame];
// In Core Graphics, (0, 0) is bottom left, not top left
let origin = CGPoint { x: 0f64, y: frame.size.height };
let size = CGSize { width: width as f64, height: -(height as f64) };
let rect = CGRect { origin, size };
context.draw_image(rect, &image);
}
}
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
#![doc = include_str!("../README.md")]

#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;

#[cfg(target_os = "windows")]
mod win32;
#[cfg(target_os = "macos")]
mod cg;
#[cfg(target_os = "linux")]
mod x11;

Expand Down Expand Up @@ -32,6 +38,8 @@ impl<W: HasRawWindowHandle> GraphicsContext<W> {
RawWindowHandle::Xlib(xlib_handle) => Box::new(x11::X11Impl::new(xlib_handle)?),
#[cfg(target_os = "windows")]
RawWindowHandle::Win32(win32_handle) => Box::new(win32::Win32Impl::new(&win32_handle)?),
#[cfg(target_os = "macos")]
RawWindowHandle::AppKit(appkit_handle) => Box::new(cg::CGImpl::new(appkit_handle)?),
unimplemented_handle_type => return Err(SoftBufferError::UnsupportedPlatform {
window,
human_readable_platform_name: window_handle_type_name(&unimplemented_handle_type),
Expand Down