use super::device::{Device, NativeDevice};
use super::surface::NativeWidget;
use crate::egl;
use crate::egl::types::{EGLAttrib, EGLDisplay};
use crate::error::Error;
use crate::info::GLApi;
use crate::platform::generic::egl::device::EGL_FUNCTIONS;
use crate::platform::generic::egl::ffi::EGL_PLATFORM_X11_KHR;
use crate::platform::unix::generic::device::Adapter;
use euclid::default::Size2D;
use std::marker::PhantomData;
use std::os::raw::c_void;
use std::ptr;
use std::sync::{Arc, Once};
use x11::xlib::{Display, XCloseDisplay, XInitThreads, XLockDisplay, XOpenDisplay, XUnlockDisplay};
static X_THREADS_INIT: Once = Once::new();
#[derive(Clone)]
pub struct Connection {
pub(crate) native_connection: Arc<NativeConnectionWrapper>,
}
unsafe impl Send for Connection {}
pub(crate) struct NativeConnectionWrapper {
pub(crate) egl_display: EGLDisplay,
x11_display: *mut Display,
x11_display_is_owned: bool,
}
#[derive(Clone)]
pub struct NativeConnection {
pub egl_display: EGLDisplay,
pub x11_display: *mut Display,
}
impl Drop for NativeConnectionWrapper {
#[inline]
fn drop(&mut self) {
unsafe {
if self.x11_display_is_owned {
XCloseDisplay(self.x11_display);
}
self.x11_display = ptr::null_mut();
}
}
}
impl Connection {
#[inline]
pub fn new() -> Result<Connection, Error> {
unsafe {
X_THREADS_INIT.call_once(|| {
XInitThreads();
});
let x11_display = XOpenDisplay(ptr::null());
if x11_display.is_null() {
return Err(Error::ConnectionFailed);
}
let egl_display = create_egl_display(x11_display);
Ok(Connection {
native_connection: Arc::new(NativeConnectionWrapper {
x11_display,
x11_display_is_owned: true,
egl_display,
}),
})
}
}
#[inline]
pub unsafe fn from_native_connection(
native_connection: NativeConnection,
) -> Result<Connection, Error> {
Ok(Connection {
native_connection: Arc::new(NativeConnectionWrapper {
egl_display: native_connection.egl_display,
x11_display: native_connection.x11_display,
x11_display_is_owned: false,
}),
})
}
fn from_x11_display(x11_display: *mut Display, is_owned: bool) -> Result<Connection, Error> {
unsafe {
let egl_display = create_egl_display(x11_display);
Ok(Connection {
native_connection: Arc::new(NativeConnectionWrapper {
egl_display,
x11_display,
x11_display_is_owned: is_owned,
}),
})
}
}
#[inline]
pub fn native_connection(&self) -> NativeConnection {
NativeConnection {
egl_display: self.native_connection.egl_display,
x11_display: self.native_connection.x11_display,
}
}
#[inline]
pub fn gl_api(&self) -> GLApi {
GLApi::GL
}
#[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::hardware())
}
#[inline]
pub fn create_low_power_adapter(&self) -> Result<Adapter, Error> {
Ok(Adapter::low_power())
}
#[inline]
pub fn create_software_adapter(&self) -> Result<Adapter, Error> {
Ok(Adapter::software())
}
#[inline]
pub fn create_device(&self, adapter: &Adapter) -> Result<Device, Error> {
Device::new(self, adapter)
}
#[inline]
pub unsafe fn create_device_from_native_device(
&self,
native_device: NativeDevice,
) -> Result<Device, Error> {
Device::new(self, &native_device.adapter)
}
#[cfg(feature = "sm-raw-window-handle-05")]
pub fn from_raw_display_handle(
raw_handle: rwh_05::RawDisplayHandle,
) -> Result<Connection, Error> {
use rwh_05::RawDisplayHandle::Xcb;
use rwh_05::RawDisplayHandle::Xlib;
use rwh_05::XlibDisplayHandle;
let display = match raw_handle {
Xlib(XlibDisplayHandle { display, .. }) => display as *mut Display,
Xcb(_) => return Err(Error::Unimplemented),
_ => return Err(Error::IncompatibleRawDisplayHandle),
};
Connection::from_x11_display(display, false)
}
#[cfg(feature = "sm-raw-window-handle-06")]
pub fn from_display_handle(handle: rwh_06::DisplayHandle) -> Result<Connection, Error> {
use rwh_06::RawDisplayHandle::Xcb;
use rwh_06::RawDisplayHandle::Xlib;
use rwh_06::XlibDisplayHandle;
let display = match handle.as_raw() {
Xlib(XlibDisplayHandle {
display: Some(display),
..
}) => display.as_ptr() as *mut Display,
Xcb(_) => return Err(Error::Unimplemented),
_ => return Err(Error::IncompatibleRawDisplayHandle),
};
Connection::from_x11_display(display, false)
}
pub unsafe fn create_native_widget_from_ptr(
&self,
raw: *mut c_void,
_size: Size2D<i32>,
) -> NativeWidget {
NativeWidget {
window: std::mem::transmute(raw),
}
}
#[cfg(feature = "sm-raw-window-handle-05")]
pub fn create_native_widget_from_raw_window_handle(
&self,
raw_handle: rwh_05::RawWindowHandle,
_size: Size2D<i32>,
) -> Result<NativeWidget, Error> {
use rwh_05::RawWindowHandle::Xlib;
match raw_handle {
Xlib(handle) => Ok(NativeWidget {
window: handle.window,
}),
_ => Err(Error::IncompatibleNativeWidget),
}
}
#[cfg(feature = "sm-raw-window-handle-06")]
pub fn create_native_widget_from_window_handle(
&self,
handle: rwh_06::WindowHandle,
_size: Size2D<i32>,
) -> Result<NativeWidget, Error> {
use rwh_06::RawWindowHandle::Xlib;
match handle.as_raw() {
Xlib(handle) => Ok(NativeWidget {
window: handle.window,
}),
_ => Err(Error::IncompatibleNativeWidget),
}
}
}
impl NativeConnectionWrapper {
#[inline]
pub(crate) fn lock_display(&self) -> DisplayGuard {
unsafe {
let display = self.x11_display;
XLockDisplay(display);
DisplayGuard {
display,
phantom: PhantomData,
}
}
}
}
pub(crate) struct DisplayGuard<'a> {
display: *mut Display,
phantom: PhantomData<&'a ()>,
}
impl<'a> Drop for DisplayGuard<'a> {
fn drop(&mut self) {
unsafe {
XUnlockDisplay(self.display);
}
}
}
impl<'a> DisplayGuard<'a> {
#[inline]
pub(crate) fn display(&self) -> *mut Display {
self.display
}
}
unsafe fn create_egl_display(display: *mut Display) -> EGLDisplay {
EGL_FUNCTIONS.with(|egl| {
let display_attributes = [egl::NONE as EGLAttrib];
let egl_display = egl.GetPlatformDisplay(
EGL_PLATFORM_X11_KHR,
display as *mut c_void,
display_attributes.as_ptr(),
);
let (mut egl_major_version, mut egl_minor_version) = (0, 0);
let ok = egl.Initialize(egl_display, &mut egl_major_version, &mut egl_minor_version);
assert_ne!(ok, egl::FALSE);
egl_display
})
}