use {AsRaw, FromRaw};
use BufferObject;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut};
pub struct Surface<'a, T: 'static> {
ffi: *mut ::ffi::gbm_surface,
_lifetime: PhantomData<&'a ()>,
_bo_userdata: PhantomData<T>,
}
pub struct SurfaceBufferHandle<'a, T: 'static>(&'a Surface<'a, T>, Option<BufferObject<'a, T>>);
impl<'a, T: 'static> Deref for SurfaceBufferHandle<'a, T> {
type Target = BufferObject<'a, T>;
fn deref(&self) -> &Self::Target {
self.1.as_ref().unwrap()
}
}
impl<'a, T: 'static> DerefMut for SurfaceBufferHandle<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.1.as_mut().unwrap()
}
}
impl<'a, T: 'static> Drop for SurfaceBufferHandle<'a, T> {
fn drop(&mut self) {
let mut bo = None;
mem::swap(&mut bo, &mut self.1);
unsafe { ::ffi::gbm_surface_release_buffer(self.0.ffi, bo.as_mut().unwrap().as_raw_mut()) };
mem::forget(bo); }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrontBufferError {
NoFreeBuffers,
Unknown,
}
impl<'a, T: 'static> Surface<'a, T> {
pub fn has_free_buffers(&self) -> bool {
unsafe { ::ffi::gbm_surface_has_free_buffers(self.ffi) != 0 }
}
pub fn lock_front_buffer(&'a self) -> Result<SurfaceBufferHandle<'a, T>, FrontBufferError> {
if unsafe { ::ffi::gbm_surface_has_free_buffers(self.ffi) != 0 } {
let buffer_ptr = unsafe { ::ffi::gbm_surface_lock_front_buffer(self.ffi) };
if !buffer_ptr.is_null() {
let buffer = unsafe { BufferObject::from_raw(buffer_ptr) };
Ok(SurfaceBufferHandle(self, Some(buffer)))
} else {
Err(FrontBufferError::Unknown)
}
} else {
Err(FrontBufferError::NoFreeBuffers)
}
}
}
impl<'a, T: 'static> AsRaw<::ffi::gbm_surface> for Surface<'a, T> {
fn as_raw(&self) -> *const ::ffi::gbm_surface {
self.ffi
}
}
impl<'a, T: 'static> FromRaw<::ffi::gbm_surface> for Surface<'a, T> {
unsafe fn from_raw(ffi: *mut ::ffi::gbm_surface) -> Self {
Surface {
ffi: ffi,
_lifetime: PhantomData,
_bo_userdata: PhantomData,
}
}
}
impl<'a, T: 'static> Drop for Surface<'a, T> {
fn drop(&mut self) {
while self.has_free_buffers() {
if let Ok(mut buffer) = self.lock_front_buffer() {
buffer.take_userdata();
} else {
break;
}
}
unsafe { ::ffi::gbm_surface_destroy(self.ffi) }
}
}