breaking: Use raw-window-handle version 0.6
Signed-off-by: John Nunley <dev@notgull.net> Co-Authored-By: dAxpeDDa <daxpedda@gmail.com>
This commit is contained in:
parent
18c944736e
commit
0bcd2e22a2
22 changed files with 830 additions and 628 deletions
35
src/cg.rs
35
src/cg.rs
|
|
@ -1,3 +1,4 @@
|
|||
use crate::error::InitError;
|
||||
use crate::{Rect, SoftBufferError};
|
||||
use core_graphics::base::{
|
||||
kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipFirst, kCGRenderingIntentDefault,
|
||||
|
|
@ -5,13 +6,14 @@ use core_graphics::base::{
|
|||
use core_graphics::color_space::CGColorSpace;
|
||||
use core_graphics::data_provider::CGDataProvider;
|
||||
use core_graphics::image::CGImage;
|
||||
use raw_window_handle::AppKitWindowHandle;
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
|
||||
|
||||
use cocoa::appkit::{NSView, NSViewHeightSizable, NSViewWidthSizable, NSWindow};
|
||||
use cocoa::base::{id, nil};
|
||||
use cocoa::quartzcore::{transaction, CALayer, ContentsGravity};
|
||||
use foreign_types::ForeignType;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU32;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
|
@ -23,18 +25,24 @@ impl AsRef<[u8]> for Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CGImpl {
|
||||
pub struct CGImpl<D, W> {
|
||||
layer: CALayer,
|
||||
window: id,
|
||||
color_space: CGColorSpace,
|
||||
size: Option<(NonZeroU32, NonZeroU32)>,
|
||||
_window_source: W,
|
||||
_display: PhantomData<D>,
|
||||
}
|
||||
|
||||
impl CGImpl {
|
||||
pub unsafe fn new(handle: AppKitWindowHandle) -> Result<Self, SoftBufferError> {
|
||||
let window = handle.ns_window as id;
|
||||
let window: id = msg_send![window, retain];
|
||||
let view = handle.ns_view as id;
|
||||
impl<D: HasDisplayHandle, W: HasWindowHandle> CGImpl<D, W> {
|
||||
pub(crate) fn new(window_src: W) -> Result<Self, InitError<W>> {
|
||||
let raw = window_src.window_handle()?.as_raw();
|
||||
let handle = match raw {
|
||||
RawWindowHandle::AppKit(handle) => handle,
|
||||
_ => return Err(InitError::Unsupported(window_src)),
|
||||
};
|
||||
let view = handle.ns_view.as_ptr() as id;
|
||||
let window = unsafe { msg_send![view, window] };
|
||||
let layer = CALayer::new();
|
||||
unsafe {
|
||||
let subview: id = NSView::alloc(nil).initWithFrame_(NSView::frame(view));
|
||||
|
|
@ -52,6 +60,8 @@ impl CGImpl {
|
|||
window,
|
||||
color_space,
|
||||
size: None,
|
||||
_display: PhantomData,
|
||||
_window_source: window_src,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -60,10 +70,11 @@ impl CGImpl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
let (width, height) = self
|
||||
.size
|
||||
.expect("Must set size of surface before calling `buffer_mut()`");
|
||||
|
||||
Ok(BufferImpl {
|
||||
buffer: vec![0; width.get() as usize * height.get() as usize],
|
||||
imp: self,
|
||||
|
|
@ -76,12 +87,12 @@ impl CGImpl {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a> {
|
||||
imp: &'a mut CGImpl,
|
||||
pub struct BufferImpl<'a, D, W> {
|
||||
imp: &'a mut CGImpl<D, W>,
|
||||
buffer: Vec<u32>,
|
||||
}
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
&self.buffer
|
||||
|
|
@ -135,7 +146,7 @@ impl<'a> BufferImpl<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for CGImpl {
|
||||
impl<D, W> Drop for CGImpl<D, W> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _: () = msg_send![self.window, release];
|
||||
|
|
|
|||
45
src/error.rs
45
src/error.rs
|
|
@ -1,4 +1,4 @@
|
|||
use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
|
||||
use raw_window_handle::{HandleError, RawDisplayHandle, RawWindowHandle};
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::num::NonZeroU32;
|
||||
|
|
@ -7,6 +7,11 @@ use std::num::NonZeroU32;
|
|||
#[non_exhaustive]
|
||||
/// A sum type of all of the errors that can occur during the operation of this crate.
|
||||
pub enum SoftBufferError {
|
||||
/// A [`raw-window-handle`] error occurred.
|
||||
///
|
||||
/// [`raw-window-handle`]: raw_window_handle
|
||||
RawWindowHandle(HandleError),
|
||||
|
||||
/// The [`RawDisplayHandle`] passed into [`Context::new`] is not supported by this crate.
|
||||
///
|
||||
/// [`RawDisplayHandle`]: raw_window_handle::RawDisplayHandle
|
||||
|
|
@ -102,6 +107,7 @@ pub enum SoftBufferError {
|
|||
impl fmt::Display for SoftBufferError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::RawWindowHandle(err) => fmt::Display::fmt(err, f),
|
||||
Self::UnsupportedDisplayPlatform {
|
||||
human_readable_display_platform_name,
|
||||
display_handle,
|
||||
|
|
@ -137,7 +143,42 @@ impl fmt::Display for SoftBufferError {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SoftBufferError {}
|
||||
impl std::error::Error for SoftBufferError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
Self::RawWindowHandle(err) => Some(err),
|
||||
Self::PlatformError(_, err) => err.as_deref(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HandleError> for SoftBufferError {
|
||||
fn from(err: HandleError) -> Self {
|
||||
Self::RawWindowHandle(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple unit error type used to bubble up rejected platforms.
|
||||
pub(crate) enum InitError<D> {
|
||||
/// Failed to initialize.
|
||||
Failure(SoftBufferError),
|
||||
|
||||
/// Cannot initialize this handle on this platform.
|
||||
Unsupported(D),
|
||||
}
|
||||
|
||||
impl<T> From<SoftBufferError> for InitError<T> {
|
||||
fn from(err: SoftBufferError) -> Self {
|
||||
Self::Failure(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<HandleError> for InitError<T> {
|
||||
fn from(err: HandleError) -> Self {
|
||||
Self::Failure(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenient wrapper to cast errors into SoftBufferError.
|
||||
pub(crate) trait SwResultExt<T> {
|
||||
|
|
|
|||
87
src/kms.rs
87
src/kms.rs
|
|
@ -9,54 +9,59 @@ use drm::control::{
|
|||
};
|
||||
use drm::Device;
|
||||
|
||||
use raw_window_handle::{DrmDisplayHandle, DrmWindowHandle};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU32;
|
||||
use std::os::unix::io::{AsFd, BorrowedFd};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::error::{SoftBufferError, SwResultExt};
|
||||
use crate::error::{InitError, SoftBufferError, SwResultExt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct KmsDisplayImpl {
|
||||
pub(crate) struct KmsDisplayImpl<D: ?Sized> {
|
||||
/// The underlying raw device file descriptor.
|
||||
///
|
||||
/// Once rwh v0.6 support is merged, this an be made safe. Until then,
|
||||
/// we use this hacky workaround, since this FD's validity is guaranteed by
|
||||
/// the unsafe constructor.
|
||||
fd: BorrowedFd<'static>,
|
||||
|
||||
/// Holds a reference to the display.
|
||||
_display: D,
|
||||
}
|
||||
|
||||
impl AsFd for KmsDisplayImpl {
|
||||
impl<D: ?Sized> AsFd for KmsDisplayImpl<D> {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for KmsDisplayImpl {}
|
||||
impl CtrlDevice for KmsDisplayImpl {}
|
||||
impl<D: ?Sized> Device for KmsDisplayImpl<D> {}
|
||||
impl<D: ?Sized> CtrlDevice for KmsDisplayImpl<D> {}
|
||||
|
||||
impl KmsDisplayImpl {
|
||||
/// SAFETY: The underlying fd must not outlive the display.
|
||||
pub(crate) unsafe fn new(handle: DrmDisplayHandle) -> Result<KmsDisplayImpl, SoftBufferError> {
|
||||
let fd = handle.fd;
|
||||
impl<D: HasDisplayHandle> KmsDisplayImpl<D> {
|
||||
pub(crate) fn new(display: D) -> Result<Self, InitError<D>> {
|
||||
let fd = match display.display_handle()?.as_raw() {
|
||||
RawDisplayHandle::Drm(drm) => drm.fd,
|
||||
_ => return Err(InitError::Unsupported(display)),
|
||||
};
|
||||
if fd == -1 {
|
||||
return Err(SoftBufferError::IncompleteDisplayHandle);
|
||||
return Err(SoftBufferError::IncompleteDisplayHandle.into());
|
||||
}
|
||||
|
||||
// SAFETY: Invariants guaranteed by the user.
|
||||
let fd = unsafe { BorrowedFd::borrow_raw(fd) };
|
||||
|
||||
Ok(KmsDisplayImpl { fd })
|
||||
Ok(KmsDisplayImpl {
|
||||
fd,
|
||||
_display: display,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// All the necessary types for the Drm/Kms backend.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct KmsImpl {
|
||||
pub(crate) struct KmsImpl<D: ?Sized, W: ?Sized> {
|
||||
/// The display implementation.
|
||||
display: Rc<KmsDisplayImpl>,
|
||||
display: Rc<KmsDisplayImpl<D>>,
|
||||
|
||||
/// The connectors to use.
|
||||
connectors: Vec<connector::Handle>,
|
||||
|
|
@ -66,6 +71,9 @@ pub(crate) struct KmsImpl {
|
|||
|
||||
/// The dumb buffer we're using as a buffer.
|
||||
buffer: Option<Buffers>,
|
||||
|
||||
/// Window handle that we are keeping around.
|
||||
_window: W,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -81,7 +89,7 @@ struct Buffers {
|
|||
}
|
||||
|
||||
/// The buffer implementation.
|
||||
pub(crate) struct BufferImpl<'a> {
|
||||
pub(crate) struct BufferImpl<'a, D: ?Sized, W: ?Sized> {
|
||||
/// The mapping of the dump buffer.
|
||||
mapping: DumbMapping<'a>,
|
||||
|
||||
|
|
@ -101,13 +109,16 @@ pub(crate) struct BufferImpl<'a> {
|
|||
size: (NonZeroU32, NonZeroU32),
|
||||
|
||||
/// The display implementation.
|
||||
display: &'a KmsDisplayImpl,
|
||||
display: &'a KmsDisplayImpl<D>,
|
||||
|
||||
/// Age of the front buffer.
|
||||
front_age: &'a mut u8,
|
||||
|
||||
/// Age of the back buffer.
|
||||
back_age: &'a mut u8,
|
||||
|
||||
/// Window reference.
|
||||
_window: PhantomData<&'a mut W>,
|
||||
}
|
||||
|
||||
/// The combined frame buffer and dumb buffer.
|
||||
|
|
@ -123,22 +134,16 @@ struct SharedBuffer {
|
|||
age: u8,
|
||||
}
|
||||
|
||||
impl KmsImpl {
|
||||
impl<D: ?Sized, W: HasWindowHandle> KmsImpl<D, W> {
|
||||
/// Create a new KMS backend.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The plane must be valid for the lifetime of the backend.
|
||||
pub(crate) unsafe fn new(
|
||||
window_handle: DrmWindowHandle,
|
||||
display: Rc<KmsDisplayImpl>,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
log::trace!("new: window_handle={:X}", window_handle.plane);
|
||||
|
||||
pub(crate) fn new(window: W, display: Rc<KmsDisplayImpl<D>>) -> Result<Self, InitError<W>> {
|
||||
// Make sure that the window handle is valid.
|
||||
let plane_handle = match NonZeroU32::new(window_handle.plane) {
|
||||
Some(handle) => plane::Handle::from(handle),
|
||||
None => return Err(SoftBufferError::IncompleteWindowHandle),
|
||||
let plane_handle = match window.window_handle()?.as_raw() {
|
||||
RawWindowHandle::Drm(drm) => match NonZeroU32::new(drm.plane) {
|
||||
Some(handle) => plane::Handle::from(handle),
|
||||
None => return Err(SoftBufferError::IncompleteWindowHandle.into()),
|
||||
},
|
||||
_ => return Err(InitError::Unsupported(window)),
|
||||
};
|
||||
|
||||
let plane_info = display
|
||||
|
|
@ -195,6 +200,7 @@ impl KmsImpl {
|
|||
connectors,
|
||||
display,
|
||||
buffer: None,
|
||||
_window: window,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +238,7 @@ impl KmsImpl {
|
|||
}
|
||||
|
||||
/// Get a mutable reference to the buffer.
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_>, SoftBufferError> {
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
// Map the dumb buffer.
|
||||
let set = self
|
||||
.buffer
|
||||
|
|
@ -267,11 +273,12 @@ impl KmsImpl {
|
|||
zeroes: &set.zeroes,
|
||||
front_age,
|
||||
back_age,
|
||||
_window: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for KmsImpl {
|
||||
impl<D: ?Sized, W: ?Sized> Drop for KmsImpl<D, W> {
|
||||
fn drop(&mut self) {
|
||||
// Map the CRTC to the information that was there before.
|
||||
self.display
|
||||
|
|
@ -286,7 +293,7 @@ impl Drop for KmsImpl {
|
|||
}
|
||||
}
|
||||
|
||||
impl BufferImpl<'_> {
|
||||
impl<D: ?Sized, W: ?Sized> BufferImpl<'_, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
// drm-rs doesn't let us have the immutable reference... so just use a bunch of zeroes.
|
||||
|
|
@ -310,7 +317,7 @@ impl BufferImpl<'_> {
|
|||
.iter()
|
||||
.map(|&rect| {
|
||||
let err = || SoftBufferError::DamageOutOfRange { rect };
|
||||
Ok(ClipRect::new(
|
||||
Ok::<_, SoftBufferError>(ClipRect::new(
|
||||
rect.x.try_into().map_err(|_| err())?,
|
||||
rect.y.try_into().map_err(|_| err())?,
|
||||
rect.x
|
||||
|
|
@ -375,8 +382,8 @@ impl BufferImpl<'_> {
|
|||
|
||||
impl SharedBuffer {
|
||||
/// Create a new buffer set.
|
||||
pub(crate) fn new(
|
||||
display: &KmsDisplayImpl,
|
||||
pub(crate) fn new<D: ?Sized>(
|
||||
display: &KmsDisplayImpl<D>,
|
||||
width: NonZeroU32,
|
||||
height: NonZeroU32,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
|
|
|
|||
268
src/lib.rs
268
src/lib.rs
|
|
@ -32,39 +32,41 @@ use std::ops;
|
|||
#[cfg(any(wayland_platform, x11_platform, kms_platform))]
|
||||
use std::rc::Rc;
|
||||
|
||||
use error::InitError;
|
||||
pub use error::SoftBufferError;
|
||||
|
||||
use raw_window_handle::{
|
||||
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub use self::web::SurfaceExtWeb;
|
||||
|
||||
/// An instance of this struct contains the platform-specific data that must be managed in order to
|
||||
/// write to a window on that platform.
|
||||
pub struct Context {
|
||||
/// The inner static dispatch object.
|
||||
context_impl: ContextDispatch,
|
||||
pub struct Context<D> {
|
||||
_marker: PhantomData<*mut ()>,
|
||||
|
||||
/// The inner static dispatch object.
|
||||
context_impl: ContextDispatch<D>,
|
||||
}
|
||||
|
||||
/// A macro for creating the enum used to statically dispatch to the platform-specific implementation.
|
||||
macro_rules! make_dispatch {
|
||||
(
|
||||
<$dgen: ident, $wgen: ident> =>
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
$name: ident ($context_inner: ty, $surface_inner: ty, $buffer_inner: ty),
|
||||
$name: ident
|
||||
($context_inner: ty, $surface_inner: ty, $buffer_inner: ty),
|
||||
)*
|
||||
) => {
|
||||
enum ContextDispatch {
|
||||
enum ContextDispatch<$dgen> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$name($context_inner),
|
||||
)*
|
||||
}
|
||||
|
||||
impl ContextDispatch {
|
||||
impl<D: HasDisplayHandle> ContextDispatch<D> {
|
||||
fn variant_name(&self) -> &'static str {
|
||||
match self {
|
||||
$(
|
||||
|
|
@ -76,14 +78,14 @@ macro_rules! make_dispatch {
|
|||
}
|
||||
|
||||
#[allow(clippy::large_enum_variant)] // it's boxed anyways
|
||||
enum SurfaceDispatch {
|
||||
enum SurfaceDispatch<$dgen, $wgen> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$name($surface_inner),
|
||||
)*
|
||||
}
|
||||
|
||||
impl SurfaceDispatch {
|
||||
impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceDispatch<D, W> {
|
||||
pub fn resize(&mut self, width: NonZeroU32, height: NonZeroU32) -> Result<(), SoftBufferError> {
|
||||
match self {
|
||||
$(
|
||||
|
|
@ -93,7 +95,7 @@ macro_rules! make_dispatch {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferDispatch, SoftBufferError> {
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferDispatch<'_, D, W>, SoftBufferError> {
|
||||
match self {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
|
|
@ -112,14 +114,14 @@ macro_rules! make_dispatch {
|
|||
}
|
||||
}
|
||||
|
||||
enum BufferDispatch<'a> {
|
||||
enum BufferDispatch<'a, $dgen, $wgen> {
|
||||
$(
|
||||
$(#[$attr])*
|
||||
$name($buffer_inner),
|
||||
)*
|
||||
}
|
||||
|
||||
impl<'a> BufferDispatch<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferDispatch<'a, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
match self {
|
||||
|
|
@ -173,76 +175,61 @@ macro_rules! make_dispatch {
|
|||
// XXX empty enum with generic bound is invalid?
|
||||
|
||||
make_dispatch! {
|
||||
<D, W> =>
|
||||
#[cfg(x11_platform)]
|
||||
X11(Rc<x11::X11DisplayImpl>, x11::X11Impl, x11::BufferImpl<'a>),
|
||||
X11(Rc<x11::X11DisplayImpl<D>>, x11::X11Impl<D, W>, x11::BufferImpl<'a, D, W>),
|
||||
#[cfg(wayland_platform)]
|
||||
Wayland(Rc<wayland::WaylandDisplayImpl>, wayland::WaylandImpl, wayland::BufferImpl<'a>),
|
||||
Wayland(Rc<wayland::WaylandDisplayImpl<D>>, wayland::WaylandImpl<D, W>, wayland::BufferImpl<'a, D, W>),
|
||||
#[cfg(kms_platform)]
|
||||
Kms(Rc<kms::KmsDisplayImpl>, kms::KmsImpl, kms::BufferImpl<'a>),
|
||||
Kms(Rc<kms::KmsDisplayImpl<D>>, kms::KmsImpl<D, W>, kms::BufferImpl<'a, D, W>),
|
||||
#[cfg(target_os = "windows")]
|
||||
Win32((), win32::Win32Impl, win32::BufferImpl<'a>),
|
||||
Win32(D, win32::Win32Impl<D, W>, win32::BufferImpl<'a, D, W>),
|
||||
#[cfg(target_os = "macos")]
|
||||
CG((), cg::CGImpl, cg::BufferImpl<'a>),
|
||||
CG(D, cg::CGImpl<D, W>, cg::BufferImpl<'a, D, W>),
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
Web(web::WebDisplayImpl, web::WebImpl, web::BufferImpl<'a>),
|
||||
Web(web::WebDisplayImpl<D>, web::WebImpl<D, W>, web::BufferImpl<'a, D, W>),
|
||||
#[cfg(target_os = "redox")]
|
||||
Orbital((), orbital::OrbitalImpl, orbital::BufferImpl<'a>),
|
||||
Orbital(D, orbital::OrbitalImpl<D, W>, orbital::BufferImpl<'a, D, W>),
|
||||
}
|
||||
|
||||
impl Context {
|
||||
impl<D: HasDisplayHandle> Context<D> {
|
||||
/// Creates a new instance of this struct, using the provided display.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Ensure that the provided object is valid for the lifetime of the Context
|
||||
pub unsafe fn new<D: HasRawDisplayHandle>(display: &D) -> Result<Self, SoftBufferError> {
|
||||
unsafe { Self::from_raw(display.raw_display_handle()) }
|
||||
}
|
||||
pub fn new(mut dpy: D) -> Result<Self, SoftBufferError> {
|
||||
macro_rules! try_init {
|
||||
($imp:ident, $x:ident => $make_it:expr) => {{
|
||||
let $x = dpy;
|
||||
match { $make_it } {
|
||||
Ok(x) => {
|
||||
return Ok(Self {
|
||||
context_impl: ContextDispatch::$imp(x),
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
Err(InitError::Unsupported(d)) => dpy = d,
|
||||
Err(InitError::Failure(f)) => return Err(f),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Creates a new instance of this struct, using the provided display handles
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Ensure that the provided handle is valid for the lifetime of the Context
|
||||
pub unsafe fn from_raw(raw_display_handle: RawDisplayHandle) -> Result<Self, SoftBufferError> {
|
||||
let imple: ContextDispatch = match raw_display_handle {
|
||||
#[cfg(x11_platform)]
|
||||
RawDisplayHandle::Xlib(xlib_handle) => unsafe {
|
||||
ContextDispatch::X11(Rc::new(x11::X11DisplayImpl::from_xlib(xlib_handle)?))
|
||||
},
|
||||
#[cfg(x11_platform)]
|
||||
RawDisplayHandle::Xcb(xcb_handle) => unsafe {
|
||||
ContextDispatch::X11(Rc::new(x11::X11DisplayImpl::from_xcb(xcb_handle)?))
|
||||
},
|
||||
#[cfg(wayland_platform)]
|
||||
RawDisplayHandle::Wayland(wayland_handle) => unsafe {
|
||||
ContextDispatch::Wayland(Rc::new(wayland::WaylandDisplayImpl::new(wayland_handle)?))
|
||||
},
|
||||
#[cfg(kms_platform)]
|
||||
RawDisplayHandle::Drm(drm_handle) => unsafe {
|
||||
ContextDispatch::Kms(Rc::new(kms::KmsDisplayImpl::new(drm_handle)?))
|
||||
},
|
||||
#[cfg(target_os = "windows")]
|
||||
RawDisplayHandle::Windows(_) => ContextDispatch::Win32(()),
|
||||
#[cfg(target_os = "macos")]
|
||||
RawDisplayHandle::AppKit(_) => ContextDispatch::CG(()),
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
RawDisplayHandle::Web(_) => ContextDispatch::Web(web::WebDisplayImpl::new()?),
|
||||
#[cfg(target_os = "redox")]
|
||||
RawDisplayHandle::Orbital(_) => ContextDispatch::Orbital(()),
|
||||
unimplemented_display_handle => {
|
||||
return Err(SoftBufferError::UnsupportedDisplayPlatform {
|
||||
human_readable_display_platform_name: display_handle_type_name(
|
||||
&unimplemented_display_handle,
|
||||
),
|
||||
display_handle: unimplemented_display_handle,
|
||||
})
|
||||
}
|
||||
};
|
||||
#[cfg(x11_platform)]
|
||||
try_init!(X11, display => x11::X11DisplayImpl::new(display).map(Rc::new));
|
||||
#[cfg(wayland_platform)]
|
||||
try_init!(Wayland, display => wayland::WaylandDisplayImpl::new(display).map(Rc::new));
|
||||
#[cfg(kms_platform)]
|
||||
try_init!(Kms, display => kms::KmsDisplayImpl::new(display).map(Rc::new));
|
||||
#[cfg(target_os = "windows")]
|
||||
try_init!(Win32, display => Ok(display));
|
||||
#[cfg(target_os = "macos")]
|
||||
try_init!(CG, display => Ok(display));
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
try_init!(Web, display => web::WebDisplayImpl::new(display));
|
||||
#[cfg(target_os = "redox")]
|
||||
try_init!(Orbital, display => Ok(display));
|
||||
|
||||
Ok(Self {
|
||||
context_impl: imple,
|
||||
_marker: PhantomData,
|
||||
let raw = dpy.display_handle()?.as_raw();
|
||||
Err(SoftBufferError::UnsupportedDisplayPlatform {
|
||||
human_readable_display_platform_name: display_handle_type_name(&raw),
|
||||
display_handle: raw,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -261,87 +248,60 @@ pub struct Rect {
|
|||
}
|
||||
|
||||
/// A surface for drawing to a window with software buffers.
|
||||
pub struct Surface {
|
||||
pub struct Surface<D, W> {
|
||||
/// This is boxed so that `Surface` is the same size on every platform.
|
||||
surface_impl: Box<SurfaceDispatch>,
|
||||
surface_impl: Box<SurfaceDispatch<D, W>>,
|
||||
_marker: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl Surface {
|
||||
impl<D: HasDisplayHandle, W: HasWindowHandle> Surface<D, W> {
|
||||
/// Creates a new surface for the context for the provided window.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Ensure that the provided objects are valid to draw a 2D buffer to, and are valid for the
|
||||
/// lifetime of the Context
|
||||
pub unsafe fn new<W: HasRawWindowHandle>(
|
||||
context: &Context,
|
||||
window: &W,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
unsafe { Self::from_raw(context, window.raw_window_handle()) }
|
||||
}
|
||||
pub fn new(context: &Context<D>, window: W) -> Result<Self, SoftBufferError> {
|
||||
macro_rules! leap {
|
||||
($e:expr) => {{
|
||||
match ($e) {
|
||||
Ok(x) => x,
|
||||
Err(InitError::Unsupported(window)) => {
|
||||
let raw = window.window_handle()?.as_raw();
|
||||
return Err(SoftBufferError::UnsupportedWindowPlatform {
|
||||
human_readable_window_platform_name: window_handle_type_name(&raw),
|
||||
human_readable_display_platform_name: context
|
||||
.context_impl
|
||||
.variant_name(),
|
||||
window_handle: raw,
|
||||
});
|
||||
}
|
||||
Err(InitError::Failure(f)) => return Err(f),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// Creates a new surface for the context for the provided raw window handle.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Ensure that the provided handles are valid to draw a 2D buffer to, and are valid for the
|
||||
/// lifetime of the Context
|
||||
pub unsafe fn from_raw(
|
||||
context: &Context,
|
||||
raw_window_handle: RawWindowHandle,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
let imple: SurfaceDispatch = match (&context.context_impl, raw_window_handle) {
|
||||
let imple = match &context.context_impl {
|
||||
#[cfg(x11_platform)]
|
||||
(
|
||||
ContextDispatch::X11(xcb_display_handle),
|
||||
RawWindowHandle::Xlib(xlib_window_handle),
|
||||
) => SurfaceDispatch::X11(unsafe {
|
||||
x11::X11Impl::from_xlib(xlib_window_handle, xcb_display_handle.clone())?
|
||||
}),
|
||||
#[cfg(x11_platform)]
|
||||
(ContextDispatch::X11(xcb_display_handle), RawWindowHandle::Xcb(xcb_window_handle)) => {
|
||||
SurfaceDispatch::X11(unsafe {
|
||||
x11::X11Impl::from_xcb(xcb_window_handle, xcb_display_handle.clone())?
|
||||
})
|
||||
ContextDispatch::X11(xcb_display_handle) => {
|
||||
SurfaceDispatch::X11(leap!(x11::X11Impl::new(window, xcb_display_handle.clone())))
|
||||
}
|
||||
#[cfg(wayland_platform)]
|
||||
(
|
||||
ContextDispatch::Wayland(wayland_display_impl),
|
||||
RawWindowHandle::Wayland(wayland_window_handle),
|
||||
) => SurfaceDispatch::Wayland(unsafe {
|
||||
wayland::WaylandImpl::new(wayland_window_handle, wayland_display_impl.clone())?
|
||||
}),
|
||||
ContextDispatch::Wayland(wayland_display_impl) => SurfaceDispatch::Wayland(leap!(
|
||||
wayland::WaylandImpl::new(window, wayland_display_impl.clone())
|
||||
)),
|
||||
#[cfg(kms_platform)]
|
||||
(ContextDispatch::Kms(kms_display_impl), RawWindowHandle::Drm(drm_window_handle)) => {
|
||||
SurfaceDispatch::Kms(unsafe {
|
||||
kms::KmsImpl::new(drm_window_handle, kms_display_impl.clone())?
|
||||
})
|
||||
ContextDispatch::Kms(kms_display_impl) => {
|
||||
SurfaceDispatch::Kms(leap!(kms::KmsImpl::new(window, kms_display_impl.clone())))
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
(ContextDispatch::Win32(()), RawWindowHandle::Win32(win32_handle)) => {
|
||||
SurfaceDispatch::Win32(unsafe { win32::Win32Impl::new(&win32_handle)? })
|
||||
ContextDispatch::Win32(_) => {
|
||||
SurfaceDispatch::Win32(leap!(win32::Win32Impl::new(window)))
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
(ContextDispatch::CG(()), RawWindowHandle::AppKit(appkit_handle)) => {
|
||||
SurfaceDispatch::CG(unsafe { cg::CGImpl::new(appkit_handle)? })
|
||||
}
|
||||
ContextDispatch::CG(_) => SurfaceDispatch::CG(leap!(cg::CGImpl::new(window))),
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
(ContextDispatch::Web(context), RawWindowHandle::Web(web_handle)) => {
|
||||
SurfaceDispatch::Web(web::WebImpl::new(context, web_handle)?)
|
||||
ContextDispatch::Web(web_display_impl) => {
|
||||
SurfaceDispatch::Web(leap!(web::WebImpl::new(web_display_impl, window)))
|
||||
}
|
||||
#[cfg(target_os = "redox")]
|
||||
(ContextDispatch::Orbital(()), RawWindowHandle::Orbital(orbital_handle)) => {
|
||||
SurfaceDispatch::Orbital(orbital::OrbitalImpl::new(orbital_handle)?)
|
||||
}
|
||||
(unsupported_display_impl, unimplemented_window_handle) => {
|
||||
return Err(SoftBufferError::UnsupportedWindowPlatform {
|
||||
human_readable_window_platform_name: window_handle_type_name(
|
||||
&unimplemented_window_handle,
|
||||
),
|
||||
human_readable_display_platform_name: unsupported_display_impl.variant_name(),
|
||||
window_handle: unimplemented_window_handle,
|
||||
})
|
||||
ContextDispatch::Orbital(_) => {
|
||||
SurfaceDispatch::Orbital(leap!(orbital::OrbitalImpl::new(window)))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -382,7 +342,7 @@ impl Surface {
|
|||
/// - On DRM/KMS, there is no reliable and sound way to wait for the page flip to happen from within
|
||||
/// `softbuffer`. Therefore it is the responsibility of the user to wait for the page flip before
|
||||
/// sending another frame.
|
||||
pub fn buffer_mut(&mut self) -> Result<Buffer, SoftBufferError> {
|
||||
pub fn buffer_mut(&mut self) -> Result<Buffer<'_, D, W>, SoftBufferError> {
|
||||
Ok(Buffer {
|
||||
buffer_impl: self.surface_impl.buffer_mut()?,
|
||||
_marker: PhantomData,
|
||||
|
|
@ -426,12 +386,12 @@ impl Surface {
|
|||
/// Currently [`Buffer::present`] must block copying image data on:
|
||||
/// - Web
|
||||
/// - macOS
|
||||
pub struct Buffer<'a> {
|
||||
buffer_impl: BufferDispatch<'a>,
|
||||
pub struct Buffer<'a, D, W> {
|
||||
buffer_impl: BufferDispatch<'a, D, W>,
|
||||
_marker: PhantomData<*mut ()>,
|
||||
}
|
||||
|
||||
impl<'a> Buffer<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> Buffer<'a, D, W> {
|
||||
/// Is age is the number of frames ago this buffer was last presented. So if the value is
|
||||
/// `1`, it is the same as the last frame, and if it is `2`, it is the same as the frame
|
||||
/// before that (for backends using double buffering). If the value is `0`, it is a new
|
||||
|
|
@ -474,7 +434,7 @@ impl<'a> Buffer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::Deref for Buffer<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::Deref for Buffer<'a, D, W> {
|
||||
type Target = [u32];
|
||||
|
||||
#[inline]
|
||||
|
|
@ -483,13 +443,37 @@ impl<'a> ops::Deref for Buffer<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ops::DerefMut for Buffer<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> ops::DerefMut for Buffer<'a, D, W> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut [u32] {
|
||||
self.buffer_impl.pixels_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// There is no display handle.
|
||||
#[derive(Debug)]
|
||||
pub struct NoDisplayHandle(core::convert::Infallible);
|
||||
|
||||
impl HasDisplayHandle for NoDisplayHandle {
|
||||
fn display_handle(
|
||||
&self,
|
||||
) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
|
||||
match self.0 {}
|
||||
}
|
||||
}
|
||||
|
||||
/// There is no window handle.
|
||||
#[derive(Debug)]
|
||||
pub struct NoWindowHandle(());
|
||||
|
||||
impl HasWindowHandle for NoWindowHandle {
|
||||
fn window_handle(
|
||||
&self,
|
||||
) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
|
||||
Err(raw_window_handle::HandleError::NotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
fn window_handle_type_name(handle: &RawWindowHandle) -> &'static str {
|
||||
match handle {
|
||||
RawWindowHandle::Xlib(_) => "Xlib",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use raw_window_handle::OrbitalWindowHandle;
|
||||
use std::{cmp, num::NonZeroU32, slice, str};
|
||||
use crate::error::InitError;
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, OrbitalWindowHandle, RawWindowHandle};
|
||||
use std::{cmp, marker::PhantomData, num::NonZeroU32, slice, str};
|
||||
|
||||
use crate::{Rect, SoftBufferError};
|
||||
|
||||
|
|
@ -53,20 +54,30 @@ impl Drop for OrbitalMap {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct OrbitalImpl {
|
||||
pub struct OrbitalImpl<D, W> {
|
||||
handle: OrbitalWindowHandle,
|
||||
width: u32,
|
||||
height: u32,
|
||||
presented: bool,
|
||||
_window_source: W,
|
||||
_display: PhantomData<D>,
|
||||
}
|
||||
|
||||
impl OrbitalImpl {
|
||||
pub fn new(handle: OrbitalWindowHandle) -> Result<Self, SoftBufferError> {
|
||||
impl<D: HasDisplayHandle, W: HasWindowHandle> OrbitalImpl<D, W> {
|
||||
pub(crate) fn new(window: W) -> Result<Self, InitError<W>> {
|
||||
let raw = window.window_handle()?.as_raw();
|
||||
let handle = match raw {
|
||||
RawWindowHandle::Orbital(handle) => handle,
|
||||
_ => return Err(InitError::Unsupported(window)),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
handle,
|
||||
width: 0,
|
||||
height: 0,
|
||||
presented: false,
|
||||
_window_source: window,
|
||||
_display: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +93,7 @@ impl OrbitalImpl {
|
|||
}
|
||||
|
||||
fn window_fd(&self) -> usize {
|
||||
self.handle.window as usize
|
||||
self.handle.window.as_ptr() as usize
|
||||
}
|
||||
|
||||
// Read the current width and size
|
||||
|
|
@ -105,7 +116,7 @@ impl OrbitalImpl {
|
|||
(window_width, window_height)
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
let (window_width, window_height) = self.window_size();
|
||||
let pixels = if self.width as usize == window_width && self.height as usize == window_height
|
||||
{
|
||||
|
|
@ -162,12 +173,12 @@ enum Pixels {
|
|||
Buffer(Vec<u32>),
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a> {
|
||||
imp: &'a mut OrbitalImpl,
|
||||
pub struct BufferImpl<'a, D, W> {
|
||||
imp: &'a mut OrbitalImpl<D, W>,
|
||||
pixels: Pixels,
|
||||
}
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
match &self.pixels {
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ use crate::SoftBufferError;
|
|||
///
|
||||
/// This should be consistent with stacked borrow rules, and miri seems to
|
||||
/// accept it at least in simple cases.
|
||||
pub struct BorrowStack<'a, T: 'static + ?Sized, U: 'static + ?Sized> {
|
||||
pub struct BorrowStack<'a, T: 'a + ?Sized, U: 'a + ?Sized> {
|
||||
container: *mut T,
|
||||
member: *mut U,
|
||||
_phantom: std::marker::PhantomData<&'a mut T>,
|
||||
}
|
||||
|
||||
impl<'a, T: 'static + ?Sized, U: 'static + ?Sized> BorrowStack<'a, T, U> {
|
||||
impl<'a, T: 'a + ?Sized, U: 'a + ?Sized> BorrowStack<'a, T, U> {
|
||||
pub fn new<F>(container: &'a mut T, f: F) -> Result<Self, SoftBufferError>
|
||||
where
|
||||
F: for<'b> FnOnce(&'b mut T) -> Result<&'b mut U, SoftBufferError>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
use crate::{error::SwResultExt, util, Rect, SoftBufferError};
|
||||
use raw_window_handle::{WaylandDisplayHandle, WaylandWindowHandle};
|
||||
use crate::{
|
||||
error::{InitError, SwResultExt},
|
||||
util, Rect, SoftBufferError,
|
||||
};
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
num::{NonZeroI32, NonZeroU32},
|
||||
|
|
@ -17,17 +20,31 @@ use buffer::WaylandBuffer;
|
|||
|
||||
struct State;
|
||||
|
||||
pub struct WaylandDisplayImpl {
|
||||
conn: Connection,
|
||||
pub struct WaylandDisplayImpl<D: ?Sized> {
|
||||
conn: Option<Connection>,
|
||||
event_queue: RefCell<EventQueue<State>>,
|
||||
qh: QueueHandle<State>,
|
||||
shm: wl_shm::WlShm,
|
||||
|
||||
/// The object that owns the display handle.
|
||||
///
|
||||
/// This has to be dropped *after* the `conn` field, because the `conn` field implicitly borrows
|
||||
/// this.
|
||||
_display: D,
|
||||
}
|
||||
|
||||
impl WaylandDisplayImpl {
|
||||
pub unsafe fn new(display_handle: WaylandDisplayHandle) -> Result<Self, SoftBufferError> {
|
||||
// SAFETY: Ensured by user
|
||||
let backend = unsafe { Backend::from_foreign_display(display_handle.display as *mut _) };
|
||||
impl<D: HasDisplayHandle + ?Sized> WaylandDisplayImpl<D> {
|
||||
pub(crate) fn new(display: D) -> Result<Self, InitError<D>>
|
||||
where
|
||||
D: Sized,
|
||||
{
|
||||
let raw = display.display_handle()?.as_raw();
|
||||
let wayland_handle = match raw {
|
||||
RawDisplayHandle::Wayland(w) => w.display,
|
||||
_ => return Err(InitError::Unsupported(display)),
|
||||
};
|
||||
|
||||
let backend = unsafe { Backend::from_foreign_display(wayland_handle.as_ptr().cast()) };
|
||||
let conn = Connection::from_backend(backend);
|
||||
let (globals, event_queue) =
|
||||
registry_queue_init(&conn).swbuf_err("Failed to make round trip to server")?;
|
||||
|
|
@ -36,41 +53,63 @@ impl WaylandDisplayImpl {
|
|||
.bind(&qh, 1..=1, ())
|
||||
.swbuf_err("Failed to instantiate Wayland Shm")?;
|
||||
Ok(Self {
|
||||
conn,
|
||||
conn: Some(conn),
|
||||
event_queue: RefCell::new(event_queue),
|
||||
qh,
|
||||
shm,
|
||||
_display: display,
|
||||
})
|
||||
}
|
||||
|
||||
fn conn(&self) -> &Connection {
|
||||
self.conn.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WaylandImpl {
|
||||
display: Rc<WaylandDisplayImpl>,
|
||||
surface: wl_surface::WlSurface,
|
||||
buffers: Option<(WaylandBuffer, WaylandBuffer)>,
|
||||
size: Option<(NonZeroI32, NonZeroI32)>,
|
||||
impl<D: ?Sized> Drop for WaylandDisplayImpl<D> {
|
||||
fn drop(&mut self) {
|
||||
// Make sure the connection is dropped first.
|
||||
self.conn = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl WaylandImpl {
|
||||
pub unsafe fn new(
|
||||
window_handle: WaylandWindowHandle,
|
||||
display: Rc<WaylandDisplayImpl>,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
// SAFETY: Ensured by user
|
||||
pub struct WaylandImpl<D: ?Sized, W: ?Sized> {
|
||||
display: Rc<WaylandDisplayImpl<D>>,
|
||||
surface: Option<wl_surface::WlSurface>,
|
||||
buffers: Option<(WaylandBuffer, WaylandBuffer)>,
|
||||
size: Option<(NonZeroI32, NonZeroI32)>,
|
||||
|
||||
/// The pointer to the window object.
|
||||
///
|
||||
/// This has to be dropped *after* the `surface` field, because the `surface` field implicitly
|
||||
/// borrows this.
|
||||
_window: W,
|
||||
}
|
||||
|
||||
impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> WaylandImpl<D, W> {
|
||||
pub(crate) fn new(window: W, display: Rc<WaylandDisplayImpl<D>>) -> Result<Self, InitError<W>> {
|
||||
// Get the raw Wayland window.
|
||||
let raw = window.window_handle()?.as_raw();
|
||||
let wayland_handle = match raw {
|
||||
RawWindowHandle::Wayland(w) => w.surface,
|
||||
_ => return Err(InitError::Unsupported(window)),
|
||||
};
|
||||
|
||||
let surface_id = unsafe {
|
||||
ObjectId::from_ptr(
|
||||
wl_surface::WlSurface::interface(),
|
||||
window_handle.surface as _,
|
||||
wayland_handle.as_ptr().cast(),
|
||||
)
|
||||
}
|
||||
.swbuf_err("Failed to create proxy for surface ID.")?;
|
||||
let surface = wl_surface::WlSurface::from_id(&display.conn, surface_id)
|
||||
let surface = wl_surface::WlSurface::from_id(display.conn(), surface_id)
|
||||
.swbuf_err("Failed to create proxy for surface ID.")?;
|
||||
Ok(Self {
|
||||
display,
|
||||
surface,
|
||||
surface: Some(surface),
|
||||
buffers: Default::default(),
|
||||
size: None,
|
||||
_window: window,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -86,7 +125,7 @@ impl WaylandImpl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
let (width, height) = self
|
||||
.size
|
||||
.expect("Must set size of surface before calling `buffer_mut()`");
|
||||
|
|
@ -155,13 +194,13 @@ impl WaylandImpl {
|
|||
// Swap front and back buffer
|
||||
std::mem::swap(front, back);
|
||||
|
||||
front.attach(&self.surface);
|
||||
front.attach(self.surface.as_ref().unwrap());
|
||||
|
||||
// Like Mesa's EGL/WSI implementation, we damage the whole buffer with `i32::MAX` if
|
||||
// the compositor doesn't support `damage_buffer`.
|
||||
// https://bugs.freedesktop.org/show_bug.cgi?id=78190
|
||||
if self.surface.version() < 4 {
|
||||
self.surface.damage(0, 0, i32::MAX, i32::MAX);
|
||||
if self.surface().version() < 4 {
|
||||
self.surface().damage(0, 0, i32::MAX, i32::MAX);
|
||||
} else {
|
||||
for rect in damage {
|
||||
// Introduced in version 4, it is an error to use this request in version 3 or lower.
|
||||
|
|
@ -174,25 +213,36 @@ impl WaylandImpl {
|
|||
))
|
||||
})()
|
||||
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
|
||||
self.surface.damage_buffer(x, y, width, height);
|
||||
self.surface().damage_buffer(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
self.surface.commit();
|
||||
self.surface().commit();
|
||||
}
|
||||
|
||||
let _ = self.display.event_queue.borrow_mut().flush();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn surface(&self) -> &wl_surface::WlSurface {
|
||||
self.surface.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a> {
|
||||
stack: util::BorrowStack<'a, WaylandImpl, [u32]>,
|
||||
impl<D: ?Sized, W: ?Sized> Drop for WaylandImpl<D, W> {
|
||||
fn drop(&mut self) {
|
||||
// Make sure the surface is dropped first.
|
||||
self.surface = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a, D: ?Sized, W> {
|
||||
stack: util::BorrowStack<'a, WaylandImpl<D, W>, [u32]>,
|
||||
age: u8,
|
||||
}
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle> BufferImpl<'a, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
self.stack.member()
|
||||
|
|
|
|||
75
src/web.rs
75
src/web.rs
|
|
@ -2,39 +2,48 @@
|
|||
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use js_sys::Object;
|
||||
use raw_window_handle::WebWindowHandle;
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle};
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use web_sys::ImageData;
|
||||
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
||||
use web_sys::{OffscreenCanvas, OffscreenCanvasRenderingContext2d};
|
||||
|
||||
use crate::error::SwResultExt;
|
||||
use crate::{util, Rect, SoftBufferError};
|
||||
use crate::error::{InitError, SwResultExt};
|
||||
use crate::{util, NoDisplayHandle, NoWindowHandle, Rect, SoftBufferError};
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
/// Display implementation for the web platform.
|
||||
///
|
||||
/// This just caches the document to prevent having to query it every time.
|
||||
pub struct WebDisplayImpl {
|
||||
pub struct WebDisplayImpl<D> {
|
||||
document: web_sys::Document,
|
||||
_display: D,
|
||||
}
|
||||
|
||||
impl WebDisplayImpl {
|
||||
pub(super) fn new() -> Result<Self, SoftBufferError> {
|
||||
impl<D: HasDisplayHandle> WebDisplayImpl<D> {
|
||||
pub(super) fn new(display: D) -> Result<Self, InitError<D>> {
|
||||
let raw = display.display_handle()?.as_raw();
|
||||
match raw {
|
||||
RawDisplayHandle::Web(..) => {}
|
||||
_ => return Err(InitError::Unsupported(display)),
|
||||
}
|
||||
|
||||
let document = web_sys::window()
|
||||
.swbuf_err("`Window` is not present in this runtime")?
|
||||
.document()
|
||||
.swbuf_err("`Document` is not present in this runtime")?;
|
||||
|
||||
Ok(Self { document })
|
||||
Ok(Self {
|
||||
document,
|
||||
_display: display,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WebImpl {
|
||||
pub struct WebImpl<D, W> {
|
||||
/// The handle and context to the canvas that we're drawing to.
|
||||
canvas: Canvas,
|
||||
|
||||
|
|
@ -46,6 +55,12 @@ pub struct WebImpl {
|
|||
|
||||
/// The current canvas width/height.
|
||||
size: Option<(NonZeroU32, NonZeroU32)>,
|
||||
|
||||
/// The underlying window handle.
|
||||
_window: W,
|
||||
|
||||
/// The underlying display handle.
|
||||
_display: PhantomData<D>,
|
||||
}
|
||||
|
||||
/// Holding canvas and context for [`HtmlCanvasElement`] or [`OffscreenCanvas`],
|
||||
|
|
@ -61,8 +76,13 @@ enum Canvas {
|
|||
},
|
||||
}
|
||||
|
||||
impl WebImpl {
|
||||
pub fn new(display: &WebDisplayImpl, handle: WebWindowHandle) -> Result<Self, SoftBufferError> {
|
||||
impl<D: HasDisplayHandle, W: HasWindowHandle> WebImpl<D, W> {
|
||||
pub(crate) fn new(display: &WebDisplayImpl<D>, window: W) -> Result<Self, InitError<W>> {
|
||||
let raw = window.window_handle()?.as_raw();
|
||||
let handle = match raw {
|
||||
RawWindowHandle::Web(handle) => handle,
|
||||
_ => return Err(InitError::Unsupported(window)),
|
||||
};
|
||||
let canvas: HtmlCanvasElement = display
|
||||
.document
|
||||
.query_selector(&format!("canvas[data-raw-handle=\"{}\"]", handle.id))
|
||||
|
|
@ -72,10 +92,10 @@ impl WebImpl {
|
|||
// We already made sure this was a canvas in `querySelector`.
|
||||
.unchecked_into();
|
||||
|
||||
Self::from_canvas(canvas)
|
||||
Self::from_canvas(canvas, window).map_err(InitError::Failure)
|
||||
}
|
||||
|
||||
fn from_canvas(canvas: HtmlCanvasElement) -> Result<Self, SoftBufferError> {
|
||||
fn from_canvas(canvas: HtmlCanvasElement, window: W) -> Result<Self, SoftBufferError> {
|
||||
let ctx = Self::resolve_ctx(canvas.get_context("2d").ok(), "CanvasRenderingContext2d")?;
|
||||
|
||||
Ok(Self {
|
||||
|
|
@ -83,10 +103,12 @@ impl WebImpl {
|
|||
buffer: Vec::new(),
|
||||
buffer_presented: false,
|
||||
size: None,
|
||||
_window: window,
|
||||
_display: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
fn from_offscreen_canvas(canvas: OffscreenCanvas) -> Result<Self, SoftBufferError> {
|
||||
fn from_offscreen_canvas(canvas: OffscreenCanvas, window: W) -> Result<Self, SoftBufferError> {
|
||||
let ctx = Self::resolve_ctx(
|
||||
canvas.get_context("2d").ok(),
|
||||
"OffscreenCanvasRenderingContext2d",
|
||||
|
|
@ -97,6 +119,8 @@ impl WebImpl {
|
|||
buffer: Vec::new(),
|
||||
buffer_presented: false,
|
||||
size: None,
|
||||
_window: window,
|
||||
_display: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +158,7 @@ impl WebImpl {
|
|||
}
|
||||
|
||||
/// Get a pointer to the mutable buffer.
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
Ok(BufferImpl { imp: self })
|
||||
}
|
||||
|
||||
|
|
@ -258,9 +282,9 @@ pub trait SurfaceExtWeb: Sized {
|
|||
fn from_offscreen_canvas(offscreen_canvas: OffscreenCanvas) -> Result<Self, SoftBufferError>;
|
||||
}
|
||||
|
||||
impl SurfaceExtWeb for crate::Surface {
|
||||
impl SurfaceExtWeb for crate::Surface<NoDisplayHandle, NoWindowHandle> {
|
||||
fn from_canvas(canvas: HtmlCanvasElement) -> Result<Self, SoftBufferError> {
|
||||
let imple = crate::SurfaceDispatch::Web(WebImpl::from_canvas(canvas)?);
|
||||
let imple = crate::SurfaceDispatch::Web(WebImpl::from_canvas(canvas, NoWindowHandle(()))?);
|
||||
|
||||
Ok(Self {
|
||||
surface_impl: Box::new(imple),
|
||||
|
|
@ -269,7 +293,10 @@ impl SurfaceExtWeb for crate::Surface {
|
|||
}
|
||||
|
||||
fn from_offscreen_canvas(offscreen_canvas: OffscreenCanvas) -> Result<Self, SoftBufferError> {
|
||||
let imple = crate::SurfaceDispatch::Web(WebImpl::from_offscreen_canvas(offscreen_canvas)?);
|
||||
let imple = crate::SurfaceDispatch::Web(WebImpl::from_offscreen_canvas(
|
||||
offscreen_canvas,
|
||||
NoWindowHandle(()),
|
||||
)?);
|
||||
|
||||
Ok(Self {
|
||||
surface_impl: Box::new(imple),
|
||||
|
|
@ -326,11 +353,11 @@ impl Canvas {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a> {
|
||||
imp: &'a mut WebImpl,
|
||||
pub struct BufferImpl<'a, D, W> {
|
||||
imp: &'a mut WebImpl<D, W>,
|
||||
}
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
&self.imp.buffer
|
||||
}
|
||||
|
|
|
|||
45
src/win32.rs
45
src/win32.rs
|
|
@ -3,9 +3,10 @@
|
|||
//! This module converts the input buffer into a bitmap and then stretches it to the window.
|
||||
|
||||
use crate::{Rect, SoftBufferError};
|
||||
use raw_window_handle::Win32WindowHandle;
|
||||
use raw_window_handle::{HasDisplayHandle, HasWindowHandle, RawWindowHandle};
|
||||
|
||||
use std::io;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
use std::num::{NonZeroI32, NonZeroU32};
|
||||
use std::ptr::{self, NonNull};
|
||||
|
|
@ -128,7 +129,7 @@ impl Buffer {
|
|||
}
|
||||
|
||||
/// The handle to a window for software buffering.
|
||||
pub struct Win32Impl {
|
||||
pub struct Win32Impl<D: ?Sized, W> {
|
||||
/// The window handle.
|
||||
window: HWND,
|
||||
|
||||
|
|
@ -137,6 +138,16 @@ pub struct Win32Impl {
|
|||
|
||||
/// The buffer used to hold the image.
|
||||
buffer: Option<Buffer>,
|
||||
|
||||
/// The handle for the window.
|
||||
///
|
||||
/// This should be kept alive in order to keep `window` valid.
|
||||
_window: W,
|
||||
|
||||
/// The display handle.
|
||||
///
|
||||
/// We don't use this, but other code might.
|
||||
_display: PhantomData<D>,
|
||||
}
|
||||
|
||||
/// The Win32-compatible bitmap information.
|
||||
|
|
@ -146,21 +157,18 @@ struct BitmapInfo {
|
|||
bmi_colors: [Gdi::RGBQUAD; 3],
|
||||
}
|
||||
|
||||
impl Win32Impl {
|
||||
impl<D: HasDisplayHandle, W: HasWindowHandle> Win32Impl<D, W> {
|
||||
/// Create a new `Win32Impl` from a `Win32WindowHandle`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `Win32WindowHandle` must be a valid window handle.
|
||||
pub unsafe fn new(handle: &Win32WindowHandle) -> Result<Self, crate::SoftBufferError> {
|
||||
// It is valid for the window handle to be null here. Error out if it is.
|
||||
if handle.hwnd.is_null() {
|
||||
return Err(SoftBufferError::IncompleteWindowHandle);
|
||||
}
|
||||
pub(crate) fn new(window: W) -> Result<Self, crate::error::InitError<W>> {
|
||||
let raw = window.window_handle()?.as_raw();
|
||||
let handle = match raw {
|
||||
RawWindowHandle::Win32(handle) => handle,
|
||||
_ => return Err(crate::InitError::Unsupported(window)),
|
||||
};
|
||||
|
||||
// Get the handle to the device context.
|
||||
// SAFETY: We have confirmed that the window handle is valid.
|
||||
let hwnd = handle.hwnd as HWND;
|
||||
let hwnd = handle.hwnd.get() as HWND;
|
||||
let dc = unsafe { Gdi::GetDC(hwnd) };
|
||||
|
||||
// GetDC returns null if there is a platform error.
|
||||
|
|
@ -168,13 +176,16 @@ impl Win32Impl {
|
|||
return Err(SoftBufferError::PlatformError(
|
||||
Some("Device Context is null".into()),
|
||||
Some(Box::new(io::Error::last_os_error())),
|
||||
));
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
dc,
|
||||
window: hwnd,
|
||||
buffer: None,
|
||||
_window: window,
|
||||
_display: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +208,7 @@ impl Win32Impl {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
pub fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
if self.buffer.is_none() {
|
||||
panic!("Must set size of surface before calling `buffer_mut()`");
|
||||
}
|
||||
|
|
@ -235,9 +246,9 @@ impl Win32Impl {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a>(&'a mut Win32Impl);
|
||||
pub struct BufferImpl<'a, D, W>(&'a mut Win32Impl<D, W>);
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
impl<'a, D: HasDisplayHandle, W: HasWindowHandle> BufferImpl<'a, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
self.0.buffer.as_ref().unwrap().pixels()
|
||||
|
|
|
|||
207
src/x11.rs
207
src/x11.rs
|
|
@ -5,10 +5,14 @@
|
|||
|
||||
#![allow(clippy::uninlined_format_args)]
|
||||
|
||||
use crate::error::SwResultExt;
|
||||
use crate::error::{InitError, SwResultExt};
|
||||
use crate::{Rect, SoftBufferError};
|
||||
use raw_window_handle::{XcbDisplayHandle, XcbWindowHandle, XlibDisplayHandle, XlibWindowHandle};
|
||||
use raw_window_handle::{
|
||||
HasDisplayHandle, HasWindowHandle, RawDisplayHandle, RawWindowHandle, XcbDisplayHandle,
|
||||
XcbWindowHandle,
|
||||
};
|
||||
use rustix::{fd, mm, shm as posix_shm};
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
fs::File,
|
||||
|
|
@ -27,57 +31,62 @@ use x11rb::protocol::shm::{self, ConnectionExt as _};
|
|||
use x11rb::protocol::xproto::{self, ConnectionExt as _};
|
||||
use x11rb::xcb_ffi::XCBConnection;
|
||||
|
||||
pub struct X11DisplayImpl {
|
||||
pub struct X11DisplayImpl<D: ?Sized> {
|
||||
/// The handle to the XCB connection.
|
||||
connection: XCBConnection,
|
||||
connection: Option<XCBConnection>,
|
||||
|
||||
/// SHM extension is available.
|
||||
is_shm_available: bool,
|
||||
|
||||
/// The generic display where the `connection` field comes from.
|
||||
///
|
||||
/// Without `&mut`, the underlying connection cannot be closed without other unsafe behavior.
|
||||
/// With `&mut`, the connection can be dropped without us knowing about it. Therefore, we
|
||||
/// cannot provide `&mut` access to this field.
|
||||
_display: D,
|
||||
}
|
||||
|
||||
impl X11DisplayImpl {
|
||||
pub(crate) unsafe fn from_xlib(
|
||||
display_handle: XlibDisplayHandle,
|
||||
) -> Result<X11DisplayImpl, SoftBufferError> {
|
||||
// Validate the display handle to ensure we can use it.
|
||||
if display_handle.display.is_null() {
|
||||
return Err(SoftBufferError::IncompleteDisplayHandle);
|
||||
}
|
||||
impl<D: HasDisplayHandle + ?Sized> X11DisplayImpl<D> {
|
||||
/// Create a new `X11DisplayImpl`.
|
||||
pub(crate) fn new(display: D) -> Result<Self, InitError<D>>
|
||||
where
|
||||
D: Sized,
|
||||
{
|
||||
// Get the underlying libxcb handle.
|
||||
let raw = display.display_handle()?.as_raw();
|
||||
let xcb_handle = match raw {
|
||||
RawDisplayHandle::Xcb(xcb_handle) => xcb_handle,
|
||||
RawDisplayHandle::Xlib(xlib) => {
|
||||
// Convert to an XCB handle.
|
||||
let display = match xlib.display {
|
||||
Some(display) => display,
|
||||
None => return Err(SoftBufferError::IncompleteDisplayHandle.into()),
|
||||
};
|
||||
|
||||
// Get the underlying XCB connection.
|
||||
// SAFETY: The user has asserted that the display handle is valid.
|
||||
let connection = unsafe {
|
||||
let display = tiny_xlib::Display::from_ptr(display_handle.display);
|
||||
display.as_raw_xcb_connection()
|
||||
// Get the underlying XCB connection.
|
||||
// SAFETY: The user has asserted that the display handle is valid.
|
||||
let connection = unsafe {
|
||||
let display = tiny_xlib::Display::from_ptr(display.as_ptr());
|
||||
NonNull::new_unchecked(display.as_raw_xcb_connection())
|
||||
};
|
||||
|
||||
// Construct the equivalent XCB display and window handles.
|
||||
XcbDisplayHandle::new(Some(connection.cast()), xlib.screen)
|
||||
}
|
||||
_ => return Err(InitError::Unsupported(display)),
|
||||
};
|
||||
|
||||
// Construct the equivalent XCB display and window handles.
|
||||
let mut xcb_display_handle = XcbDisplayHandle::empty();
|
||||
xcb_display_handle.connection = connection.cast();
|
||||
xcb_display_handle.screen = display_handle.screen;
|
||||
|
||||
// SAFETY: If the user passed in valid Xlib handles, then these are valid XCB handles.
|
||||
unsafe { Self::from_xcb(xcb_display_handle) }
|
||||
}
|
||||
|
||||
/// Create a new `X11Impl` from a `XcbWindowHandle` and `XcbDisplayHandle`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `XcbWindowHandle` and `XcbDisplayHandle` must be valid.
|
||||
pub(crate) unsafe fn from_xcb(
|
||||
display_handle: XcbDisplayHandle,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
// Check that the handle is valid.
|
||||
if display_handle.connection.is_null() {
|
||||
return Err(SoftBufferError::IncompleteDisplayHandle);
|
||||
}
|
||||
// Validate the display handle to ensure we can use it.
|
||||
let connection = match xcb_handle.connection {
|
||||
Some(conn) => conn,
|
||||
None => return Err(SoftBufferError::IncompleteDisplayHandle.into()),
|
||||
};
|
||||
|
||||
// Wrap the display handle in an x11rb connection.
|
||||
// SAFETY: We don't own the connection, so don't drop it. We also assert that the connection is valid.
|
||||
let connection = {
|
||||
let result =
|
||||
unsafe { XCBConnection::from_raw_xcb_connection(display_handle.connection, false) };
|
||||
unsafe { XCBConnection::from_raw_xcb_connection(connection.as_ptr(), false) };
|
||||
|
||||
result.swbuf_err("Failed to wrap XCB connection")?
|
||||
};
|
||||
|
|
@ -88,16 +97,25 @@ impl X11DisplayImpl {
|
|||
}
|
||||
|
||||
Ok(Self {
|
||||
connection,
|
||||
connection: Some(connection),
|
||||
is_shm_available,
|
||||
_display: display,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: ?Sized> X11DisplayImpl<D> {
|
||||
fn connection(&self) -> &XCBConnection {
|
||||
self.connection
|
||||
.as_ref()
|
||||
.expect("X11DisplayImpl::connection() called after X11DisplayImpl::drop()")
|
||||
}
|
||||
}
|
||||
|
||||
/// The handle to an X11 drawing context.
|
||||
pub struct X11Impl {
|
||||
pub struct X11Impl<D: ?Sized, W: ?Sized> {
|
||||
/// X display this window belongs to.
|
||||
display: Rc<X11DisplayImpl>,
|
||||
display: Rc<X11DisplayImpl<D>>,
|
||||
|
||||
/// The window to draw to.
|
||||
window: xproto::Window,
|
||||
|
|
@ -119,6 +137,9 @@ pub struct X11Impl {
|
|||
|
||||
/// The current buffer width/height.
|
||||
size: Option<(NonZeroU16, NonZeroU16)>,
|
||||
|
||||
/// Keep the window alive.
|
||||
_window_handle: W,
|
||||
}
|
||||
|
||||
/// The buffer that is being drawn to.
|
||||
|
|
@ -149,53 +170,41 @@ struct ShmBuffer {
|
|||
done_processing: Option<SequenceNumber>,
|
||||
}
|
||||
|
||||
impl X11Impl {
|
||||
/// Create a new `X11Impl` from a `XlibWindowHandle` and `XlibDisplayHandle`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `XlibWindowHandle` and `XlibDisplayHandle` must be valid.
|
||||
pub unsafe fn from_xlib(
|
||||
window_handle: XlibWindowHandle,
|
||||
display: Rc<X11DisplayImpl>,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
let mut xcb_window_handle = XcbWindowHandle::empty();
|
||||
xcb_window_handle.window = window_handle.window as _;
|
||||
xcb_window_handle.visual_id = window_handle.visual_id as _;
|
||||
impl<D: HasDisplayHandle + ?Sized, W: HasWindowHandle> X11Impl<D, W> {
|
||||
/// Create a new `X11Impl` from a `HasWindowHandle`.
|
||||
pub(crate) fn new(window_src: W, display: Rc<X11DisplayImpl<D>>) -> Result<Self, InitError<W>> {
|
||||
// Get the underlying raw window handle.
|
||||
let raw = window_src.window_handle()?.as_raw();
|
||||
let window_handle = match raw {
|
||||
RawWindowHandle::Xcb(xcb) => xcb,
|
||||
RawWindowHandle::Xlib(xlib) => {
|
||||
let window = match NonZeroU32::new(xlib.window as u32) {
|
||||
Some(window) => window,
|
||||
None => return Err(SoftBufferError::IncompleteWindowHandle.into()),
|
||||
};
|
||||
let mut xcb_window_handle = XcbWindowHandle::new(window);
|
||||
xcb_window_handle.visual_id = NonZeroU32::new(xlib.visual_id as u32);
|
||||
xcb_window_handle
|
||||
}
|
||||
_ => {
|
||||
return Err(InitError::Unsupported(window_src));
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: If the user passed in valid Xlib handles, then these are valid XCB handles.
|
||||
unsafe { Self::from_xcb(xcb_window_handle, display) }
|
||||
}
|
||||
|
||||
/// Create a new `X11Impl` from a `XcbWindowHandle` and `XcbDisplayHandle`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `XcbWindowHandle` and `XcbDisplayHandle` must be valid.
|
||||
pub(crate) unsafe fn from_xcb(
|
||||
window_handle: XcbWindowHandle,
|
||||
display: Rc<X11DisplayImpl>,
|
||||
) -> Result<Self, SoftBufferError> {
|
||||
log::trace!("new: window_handle={:X}", window_handle.window,);
|
||||
|
||||
// Check that the handle is valid.
|
||||
if window_handle.window == 0 {
|
||||
return Err(SoftBufferError::IncompleteWindowHandle);
|
||||
}
|
||||
|
||||
let window = window_handle.window;
|
||||
log::trace!("new: window_handle={:X}", window_handle.window);
|
||||
let window = window_handle.window.get();
|
||||
|
||||
// Run in parallel: start getting the window depth and (if necessary) visual.
|
||||
let display2 = display.clone();
|
||||
let tokens = {
|
||||
let geometry_token = display2
|
||||
.connection
|
||||
.connection()
|
||||
.get_geometry(window)
|
||||
.swbuf_err("Failed to send geometry request")?;
|
||||
let window_attrs_token = if window_handle.visual_id == 0 {
|
||||
let window_attrs_token = if window_handle.visual_id.is_none() {
|
||||
Some(
|
||||
display2
|
||||
.connection
|
||||
.connection()
|
||||
.get_window_attributes(window)
|
||||
.swbuf_err("Failed to send window attributes request")?,
|
||||
)
|
||||
|
|
@ -208,11 +217,11 @@ impl X11Impl {
|
|||
|
||||
// Create a new graphics context to draw to.
|
||||
let gc = display
|
||||
.connection
|
||||
.connection()
|
||||
.generate_id()
|
||||
.swbuf_err("Failed to generate GC ID")?;
|
||||
display
|
||||
.connection
|
||||
.connection()
|
||||
.create_gc(
|
||||
gc,
|
||||
window,
|
||||
|
|
@ -229,7 +238,7 @@ impl X11Impl {
|
|||
.reply()
|
||||
.swbuf_err("Failed to get geometry reply")?;
|
||||
let visual_id = match window_attrs_token {
|
||||
None => window_handle.visual_id,
|
||||
None => window_handle.visual_id.unwrap().get(),
|
||||
Some(window_attrs) => {
|
||||
window_attrs
|
||||
.reply()
|
||||
|
|
@ -262,6 +271,7 @@ impl X11Impl {
|
|||
buffer,
|
||||
buffer_presented: false,
|
||||
size: None,
|
||||
_window_handle: window_src,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +300,7 @@ impl X11Impl {
|
|||
if self.size != Some((width, height)) {
|
||||
self.buffer_presented = false;
|
||||
self.buffer
|
||||
.resize(&self.display.connection, width.get(), height.get())
|
||||
.resize(self.display.connection(), width.get(), height.get())
|
||||
.swbuf_err("Failed to resize X11 buffer")?;
|
||||
|
||||
// We successfully resized the buffer.
|
||||
|
|
@ -301,11 +311,11 @@ impl X11Impl {
|
|||
}
|
||||
|
||||
/// Get a mutable reference to the buffer.
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl, SoftBufferError> {
|
||||
pub(crate) fn buffer_mut(&mut self) -> Result<BufferImpl<'_, D, W>, SoftBufferError> {
|
||||
log::trace!("buffer_mut: window={:X}", self.window);
|
||||
|
||||
// Finish waiting on the previous `shm::PutImage` request, if any.
|
||||
self.buffer.finish_wait(&self.display.connection)?;
|
||||
self.buffer.finish_wait(self.display.connection())?;
|
||||
|
||||
// We can now safely call `buffer_mut` on the buffer.
|
||||
Ok(BufferImpl(self))
|
||||
|
|
@ -322,7 +332,7 @@ impl X11Impl {
|
|||
// TODO: Is it worth it to do SHM here? Probably not.
|
||||
let reply = self
|
||||
.display
|
||||
.connection
|
||||
.connection()
|
||||
.get_image(
|
||||
xproto::ImageFormat::Z_PIXMAP,
|
||||
self.window,
|
||||
|
|
@ -349,9 +359,9 @@ impl X11Impl {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BufferImpl<'a>(&'a mut X11Impl);
|
||||
pub struct BufferImpl<'a, D: ?Sized, W: ?Sized>(&'a mut X11Impl<D, W>);
|
||||
|
||||
impl<'a> BufferImpl<'a> {
|
||||
impl<'a, D: HasDisplayHandle + ?Sized, W: HasWindowHandle + ?Sized> BufferImpl<'a, D, W> {
|
||||
#[inline]
|
||||
pub fn pixels(&self) -> &[u32] {
|
||||
// SAFETY: We called `finish_wait` on the buffer, so it is safe to call `buffer()`.
|
||||
|
|
@ -388,7 +398,7 @@ impl<'a> BufferImpl<'a> {
|
|||
log::debug!("Falling back to non-SHM method for window drawing.");
|
||||
|
||||
imp.display
|
||||
.connection
|
||||
.connection()
|
||||
.put_image(
|
||||
xproto::ImageFormat::Z_PIXMAP,
|
||||
imp.window,
|
||||
|
|
@ -427,7 +437,7 @@ impl<'a> BufferImpl<'a> {
|
|||
)
|
||||
.ok_or(SoftBufferError::DamageOutOfRange { rect: *rect })?;
|
||||
imp.display
|
||||
.connection
|
||||
.connection()
|
||||
.shm_put_image(
|
||||
imp.window,
|
||||
imp.gc,
|
||||
|
|
@ -451,7 +461,7 @@ impl<'a> BufferImpl<'a> {
|
|||
})
|
||||
.and_then(|()| {
|
||||
// Send a short request to act as a notification for when the X server is done processing the image.
|
||||
shm.begin_wait(&imp.display.connection)
|
||||
shm.begin_wait(imp.display.connection())
|
||||
.swbuf_err("Failed to draw image to window")
|
||||
})?;
|
||||
}
|
||||
|
|
@ -743,15 +753,22 @@ impl Drop for ShmSegment {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drop for X11Impl {
|
||||
impl<D: ?Sized> Drop for X11DisplayImpl<D> {
|
||||
fn drop(&mut self) {
|
||||
// Make sure that the x11rb connection is dropped before its source is.
|
||||
self.connection = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: ?Sized, W: ?Sized> Drop for X11Impl<D, W> {
|
||||
fn drop(&mut self) {
|
||||
// If we used SHM, make sure it's detached from the server.
|
||||
if let Buffer::Shm(mut shm) = mem::replace(&mut self.buffer, Buffer::Wire(Vec::new())) {
|
||||
// If we were in the middle of processing a buffer, wait for it to finish.
|
||||
shm.finish_wait(&self.display.connection).ok();
|
||||
shm.finish_wait(self.display.connection()).ok();
|
||||
|
||||
if let Some((segment, seg_id)) = shm.seg.take() {
|
||||
if let Ok(token) = self.display.connection.shm_detach(seg_id) {
|
||||
if let Ok(token) = self.display.connection().shm_detach(seg_id) {
|
||||
token.ignore_error();
|
||||
}
|
||||
|
||||
|
|
@ -761,7 +778,7 @@ impl Drop for X11Impl {
|
|||
}
|
||||
|
||||
// Close the graphics context that we created.
|
||||
if let Ok(token) = self.display.connection.free_gc(self.gc) {
|
||||
if let Ok(token) = self.display.connection().free_gc(self.gc) {
|
||||
token.ignore_error();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue