use libc::{self, c_double};
use std::{panic, ptr::NonNull, cell::Cell, rc::{Rc, Weak}, time::Duration};
use wayland_sys::server::WAYLAND_SERVER_HANDLE;
use wayland_sys::server::signal::wl_signal_add;
use wlroots_sys::{timespec, wlr_subsurface, wlr_surface, wlr_surface_get_root_surface,
wlr_surface_has_buffer, wlr_surface_point_accepts_input, wlr_surface_send_enter,
wlr_surface_send_frame_done, wlr_surface_send_leave, wlr_surface_surface_at,
wlr_surface_is_xdg_surface, wlr_surface_get_texture};
use {compositor,
surface::{self,
subsurface::{self, Subsurface, InternalSubsurface},
subsurface_manager::SubsurfaceManager},
output::Output,
render::Texture,
utils::{self, Handleable, HandleErr, HandleResult, c_to_rust_string}};
pub type Handle = utils::Handle<Weak<Box<SubsurfaceManager>>,
wlr_surface,
Surface>;
#[allow(unused_variables)]
pub trait Handler {
fn on_commit(&mut self,
compositor_handle: compositor::Handle,
suface_handle: Handle) {}
fn new_subsurface(&mut self,
compositor_hadle: compositor::Handle,
surface_handle: Handle,
subsurface_handle: subsurface::Handle)
-> Option<Box<subsurface::Handler>> {
None
}
fn on_destroy(&mut self, compositor::Handle, Handle) {}
}
impl Handler for () {}
wayland_listener!(pub(crate) InternalSurface, (Surface, Box<Handler>), [
on_commit_listener => on_commit_notify: |this: &mut InternalSurface, _data: *mut libc::c_void,|
unsafe {
let (ref mut surface, ref mut manager) = this.data;
let compositor = match compositor::handle() {
Some(handle) => handle,
None => return
};
manager.on_commit(compositor, surface.weak_reference());
};
new_subsurface_listener => new_listener_notify: |this: &mut InternalSurface,
data: *mut libc::c_void,|
unsafe {
let (ref mut surface, ref mut manager) = this.data;
let compositor = match compositor::handle() {
Some(handle) => handle,
None => return
};
let subsurface_ptr = data as *mut wlr_subsurface;
let subsurface = Subsurface::new(subsurface_ptr);
if let Some(subsurface_handler) = manager.new_subsurface(compositor,
surface.weak_reference(),
subsurface.weak_reference()) {
let mut internal_subsurface = InternalSubsurface::new((subsurface, subsurface_handler));
wl_signal_add(&mut (*subsurface_ptr).events.destroy as *mut _ as _,
internal_subsurface.on_destroy_listener() as _);
(*subsurface_ptr).data = Box::into_raw(internal_subsurface) as *mut _;
}
};
on_destroy_listener => on_destroy_notify: |this: &mut InternalSurface, data: *mut libc::c_void,|
unsafe {
let (ref mut surface, ref mut manager) = this.data;
let compositor = match compositor::handle() {
Some(handle) => handle,
None => return
};
manager.on_destroy(compositor, surface.weak_reference());
let surface_ptr = data as *mut wlr_surface;
let surface_state_ptr = (*surface_ptr).data as *mut InternalState;
if let Some(surface_ptr) = (*surface_state_ptr).surface {
Box::<InternalSurface>::from_raw(surface_ptr.as_ptr());
}
};
]);
impl InternalSurface {
pub(crate) unsafe fn data(&mut self) -> &mut (Surface, Box<Handler>) {
&mut self.data
}
}
pub(crate) struct InternalState {
pub(crate) surface: Option<NonNull<InternalSurface>>,
handle: Weak<Cell<bool>>,
subsurfaces_manager: Weak<Box<SubsurfaceManager>>
}
#[derive(Debug)]
pub struct Surface {
liveliness: Rc<Cell<bool>>,
subsurfaces_manager: Rc<Box<SubsurfaceManager>>,
surface: NonNull<wlr_surface>
}
impl Surface {
pub(crate) unsafe fn new(surface: *mut wlr_surface) -> Self {
let surface = NonNull::new(surface)
.expect("Surface pointer was null");
if !(*surface.as_ptr()).data.is_null() {
panic!("Tried to construct a Surface from an already initialized wlr_surface");
}
let liveliness = Rc::new(Cell::new(false));
let handle = Rc::downgrade(&liveliness);
let subsurfaces_manager = Rc::new(Surface::create_manager(surface.as_ptr()));
let weak_manager = Rc::downgrade(&subsurfaces_manager);
let state = InternalState { surface: None,
handle,
subsurfaces_manager:
weak_manager };
(*surface.as_ptr()).data = Box::into_raw(Box::new(state)) as _;
Surface { liveliness,
subsurfaces_manager,
surface }
}
fn create_manager(surface: *mut wlr_surface) -> Box<SubsurfaceManager> {
unsafe {
let mut subsurfaces = vec![];
wl_list_for_each!((*surface).subsurfaces, parent_link,
(subsurface: wlr_subsurface) => {
subsurfaces.push(Subsurface::new(subsurface))
});
let mut manager = SubsurfaceManager::new(subsurfaces);
wl_signal_add(&mut (*surface).events.new_subsurface as *mut _ as _,
manager.subsurface_created_listener() as _);
manager
}
}
pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_surface {
self.surface.as_ptr()
}
pub fn current_state<'surface>(&'surface mut self) -> surface::State<'surface> {
unsafe {
let state = (*self.surface.as_ptr()).current;
surface::State::new(state)
}
}
pub fn pending_state<'surface>(&'surface mut self) -> surface::State<'surface> {
unsafe {
let state = (*self.surface.as_ptr()).current;
surface::State::new(state)
}
}
pub fn subsurfaces(&self) -> Vec<subsurface::Handle> {
self.subsurfaces_manager.subsurfaces()
}
pub fn texture<'surface>(&'surface self) -> Option<Texture<'surface>> {
unsafe {
let texture_ptr = wlr_surface_get_texture(self.surface.as_ptr());
if texture_ptr.is_null() {
None
} else {
Some(Texture::from_ptr(texture_ptr))
}
}
}
pub fn role(&self) -> Option<String> {
unsafe { c_to_rust_string((*(*self.surface.as_ptr()).role).name) }
}
pub fn has_buffer(&self) -> bool {
unsafe { wlr_surface_has_buffer(self.surface.as_ptr()) }
}
pub fn accepts_input(&self, sx: c_double, sy: c_double) -> bool {
unsafe { wlr_surface_point_accepts_input(self.surface.as_ptr(), sx, sy) }
}
pub fn is_xdg_surface(&self) -> bool {
unsafe { wlr_surface_is_xdg_surface(self.surface.as_ptr()) }
}
pub fn subsurface_at(&mut self,
sx: f64,
sy: f64,
sub_x: &mut f64,
sub_y: &mut f64)
-> Option<Handle> {
unsafe {
let surface = wlr_surface_surface_at(self.surface.as_ptr(), sx, sy, sub_x, sub_y);
if surface.is_null() {
None
} else {
Some(Handle::from_ptr(surface))
}
}
}
pub fn get_root_surface(&self) -> Option<Handle> {
unsafe {
let surface = wlr_surface_get_root_surface(self.surface.as_ptr());
if surface.is_null() {
None
} else {
Some(Handle::from_ptr(surface))
}
}
}
pub fn send_enter(&mut self, output: &mut Output) {
unsafe { wlr_surface_send_enter(self.surface.as_ptr(), output.as_ptr()) }
}
pub fn send_leave(&mut self, output: &mut Output) {
unsafe { wlr_surface_send_leave(self.surface.as_ptr(), output.as_ptr()) }
}
pub fn send_frame_done(&mut self, duration: Duration) {
unsafe {
let when = timespec { tv_sec: duration.as_secs() as libc::clock_t,
tv_nsec: duration.subsec_nanos() as libc::clock_t };
wlr_surface_send_frame_done(self.surface.as_ptr(), &when);
}
}
}
impl Handleable<Weak<Box<SubsurfaceManager>>, wlr_surface> for Surface {
#[doc(hidden)]
unsafe fn from_ptr(surface: *mut wlr_surface) -> Option<Self> {
let surface = NonNull::new(surface)?;
let data = (*surface.as_ptr()).data as *mut InternalState;
let liveliness = (*data).handle.upgrade()?;
let subsurfaces_manager = (*data).subsurfaces_manager.clone().upgrade().unwrap();
Some(Surface { surface,
liveliness,
subsurfaces_manager
})
}
#[doc(hidden)]
unsafe fn as_ptr(&self) -> *mut wlr_surface {
self.surface.as_ptr()
}
#[doc(hidden)]
unsafe fn from_handle(handle: &Handle) -> HandleResult<Self> {
let data = (*handle.ptr.as_ptr()).data as *mut InternalState;
let subsurfaces_manager = (*data).subsurfaces_manager
.clone()
.upgrade()
.expect("Could not upgrade subsurfaces list");
let liveliness = handle.handle
.upgrade()
.ok_or_else(|| HandleErr::AlreadyDropped)?;
Ok(Surface { liveliness,
subsurfaces_manager,
surface: handle.ptr })
}
fn weak_reference(&self) -> Handle {
Handle { handle: Rc::downgrade(&self.liveliness),
ptr: self.surface,
data: Some(Rc::downgrade(&self.subsurfaces_manager)),
_marker: std::marker::PhantomData }
}
}
impl Drop for Surface {
fn drop(&mut self) {
if Rc::strong_count(&self.liveliness) != 1 {
return
}
wlr_log!(WLR_DEBUG, "Dropped surface {:p}", self.surface.as_ptr());
let weak_count = Rc::weak_count(&self.liveliness);
if weak_count > 0 {
wlr_log!(WLR_DEBUG,
"Still {} weak pointers to Surface {:p}",
weak_count,
self.surface.as_ptr());
}
unsafe {
Box::from_raw((*self.surface.as_ptr()).data as *mut InternalState);
}
}
}
impl Drop for InternalSurface {
fn drop(&mut self) {
unsafe {
ffi_dispatch!(WAYLAND_SERVER_HANDLE,
wl_list_remove,
&mut (*self.on_commit_listener()).link as *mut _ as _);
ffi_dispatch!(WAYLAND_SERVER_HANDLE,
wl_list_remove,
&mut (*self.new_subsurface_listener()).link as *mut _ as _);
ffi_dispatch!(WAYLAND_SERVER_HANDLE,
wl_list_remove,
&mut (*self.on_destroy_listener()).link as *mut _ as _);
}
}
}