use std::fmt::{self, Debug, Formatter};
use std::ops::Deref;
use super::AnonymousObject;
use wayland_commons::user_data::UserData;
use wayland_commons::Interface;
use wayland_sys::client::*;
use crate::event_queue::QueueToken;
use crate::imp::ProxyInner;
use wayland_commons::{filter::Filter, MessageGroup};
pub struct Proxy<I: Interface> {
_i: ::std::marker::PhantomData<&'static I>,
pub(crate) inner: ProxyInner,
}
impl<I: Interface> Clone for Proxy<I> {
fn clone(&self) -> Proxy<I> {
let mut cloned = self.inner.clone();
cloned.detach();
Proxy { _i: ::std::marker::PhantomData, inner: cloned }
}
}
impl<I: Interface> PartialEq for Proxy<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn eq(&self, other: &Proxy<I>) -> bool {
self.equals(other)
}
}
impl<I: Interface> Debug for Proxy<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}@{}", I::NAME, self.inner.id())
}
}
impl<I: Interface> Eq for Proxy<I> where I: AsRef<Proxy<I>> + From<Proxy<I>> {}
impl<I: Interface> Proxy<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
#[allow(dead_code)]
pub(crate) fn wrap(inner: ProxyInner) -> Proxy<I> {
Proxy { _i: ::std::marker::PhantomData, inner }
}
pub fn send<J>(&self, msg: I::Request, version: Option<u32>) -> Option<Main<J>>
where
J: Interface + AsRef<Proxy<J>> + From<Proxy<J>>,
{
if msg.since() > self.version() && self.version() > 0 {
let opcode = msg.opcode() as usize;
panic!(
"Cannot send request {} which requires version >= {} on proxy {}@{} which is version {}.",
I::Request::MESSAGES[opcode].name,
msg.since(),
I::NAME,
self.id(),
self.version()
);
}
self.inner.send::<I, J>(msg, version).map(Main::wrap)
}
pub fn is_alive(&self) -> bool {
self.inner.is_alive()
}
pub fn version(&self) -> u32 {
self.inner.version()
}
pub fn id(&self) -> u32 {
self.inner.id()
}
pub fn user_data(&self) -> &UserData {
self.inner.user_data()
}
pub fn equals(&self, other: &Proxy<I>) -> bool {
self.inner.equals(&other.inner)
}
pub fn attach(&self, token: QueueToken) -> Attached<I> {
let mut other = self.clone();
other.inner.attach(&token.inner);
Attached { inner: other.into(), _s: std::marker::PhantomData }
}
pub fn anonymize(self) -> Proxy<AnonymousObject> {
Proxy { _i: ::std::marker::PhantomData, inner: self.inner }
}
}
impl Proxy<AnonymousObject> {
pub fn deanonymize<I: Interface>(self) -> Result<Proxy<I>, Self> {
if self.inner.is_interface::<I>() {
Ok(Proxy { inner: self.inner, _i: ::std::marker::PhantomData })
} else {
Err(self)
}
}
}
impl<I: Interface + Debug> Debug for Attached<I> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}[ATTACHED]", self.inner)
}
}
#[derive(PartialEq)]
pub struct Attached<I: Interface> {
_s: ::std::marker::PhantomData<*mut ()>,
inner: I,
}
impl<I: Interface> Attached<I>
where
I: Into<Proxy<I>> + From<Proxy<I>> + AsRef<Proxy<I>>,
{
pub fn detach(&self) -> I {
self.inner.as_ref().clone().into()
}
}
impl<I: Interface> Deref for Attached<I> {
type Target = I;
fn deref(&self) -> &I {
&self.inner
}
}
impl<I: Interface> Clone for Attached<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn clone(&self) -> Attached<I> {
let cloned = self.inner.as_ref().inner.clone();
Attached {
inner: Proxy { _i: std::marker::PhantomData, inner: cloned }.into(),
_s: std::marker::PhantomData,
}
}
}
#[derive(Clone, PartialEq)]
pub struct Main<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>> {
inner: Attached<I>,
}
impl<I: Interface> Main<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
pub(crate) fn wrap(inner: ProxyInner) -> Main<I> {
Main {
inner: Attached {
inner: Proxy { _i: std::marker::PhantomData, inner }.into(),
_s: std::marker::PhantomData,
},
}
}
pub fn assign<E>(&self, filter: Filter<E>)
where
I: Sync,
E: From<(Main<I>, I::Event)> + 'static,
I::Event: MessageGroup<Map = crate::ProxyMap>,
{
self.inner.inner.as_ref().inner.assign(filter);
}
pub fn quick_assign<F>(&self, mut f: F)
where
I: Interface + AsRef<Proxy<I>> + From<Proxy<I>> + Sync,
F: FnMut(Main<I>, I::Event, crate::DispatchData) + 'static,
I::Event: MessageGroup<Map = crate::ProxyMap>,
{
self.assign(Filter::new(move |(proxy, event), _, data| f(proxy, event, data)))
}
}
impl Main<AnonymousObject> {
pub fn deanonymize<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>>(
self,
) -> Result<Main<I>, Self> {
if self.inner.as_ref().inner.is_interface::<I>() {
Ok(Main {
inner: Attached {
inner: Proxy { _i: std::marker::PhantomData, inner: self.inner.inner.0.inner }
.into(),
_s: std::marker::PhantomData,
},
})
} else {
Err(self)
}
}
}
impl<I: Interface> Deref for Main<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
type Target = Attached<I>;
fn deref(&self) -> &Attached<I> {
&self.inner
}
}
impl<I: Interface> From<Main<I>> for Attached<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn from(main: Main<I>) -> Attached<I> {
main.inner
}
}
impl<I: Interface> Debug for Main<I>
where
I: Debug + AsRef<Proxy<I>> + From<Proxy<I>>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{:?}[MAIN]", self.inner.inner)
}
}
impl<I: Interface> Main<I>
where
I: AsRef<Proxy<I>> + From<Proxy<I>>,
{
pub unsafe fn from_c_ptr(_ptr: *mut wl_proxy) -> Main<I> {
#[cfg(feature = "use_system_lib")]
{
Main::wrap(ProxyInner::init_from_c_ptr::<I>(_ptr))
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
}
impl<I: Interface + AsRef<Proxy<I>> + From<Proxy<I>>> Proxy<I> {
pub fn is_external(&self) -> bool {
#[cfg(feature = "use_system_lib")]
{
self.inner.is_external()
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
pub fn c_ptr(&self) -> *mut wl_proxy {
#[cfg(feature = "use_system_lib")]
{
self.inner.c_ptr()
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
pub unsafe fn from_c_ptr(_ptr: *mut wl_proxy) -> Proxy<I>
where
I: From<Proxy<I>>,
{
#[cfg(feature = "use_system_lib")]
{
Proxy { _i: ::std::marker::PhantomData, inner: ProxyInner::from_c_ptr::<I>(_ptr) }
}
#[cfg(not(feature = "use_system_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `use_system_lib` cargo feature.")
}
}
}