use super::device::{Adapter, Device, NativeDevice};
use super::surface::NativeWidget;
use crate::Error;
use objc2::rc::Retained;
use objc2_app_kit::NSView;
use objc2_core_foundation::{CFBoolean, CFBundle, CFMutableDictionary, CFRetained, CFString};
use euclid::default::Size2D;
use std::os::raw::c_void;
#[derive(Clone)]
pub struct Connection;
#[derive(Clone)]
pub struct NativeConnection;
impl Connection {
#[inline]
pub fn new() -> Result<Connection, Error> {
unsafe {
let main_bundle = CFBundle::main_bundle().unwrap();
let bundle_info_dictionary = main_bundle.info_dictionary().unwrap();
let bundle_info_dictionary =
CFRetained::cast_unchecked::<CFMutableDictionary>(bundle_info_dictionary);
let supports_automatic_graphics_switching_key =
CFString::from_str("NSSupportsAutomaticGraphicsSwitching");
let supports_automatic_graphics_switching_value = CFBoolean::new(true);
CFMutableDictionary::set_value(
Some(&bundle_info_dictionary),
&*supports_automatic_graphics_switching_key as *const _ as *const c_void,
&*supports_automatic_graphics_switching_value as *const _ as *const c_void,
);
}
Ok(Connection)
}
#[inline]
pub unsafe fn from_native_connection(_: NativeConnection) -> Result<Connection, Error> {
Connection::new()
}
#[inline]
pub fn native_connection(&self) -> NativeConnection {
NativeConnection
}
#[inline]
pub fn create_adapter(&self) -> Result<Adapter, Error> {
self.create_hardware_adapter()
}
#[inline]
pub fn create_hardware_adapter(&self) -> Result<Adapter, Error> {
Ok(Adapter {
is_low_power: false,
})
}
#[inline]
pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
Ok(Adapter { is_low_power: true })
}
#[inline]
pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
self.create_low_power_adapter()
}
#[inline]
pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
Device::new((*adapter).clone())
}
#[inline]
pub unsafe fn create_device_from_native_device(
&self,
_: NativeDevice,
) -> Result<Device, Error> {
self.create_device(&self.create_adapter()?)
}
#[cfg(feature = "sm-raw-window-handle-05")]
pub fn from_raw_display_handle(_: rwh_05::RawDisplayHandle) -> Result<Connection, Error> {
Connection::new()
}
#[cfg(feature = "sm-raw-window-handle-06")]
pub fn from_display_handle(_: rwh_06::DisplayHandle) -> Result<Connection, Error> {
Connection::new()
}
pub unsafe fn create_native_widget_from_ptr(
&self,
raw: *mut c_void,
_size: Size2D<i32>,
) -> NativeWidget {
let view_ptr: *mut NSView = raw.cast();
NativeWidget {
view: unsafe { Retained::from_raw(view_ptr).unwrap() },
opaque: true,
}
}
#[cfg(feature = "sm-raw-window-handle-05")]
#[inline]
pub fn create_native_widget_from_raw_window_handle(
&self,
raw_handle: rwh_05::RawWindowHandle,
_size: Size2D<i32>,
) -> Result<NativeWidget, Error> {
use objc2::{MainThreadMarker, Message};
use objc2_app_kit::NSWindow;
use rwh_05::RawWindowHandle::AppKit;
match raw_handle {
AppKit(handle) => {
assert!(
MainThreadMarker::new().is_some(),
"NSView is only usable on the main thread"
);
let ns_view = unsafe { handle.ns_view.cast::<NSView>().as_ref().unwrap() };
let ns_window = unsafe { handle.ns_window.cast::<NSWindow>().as_ref().unwrap() };
Ok(NativeWidget {
view: ns_view.retain(),
opaque: unsafe { ns_window.isOpaque() },
})
}
_ => Err(Error::IncompatibleNativeWidget),
}
}
#[cfg(feature = "sm-raw-window-handle-06")]
#[inline]
pub fn create_native_widget_from_window_handle(
&self,
handle: rwh_06::WindowHandle,
_size: Size2D<i32>,
) -> Result<NativeWidget, Error> {
use objc2::{MainThreadMarker, Message};
use rwh_06::RawWindowHandle::AppKit;
match handle.as_raw() {
AppKit(handle) => {
assert!(
MainThreadMarker::new().is_some(),
"NSView is only usable on the main thread"
);
let ns_view = unsafe { handle.ns_view.cast::<NSView>().as_ref() };
let ns_window = ns_view
.window()
.expect("view must be installed in a window");
Ok(NativeWidget {
view: ns_view.retain(),
opaque: ns_window.isOpaque(),
})
}
_ => Err(Error::IncompatibleNativeWidget),
}
}
}
impl NativeConnection {
#[inline]
pub fn current() -> Result<NativeConnection, Error> {
Ok(NativeConnection)
}
}