wayland-client 0.20.2

Bindings to the standard C implementation of the wayland protocol, client side.
Documentation
use wayland_commons::{Implementation, Interface, MessageGroup};

#[cfg(feature = "native_lib")]
use wayland_sys::client::*;

use event_queue::QueueToken;

use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

pub(crate) struct ProxyInternal {
    alive: AtomicBool,
    user_data: AtomicPtr<()>,
}

impl ProxyInternal {
    fn new() -> ProxyInternal {
        ProxyInternal {
            alive: AtomicBool::new(true),
            user_data: AtomicPtr::new(::std::ptr::null_mut()),
        }
    }
}

/// An handle to a wayland proxy
///
/// This represents a wayland object instanciated in your client
/// session. Several handles to the same object can exist at a given
/// time, and cloning them won't create a new protocol object, only
/// clone the handle. The lifetime of the protocol object is **not**
/// tied to the lifetime of these handles, but rather to sending or
/// receiving destroying messages.
///
/// These handles are notably used to send requests to the server. To do
/// you need to import the associated `RequestsTrait` trait from the module
/// of this interface.
pub struct Proxy<I: Interface> {
    _i: ::std::marker::PhantomData<*const I>,
    #[cfg(not(feature = "native_lib"))]
    internal: Arc<ProxyInternal>,
    #[cfg(feature = "native_lib")]
    internal: Option<Arc<ProxyInternal>>,
    #[cfg(feature = "native_lib")]
    ptr: *mut wl_proxy,
    #[cfg(feature = "native_lib")]
    is_wrapper: bool,
}

unsafe impl<I: Interface> Send for Proxy<I> {}
unsafe impl<I: Interface> Sync for Proxy<I> {}

impl<I: Interface> Proxy<I> {
    /// Send a request through this object
    ///
    /// This is the generic method to send requests.
    ///
    /// Several requests require the creation of new objects using
    /// the `child()` method, which if done wrong can cause protocol
    /// errors (in which case the server will terminate your connexion).
    /// Thus unless your know exactly what you are doing, you should use
    /// the helper methods provided by the various `RequestsTrait` for
    /// each interface, which handle this correctly for you.
    pub fn send(&self, msg: I::Request) {
        #[cfg(not(feature = "native_lib"))]
        {
            if !self.internal.alive.load(Ordering::Acquire) {
                // don't send message to dead objects !
                return;
            }
            unimplemented!()
        }
        #[cfg(feature = "native_lib")]
        {
            if let Some(ref internal) = self.internal {
                // object is managed
                if !internal.alive.load(Ordering::Acquire) {
                    // don't send message to dead objects !
                    return;
                }
            }
            msg.as_raw_c_in(|opcode, args| unsafe {
                ffi_dispatch!(
                    WAYLAND_CLIENT_HANDLE,
                    wl_proxy_marshal_array,
                    self.ptr,
                    opcode,
                    args.as_ptr() as *mut _
                );
            });
        }
    }

    /// Check if the object associated with this proxy is still alive
    ///
    /// Will return `false` if either:
    ///
    /// - The object has been destroyed
    /// - The object is not managed by this library (see the `from_c_ptr` method)
    pub fn is_alive(&self) -> bool {
        #[cfg(not(feature = "native_lib"))]
        {
            self.internal.alive.load(Ordering::Acquire)
        }
        #[cfg(feature = "native_lib")]
        {
            self.internal
                .as_ref()
                .map(|i| i.alive.load(Ordering::Acquire))
                .unwrap_or(false)
        }
    }

    /// Retrieve the interface version of this wayland object instance
    ///
    /// Returns 0 on dead objects
    pub fn version(&self) -> u32 {
        if !self.is_alive() {
            return 0;
        }

        #[cfg(not(feature = "native_lib"))]
        {
            unimplemented!();
        }
        #[cfg(feature = "native_lib")]
        {
            unsafe { ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_version, self.ptr) as u32 }
        }
    }

    /// Associate an arbitrary payload to this object
    ///
    /// The pointer you associate here can be retrieved from any
    /// other proxy to the same wayland object.
    ///
    /// Setting or getting user data is done as an atomic operation.
    /// You are responsible for the correct initialization of this
    /// pointer, synchronisation of access, and destruction of the
    /// contents at the appropriate time.
    pub fn set_user_data(&self, ptr: *mut ()) {
        #[cfg(not(feature = "native_lib"))]
        {
            self.internal.user_data.store(ptr, Ordering::Release);
        }
        #[cfg(feature = "native_lib")]
        {
            if let Some(ref inner) = self.internal {
                inner.user_data.store(ptr, Ordering::Release);
            }
        }
    }

    /// Retrieve the arbitrary payload associated to this object
    ///
    /// See `set_user_data` for explanations.
    pub fn get_user_data(&self) -> *mut () {
        #[cfg(not(feature = "native_lib"))]
        {
            self.internal.user_data.load(Ordering::Acquire)
        }
        #[cfg(feature = "native_lib")]
        {
            if let Some(ref inner) = self.internal {
                inner.user_data.load(Ordering::Acquire)
            } else {
                ::std::ptr::null_mut()
            }
        }
    }

    #[cfg(feature = "native_lib")]
    /// Check whether this proxy is managed by the library or not
    ///
    /// See `from_c_ptr` for details.
    pub fn is_external(&self) -> bool {
        self.internal.is_none()
    }

    /// Clone this proxy
    ///
    /// It only creates a new handle to the same wayland
    /// object, and does not create a new one.
    pub fn clone(&self) -> Proxy<I> {
        Proxy {
            _i: ::std::marker::PhantomData,
            internal: self.internal.clone(),
            #[cfg(feature = "native_lib")]
            ptr: self.ptr,
            #[cfg(feature = "native_lib")]
            is_wrapper: self.is_wrapper,
        }
    }

    /// Check if the other proxy refers to the same underlying wayland object
    pub fn equals(&self, other: &Proxy<I>) -> bool {
        #[cfg(not(feature = "native_lib"))]
        {
            unimplemented!()
        }
        #[cfg(feature = "native_lib")]
        {
            match (&self.internal, &other.internal) {
                (&Some(ref my_inner), &Some(ref other_inner)) => Arc::ptr_eq(my_inner, other_inner),
                (&None, &None) => self.ptr == other.ptr,
                _ => false,
            }
        }
    }

    #[cfg(feature = "native_lib")]
    /// Get a raw pointer to the underlying wayland object
    ///
    /// Retrieve a pointer to the object from the `libwayland-client.so` library.
    /// You will mostly need it to interface with C libraries needing access
    /// to wayland objects (to initialize an opengl context for example).
    pub fn c_ptr(&self) -> *mut wl_proxy {
        self.ptr
    }

    #[cfg(feature = "native_lib")]
    /// Create a `Proxy` instance from a C pointer
    ///
    /// Create a `Proxy` from a raw pointer to a wayland object from the
    /// C library.
    ///
    /// If the pointer was previously obtained by the `c_ptr()` method, this
    /// constructs a new proxy for the same object just like the `clone()`
    /// method would have.
    ///
    /// If the object was created by some other C library you are interfacing
    /// with, it will be created in an "unmanaged" state: wayland-client will
    /// treat it as foreign, and as such most of the safeties will be absent.
    /// Notably the lifetime of the object can't be tracked, so the `alive()`
    /// method will always return `false` and you are responsible of not using
    /// an object past its destruction (as this would cause a protocol error).
    /// You will also be unable to associate any user data pointer to this object.
    ///
    /// In order to handle protocol races, invoking it with a NULL pointer will
    /// create an already-dead object.
    pub unsafe fn from_c_ptr(ptr: *mut wl_proxy) -> Self {
        use wayland_sys::client::*;

        if ptr.is_null() {
            return Proxy {
                _i: ::std::marker::PhantomData,
                internal: Some(Arc::new(ProxyInternal {
                    alive: AtomicBool::new(false),
                    user_data: AtomicPtr::new(::std::ptr::null_mut()),
                })),
                ptr: ptr,
                is_wrapper: false,
            };
        }

        let is_managed = {
            ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_listener, ptr)
                == &::wayland_sys::RUST_MANAGED as *const u8 as *const _
        };
        let internal = if is_managed {
            let user_data = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, ptr)
                as *mut self::native_machinery::ProxyUserData<I>;
            Some((*user_data).internal.clone())
        } else {
            None
        };
        Proxy {
            _i: ::std::marker::PhantomData,
            internal: internal,
            ptr: ptr,
            is_wrapper: false,
        }
    }

    #[doc(hidden)]
    #[cfg(feature = "native_lib")]
    pub unsafe fn new_null() -> Proxy<I> {
        Proxy {
            _i: ::std::marker::PhantomData,
            internal: None,
            ptr: ::std::ptr::null_mut(),
            is_wrapper: false,
        }
    }

    #[cfg(feature = "native_lib")]
    /// Create a wrapper for this object for queue management
    ///
    /// As assigning a proxy to an event queue can be a racy operation
    /// in contextes involving multiple thread, this provides a facility
    /// to do this safely.
    ///
    /// The wrapper object created behaves like a regular `Proxy`, except that
    /// all objects created as the result of its requests will be assigned to
    /// the queue associated to the provided token, rather than the queue of
    /// their parent. This does not change the queue of the proxy itself.
    pub fn make_wrapper(&self, queue: &QueueToken) -> Result<Proxy<I>, ()> {
        if !self.is_external() && !self.is_alive() {
            return Err(());
        }

        let wrapper_ptr;
        unsafe {
            wrapper_ptr = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_create_wrapper, self.ptr);
            queue.assign_proxy(wrapper_ptr);
        }

        Ok(Proxy {
            _i: ::std::marker::PhantomData,
            internal: self.internal.clone(),
            ptr: wrapper_ptr,
            is_wrapper: true,
        })
    }

    /// Create a new child object
    ///
    /// This creates a new wayland object, considered as a
    /// child of this object. It will notably inherit its interface
    /// version.
    ///
    /// The created object should immediatly be implemented and sent
    /// in a request to the server, to keep the object list properly
    /// synchronized. Failure to do so will likely cause a protocol
    /// error.
    pub fn child<C: Interface>(&self) -> NewProxy<C> {
        #[cfg(not(feature = "native_lib"))]
        {
            unimplemented!()
        }
        #[cfg(feature = "native_lib")]
        {
            let ptr = unsafe {
                ffi_dispatch!(
                    WAYLAND_CLIENT_HANDLE,
                    wl_proxy_create,
                    self.ptr,
                    C::c_interface()
                )
            };
            NewProxy {
                _i: ::std::marker::PhantomData,
                ptr: ptr,
            }
        }
    }

    /// Check whether this proxy has been implemented with given type
    ///
    /// Always returns false if the proxy is no longer alive
    pub fn is_implemented_with<Impl>(&self) -> bool
    where
        Impl: Implementation<Proxy<I>, I::Event> + 'static,
    {
        if !self.is_alive() {
            return false;
        }
        #[cfg(not(feature = "native_lib"))]
        {
            unimplemented!();
        }
        #[cfg(feature = "native_lib")]
        {
            let user_data = unsafe {
                let ptr = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, self.ptr)
                    as *mut self::native_machinery::ProxyUserData<I>;
                &*ptr
            };
            user_data.is_impl::<Impl>()
        }
    }
}

#[cfg(feature = "native_lib")]
impl Proxy<::protocol::wl_display::WlDisplay> {
    pub(crate) fn from_display(d: *mut wl_display) -> Proxy<::protocol::wl_display::WlDisplay> {
        Proxy {
            _i: ::std::marker::PhantomData,
            internal: None,
            ptr: d as *mut wl_proxy,
            is_wrapper: false,
        }
    }
}

impl<I: Interface> Drop for Proxy<I> {
    fn drop(&mut self) {
        #[cfg(feature = "native_lib")]
        {
            if self.is_wrapper {
                unsafe {
                    ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_wrapper_destroy, self.ptr);
                }
            }
        }
    }
}

/// A newly-created proxy that needs implementation
///
/// Whenever a new wayland object is created, you will
/// receive it as a `NewProxy`. You then have to provide an
/// implementation for it, in order to process the incoming
/// events it may receive. Once this done you will be able
/// to use it as a regular `Proxy`.
///
/// Implementations are structs implementing the appropriate
/// variant of the `Implementation` trait. They can also be
/// closures.
pub struct NewProxy<I: Interface> {
    _i: ::std::marker::PhantomData<*const I>,
    #[cfg(feature = "native_lib")]
    ptr: *mut wl_proxy,
}

impl<I: Interface + 'static> NewProxy<I> {
    /// Implement this proxy using given function and implementation data.
    pub fn implement<Impl>(self, implementation: Impl) -> Proxy<I>
    where
        Impl: Implementation<Proxy<I>, I::Event> + Send + 'static,
    {
        unsafe { self.implement_inner(implementation) }
    }

    /// Implement this proxy using given function and implementation data.
    ///
    /// This method allows the implementation to not be `Send`, but requires for
    /// safety that you provide a token to the event queue this proxy will be implemented
    /// on. This method will then ensure that this proxy is registered on this event queue,
    /// so that it cannot be dispatched from an other thread.
    ///
    /// **Unsafety:**
    ///
    /// This call can be racy if the proxy is not already registered on this event queue and its
    /// old queue is being dispatched from an other thread.
    ///
    /// To ensure safety, see `Proxy::make_wrapper`.
    pub unsafe fn implement_nonsend<Impl>(self, implementation: Impl, queue: &QueueToken) -> Proxy<I>
    where
        Impl: Implementation<Proxy<I>, I::Event> + 'static,
    {
        #[cfg(not(feature = "native_lib"))]
        {}
        #[cfg(feature = "native_lib")]
        {
            queue.assign_proxy(self.c_ptr());
            self.implement_inner(implementation)
        }
    }

    unsafe fn implement_inner<Impl>(self, implementation: Impl) -> Proxy<I>
    where
        Impl: Implementation<Proxy<I>, I::Event> + 'static,
    {
        #[cfg(not(feature = "native_lib"))]
        {
            unimplemented!()
        }
        #[cfg(feature = "native_lib")]
        {
            use wayland_sys::client::*;

            let new_user_data = Box::new(self::native_machinery::ProxyUserData::new(implementation));
            let internal = new_user_data.internal.clone();

            ffi_dispatch!(
                WAYLAND_CLIENT_HANDLE,
                wl_proxy_add_dispatcher,
                self.ptr,
                self::native_machinery::proxy_dispatcher::<I>,
                &::wayland_sys::RUST_MANAGED as *const _ as *const _,
                Box::into_raw(new_user_data) as *mut _
            );

            Proxy {
                _i: ::std::marker::PhantomData,
                internal: Some(internal),
                ptr: self.ptr,
                is_wrapper: false,
            }
        }
    }

    #[cfg(feature = "native_lib")]
    /// Get a raw pointer to the underlying wayland object
    ///
    /// Retrieve a pointer to the object from the `libwayland-client.so` library.
    /// You will mostly need it to interface with C libraries needing access
    /// to wayland objects (to initialize an opengl context for example).
    ///
    /// Use this if you need to pass an unimplemented object to the C library
    /// you are interfacing with.
    pub fn c_ptr(&self) -> *mut wl_proxy {
        self.ptr
    }

    #[cfg(feature = "native_lib")]
    /// Create a `NewProxy` instance from a C pointer.
    ///
    /// By doing so, you assert that this wayland object was newly created and
    /// can be safely implemented. As implementing it will overwrite any previously
    /// associated data or implementation, this can cause weird errors akin to
    /// memory corruption if it was not the case.
    pub unsafe fn from_c_ptr(ptr: *mut wl_proxy) -> Self {
        NewProxy {
            _i: ::std::marker::PhantomData,
            ptr: ptr,
        }
    }
}

#[cfg(feature = "native_lib")]
mod native_machinery {
    use wayland_sys::common::*;
    use wayland_sys::client::*;

    use std::sync::Arc;
    use std::sync::atomic::Ordering;
    use std::os::raw::{c_int, c_void};

    use super::Proxy;

    use wayland_commons::{Implementation, Interface, MessageGroup};

    pub(crate) struct ProxyUserData<I: Interface> {
        pub(crate) internal: Arc<super::ProxyInternal>,
        implem: Option<Box<Implementation<Proxy<I>, I::Event>>>,
    }

    impl<I: Interface> ProxyUserData<I> {
        pub(crate) fn new<Impl>(implem: Impl) -> ProxyUserData<I>
        where
            Impl: Implementation<Proxy<I>, I::Event> + 'static,
        {
            ProxyUserData {
                internal: Arc::new(super::ProxyInternal::new()),
                implem: Some(Box::new(implem)),
            }
        }

        pub(crate) fn is_impl<Impl>(&self) -> bool
        where
            Impl: Implementation<Proxy<I>, I::Event> + 'static,
        {
            self.implem
                .as_ref()
                .map(|implem| implem.is::<Impl>())
                .unwrap_or(false)
        }
    }

    pub(crate) unsafe extern "C" fn proxy_dispatcher<I: Interface>(
        _implem: *const c_void,
        proxy: *mut c_void,
        opcode: u32,
        _msg: *const wl_message,
        args: *const wl_argument,
    ) -> c_int
    where
        I: Interface,
    {
        let proxy = proxy as *mut wl_proxy;

        // We don't need to worry about panic-safeness, because if there is a panic,
        // we'll abort the process, so no access to corrupted data is possible.
        let ret = ::std::panic::catch_unwind(move || {
            // parse the message:
            let msg = I::Event::from_raw_c(proxy as *mut _, opcode, args)?;
            let must_destroy = msg.is_destructor();
            // create the proxy object
            let proxy_obj = super::Proxy::<I>::from_c_ptr(proxy);
            // retrieve the impl
            let user_data = ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_get_user_data, proxy);
            {
                let user_data = &mut *(user_data as *mut ProxyUserData<I>);
                let implem = user_data.implem.as_mut().unwrap();
                if must_destroy {
                    user_data.internal.alive.store(false, Ordering::Release);
                }
                // call the impl
                implem.receive(msg, proxy_obj);
            }
            if must_destroy {
                // final cleanup
                let _ = Box::from_raw(user_data as *mut ProxyUserData<I>);
                ffi_dispatch!(WAYLAND_CLIENT_HANDLE, wl_proxy_destroy, proxy);
            }
            Ok(())
        });
        // check the return status
        match ret {
            Ok(Ok(())) => return 0,
            Ok(Err(())) => {
                eprintln!(
                    "[wayland-client error] Attempted to dispatch unknown opcode {} for {}, aborting.",
                    opcode,
                    I::NAME
                );
                ::libc::abort();
            }
            Err(_) => {
                eprintln!("[wayland-client error] A handler for {} panicked.", I::NAME);
                ::libc::abort()
            }
        }
    }
}