use {
crate::{
Libwayland, Queue,
builder::prelude::UntypedOwnedProxy,
ffi::{wl_argument, wl_interface, wl_proxy},
proxy::low_level::{check_dispatching_proxy, check_new_proxy},
utils::sync_ptr::SyncPtr,
},
parking_lot::{RwLock, RwLockReadGuard},
std::{
ptr::{self, NonNull},
sync::atomic::{AtomicPtr, AtomicU32, Ordering::Relaxed},
},
};
#[cfg(test)]
mod tests;
pub struct UntypedBorrowedProxy {
pub(super) proxy: AtomicPtr<wl_proxy>,
pub(super) lock: RwLock<()>,
pub(super) libwayland: &'static Libwayland,
id: AtomicU32,
immutable: bool,
}
pub unsafe trait UntypedBorrowedProxyWrapper: Sized {}
unsafe impl UntypedBorrowedProxyWrapper for UntypedBorrowedProxy {}
const MIN_SERVER_ID: u32 = 0xff000000;
const LAST_CLIENT_ID: u32 = MIN_SERVER_ID - 1;
pub struct BorrowedProxyLock<'a> {
_lock: Option<RwLockReadGuard<'a, ()>>,
proxy: SyncPtr<wl_proxy>,
}
impl BorrowedProxyLock<'_> {
pub fn wl_proxy(&self) -> Option<NonNull<wl_proxy>> {
NonNull::new(self.proxy.0)
}
}
impl UntypedBorrowedProxy {
pub unsafe fn new_immutable(libwayland: &'static Libwayland, proxy: NonNull<wl_proxy>) -> Self {
unsafe { Self::new(libwayland, proxy, true) }
}
pub(crate) unsafe fn new_internal(
libwayland: &'static Libwayland,
proxy: NonNull<wl_proxy>,
) -> Self {
unsafe { Self::new(libwayland, proxy, false) }
}
unsafe fn new(
libwayland: &'static Libwayland,
proxy: NonNull<wl_proxy>,
immutable: bool,
) -> Self {
Self {
proxy: AtomicPtr::new(proxy.as_ptr()),
lock: RwLock::new(()),
id: AtomicU32::new(LAST_CLIENT_ID),
libwayland,
immutable,
}
}
#[inline]
pub fn lock(&self) -> BorrowedProxyLock<'_> {
let lock = match self.immutable {
true => None,
false => Some(self.lock.read_recursive()),
};
BorrowedProxyLock {
_lock: lock,
proxy: SyncPtr(self.proxy.load(Relaxed)),
}
}
#[inline]
pub fn wl_proxy(&self) -> Option<NonNull<wl_proxy>> {
NonNull::new(self.proxy.load(Relaxed))
}
#[inline]
pub fn id(&self) -> u32 {
let mut id = self.id.load(Relaxed);
if id == LAST_CLIENT_ID {
id = self.id_slow();
self.id.store(id, Relaxed);
}
id
}
#[cold]
fn id_slow(&self) -> u32 {
let lock = self.lock();
if let Some(proxy) = lock.wl_proxy() {
unsafe { self.libwayland.wl_proxy_get_id(proxy.as_ptr()) }
} else {
0
}
}
#[inline]
pub unsafe fn send_request(&self, opcode: u32, args: &mut [wl_argument]) {
let lock = self.lock();
let proxy = check_dispatching_proxy(lock.wl_proxy());
unsafe {
self.libwayland.wl_proxy_marshal_array_flags(
proxy.as_ptr(),
opcode,
ptr::null(),
0,
0,
args.as_mut_ptr(),
);
}
}
pub unsafe fn send_constructor(
&self,
queue: &Queue,
opcode: u32,
args: &mut [wl_argument],
interface: &'static wl_interface,
version: Option<u32>,
) -> UntypedOwnedProxy {
let lib = self.libwayland;
let lock = self.lock();
let mut proxy = check_dispatching_proxy(lock.wl_proxy());
let version =
version.unwrap_or_else(|| unsafe { lib.wl_proxy_get_version(proxy.as_ptr()) });
let parent_queue = unsafe { lib.wl_proxy_get_queue(proxy.as_ptr()) };
let need_wrapper = parent_queue != queue.wl_event_queue().as_ptr();
if need_wrapper {
let display = unsafe { self.libwayland.wl_proxy_get_display(proxy.as_ptr()) };
if display != queue.connection().wl_display().as_ptr() {
panic!("queue does not belong to same connection");
}
let proxy_ptr = unsafe { lib.wl_proxy_create_wrapper(proxy.as_ptr().cast()).cast() };
proxy = check_dispatching_proxy(NonNull::new(proxy_ptr));
unsafe {
lib.wl_proxy_set_queue(proxy.as_ptr(), queue.wl_event_queue().as_ptr());
}
}
let new_proxy = unsafe {
lib.wl_proxy_marshal_array_flags(
proxy.as_ptr(),
opcode,
interface,
version,
0,
args.as_mut_ptr(),
)
};
if need_wrapper {
unsafe {
lib.wl_proxy_wrapper_destroy(proxy.as_ptr().cast());
}
}
let new_proxy = check_new_proxy(new_proxy);
unsafe { UntypedOwnedProxy::from_plain_wl_proxy(queue, new_proxy, interface) }
}
pub fn version(&self) -> u32 {
let lock = self.lock();
let proxy = check_dispatching_proxy(lock.wl_proxy());
unsafe { self.libwayland.wl_proxy_get_version(proxy.as_ptr()) }
}
}
impl PartialEq for UntypedBorrowedProxy {
fn eq(&self, other: &Self) -> bool {
self.wl_proxy() == other.wl_proxy()
}
}
impl Eq for UntypedBorrowedProxy {}
impl PartialEq<UntypedOwnedProxy> for UntypedBorrowedProxy {
fn eq(&self, other: &UntypedOwnedProxy) -> bool {
self.wl_proxy() == other.wl_proxy()
}
}
impl PartialEq<UntypedBorrowedProxy> for UntypedOwnedProxy {
fn eq(&self, other: &UntypedBorrowedProxy) -> bool {
self.wl_proxy() == other.wl_proxy()
}
}