use Proxy;
use protocol::wl_buffer::WlBuffer;
use protocol::wl_shm::WlShm;
use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use std::ops::Deref;
use std::os::raw::c_int;
use std::ptr;
use wayland_sys::cursor::*;
pub fn is_available() -> bool {
is_lib_available()
}
pub struct CursorTheme {
theme: *mut wl_cursor_theme,
}
unsafe impl Send for CursorTheme {}
pub fn load_theme(name: Option<&str>, size: u32, shm: &WlShm) -> CursorTheme {
let ptr = if let Some(theme) = name {
let cstr = CString::new(theme).expect("Theme name contained an interior null.");
unsafe {
ffi_dispatch!(
WAYLAND_CURSOR_HANDLE,
wl_cursor_theme_load,
cstr.as_ptr(),
size as c_int,
shm.ptr()
)
}
} else {
unsafe {
ffi_dispatch!(
WAYLAND_CURSOR_HANDLE,
wl_cursor_theme_load,
ptr::null(),
size as c_int,
shm.ptr()
)
}
};
assert!(
!ptr.is_null(),
"Memory allocation failure while loading a theme."
);
CursorTheme { theme: ptr }
}
impl CursorTheme {
pub fn get_cursor(&self, name: &str) -> Option<Cursor> {
let cstr = CString::new(name).expect("Cursor name contained an interior null.");
let ptr = unsafe {
ffi_dispatch!(
WAYLAND_CURSOR_HANDLE,
wl_cursor_theme_get_cursor,
self.theme,
cstr.as_ptr()
)
};
if ptr.is_null() {
None
} else {
Some(Cursor {
_theme: PhantomData,
cursor: ptr,
})
}
}
}
impl Drop for CursorTheme {
fn drop(&mut self) {
unsafe {
ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_theme_destroy, self.theme);
}
}
}
pub struct Cursor<'a> {
_theme: PhantomData<&'a CursorTheme>,
cursor: *mut wl_cursor,
}
unsafe impl<'a> Send for Cursor<'a> {}
impl<'a> Cursor<'a> {
pub fn name(&self) -> String {
let name = unsafe { CStr::from_ptr((*self.cursor).name) };
name.to_string_lossy().into_owned()
}
pub fn image_count(&self) -> usize {
let count = unsafe { (*self.cursor).image_count };
count as usize
}
pub fn frame(&self, duration: u32) -> usize {
let frame = unsafe {
ffi_dispatch!(
WAYLAND_CURSOR_HANDLE,
wl_cursor_frame,
self.cursor,
duration
)
};
frame as usize
}
pub fn frame_and_duration(&self, duration: u32) -> (usize, u32) {
let mut out_duration = 0u32;
let frame = unsafe {
ffi_dispatch!(
WAYLAND_CURSOR_HANDLE,
wl_cursor_frame_and_duration,
self.cursor,
duration,
&mut out_duration as *mut u32
)
} as usize;
(frame, out_duration)
}
pub fn frame_buffer(&self, frame: usize) -> Option<CursorImageBuffer> {
if frame >= self.image_count() {
None
} else {
unsafe {
let image = *(*self.cursor).images.offset(frame as isize);
let ptr = ffi_dispatch!(WAYLAND_CURSOR_HANDLE, wl_cursor_image_get_buffer, image);
let data = {
use wayland_sys::client::*;
ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, ptr)
};
let buffer = if data.is_null() {
Proxy::from_ptr_new(ptr)
} else {
Proxy::from_ptr_initialized(ptr)
};
Some(CursorImageBuffer {
_cursor: PhantomData,
buffer: buffer,
})
}
}
}
pub fn frame_info(&self, frame: usize) -> Option<(u32, u32, u32, u32, u32)> {
if frame >= self.image_count() {
None
} else {
let image = unsafe { &**(*self.cursor).images.offset(frame as isize) };
Some((
image.width,
image.height,
image.hotspot_x,
image.hotspot_y,
image.delay,
))
}
}
}
pub struct CursorImageBuffer<'a> {
_cursor: PhantomData<&'a Cursor<'a>>,
buffer: WlBuffer,
}
unsafe impl<'a> Send for CursorImageBuffer<'a> {}
impl<'a> Deref for CursorImageBuffer<'a> {
type Target = WlBuffer;
fn deref(&self) -> &WlBuffer {
&self.buffer
}
}