use super::AnonymousObject;
use wayland_commons::utils::UserData;
use wayland_commons::Interface;
use wayland_sys::client::*;
use event_queue::QueueToken;
use imp::{NewProxyInner, ProxyInner};
use wayland_commons::MessageGroup;
use ProxyMap;
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> {
Proxy {
_i: ::std::marker::PhantomData,
inner: self.inner.clone(),
}
}
}
impl<I: Interface> PartialEq for Proxy<I> {
fn eq(&self, other: &Proxy<I>) -> bool {
self.equals(other)
}
}
impl<I: Interface> Eq for Proxy<I> {}
impl<I: Interface> Proxy<I> {
pub(crate) fn wrap(inner: ProxyInner) -> Proxy<I> {
Proxy {
_i: ::std::marker::PhantomData,
inner,
}
}
pub fn send(&self, msg: I::Request) {
#[cfg(feature = "native_lib")]
{
if !self.is_external() && !self.is_alive() {
return;
}
}
#[cfg(not(feature = "native_lib"))]
{
if !self.is_alive() {
return;
}
}
if msg.since() > self.version() {
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>(msg)
}
pub fn send_constructor<J, F>(
&self,
msg: I::Request,
implementor: F,
version: Option<u32>,
) -> Result<J, ()>
where
J: Interface + From<Proxy<J>>,
F: FnOnce(NewProxy<J>) -> J,
{
if !self.is_alive() {
return Err(());
}
if msg.since() > self.version() {
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_constructor::<I, J>(msg, version)
.map(NewProxy::wrap)
.map(implementor)
.map(Into::into)
}
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<UD: 'static>(&self) -> Option<&UD> {
self.inner.get_user_data()
}
pub fn equals(&self, other: &Proxy<I>) -> bool {
self.inner.equals(&other.inner)
}
pub fn child<C: Interface>(&self) -> NewProxy<C> {
NewProxy {
_i: ::std::marker::PhantomData,
inner: self.inner.child::<C>(),
}
}
pub fn anonymize(&self) -> Proxy<AnonymousObject> {
Proxy {
_i: ::std::marker::PhantomData,
inner: self.inner.clone(),
}
}
pub fn make_wrapper(&self, queue: &QueueToken) -> Result<I, ()>
where
I: From<Proxy<I>>,
{
let inner = self.inner.make_wrapper(&queue.inner)?;
Ok(Proxy {
_i: ::std::marker::PhantomData,
inner,
}
.into())
}
pub fn child_placeholder<J: Interface + From<Proxy<J>>>(&self) -> J {
Proxy::wrap(self.inner.child_placeholder()).into()
}
}
impl<I: Interface> Proxy<I> {
pub fn is_external(&self) -> bool {
#[cfg(feature = "native_lib")]
{
self.inner.is_external()
}
#[cfg(not(feature = "native_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `native_lib` cargo feature.")
}
}
pub fn c_ptr(&self) -> *mut wl_proxy {
#[cfg(feature = "native_lib")]
{
self.inner.c_ptr()
}
#[cfg(not(feature = "native_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `native_lib` cargo feature.")
}
}
pub unsafe fn from_c_ptr(_ptr: *mut wl_proxy) -> Proxy<I>
where
I: From<Proxy<I>>,
{
#[cfg(feature = "native_lib")]
{
Proxy {
_i: ::std::marker::PhantomData,
inner: ProxyInner::from_c_ptr::<I>(_ptr),
}
}
#[cfg(not(feature = "native_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `native_lib` cargo feature.")
}
}
}
#[cfg(feature = "native_lib")]
impl Proxy<::protocol::wl_display::WlDisplay> {
pub(crate) unsafe fn from_c_display_wrapper(
ptr: *mut wl_proxy,
) -> Proxy<::protocol::wl_display::WlDisplay> {
Proxy {
_i: ::std::marker::PhantomData,
inner: ProxyInner::from_c_display_wrapper(ptr),
}
}
}
pub struct NewProxy<I: Interface> {
_i: ::std::marker::PhantomData<*const I>,
pub(crate) inner: NewProxyInner,
}
impl<I: Interface + 'static> NewProxy<I> {
#[allow(dead_code)]
pub(crate) fn wrap(inner: NewProxyInner) -> NewProxy<I> {
NewProxy {
_i: ::std::marker::PhantomData,
inner,
}
}
pub fn implement<T, UD>(self, mut handler: T, user_data: UD) -> I
where
T: 'static,
UD: 'static,
I: HandledBy<T> + From<Proxy<I>>,
I::Event: MessageGroup<Map = ProxyMap>,
{
let implementation = move |event, proxy: I| I::handle(&mut handler, event, proxy);
self.implement_closure(implementation, user_data)
}
pub fn implement_closure<F, UD>(self, implementation: F, user_data: UD) -> I
where
F: FnMut(I::Event, I) + 'static,
UD: 'static,
I: From<Proxy<I>>,
I::Event: MessageGroup<Map = ProxyMap>,
{
if !self.inner.is_queue_on_current_thread() {
panic!("Trying to implement a proxy with a non-Send implementation from an other thread than the one of its event queue.");
}
let inner = unsafe {
self.inner
.implement::<I, _>(implementation, UserData::new(user_data))
};
Proxy {
_i: ::std::marker::PhantomData,
inner,
}
.into()
}
pub fn implement_dummy(self) -> I
where
I: From<Proxy<I>>,
I::Event: MessageGroup<Map = ProxyMap>,
{
self.implement_closure(|_, _| (), ())
}
pub fn implement_threadsafe<T, UD>(self, mut handler: T, user_data: UD) -> I
where
T: Send + 'static,
UD: Send + Sync + 'static,
I: HandledBy<T> + From<Proxy<I>>,
I::Event: MessageGroup<Map = ProxyMap>,
{
let implementation = move |event, proxy: I| I::handle(&mut handler, event, proxy);
self.implement_closure_threadsafe(implementation, user_data)
}
pub fn implement_closure_threadsafe<F, UD>(self, implementation: F, user_data: UD) -> I
where
F: FnMut(I::Event, I) + Send + 'static,
UD: Send + Sync + 'static,
I: From<Proxy<I>>,
I::Event: MessageGroup<Map = ProxyMap>,
{
let inner = unsafe {
self.inner
.implement::<I, _>(implementation, UserData::new_threadsafe(user_data))
};
Proxy {
_i: ::std::marker::PhantomData,
inner,
}
.into()
}
}
impl<I: Interface + 'static> NewProxy<I> {
pub fn c_ptr(&self) -> *mut wl_proxy {
#[cfg(feature = "native_lib")]
{
self.inner.c_ptr()
}
#[cfg(not(feature = "native_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `native_lib` cargo feature.")
}
}
pub unsafe fn from_c_ptr(_ptr: *mut wl_proxy) -> Self {
#[cfg(feature = "native_lib")]
{
NewProxy {
_i: ::std::marker::PhantomData,
inner: NewProxyInner::from_c_ptr(_ptr),
}
}
#[cfg(not(feature = "native_lib"))]
{
panic!("[wayland-client] C interfacing methods can only be used with the `native_lib` cargo feature.")
}
}
}
pub trait HandledBy<T>: Interface + Sized {
fn handle(handler: &mut T, event: Self::Event, proxy: Self);
}