1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
use std::os::raw::c_void;
use std::ptr;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicPtr, Ordering};

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

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

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

/// A handle to a client connected to your server
///
/// There can be several handles referring to the same client
pub struct Client {
    internal: Arc<ClientInternal>,
    #[cfg(feature = "native_lib")]
    ptr: *mut wl_client,
}

impl Client {
    #[cfg(feature = "native_lib")]
    /// Create a client from a `wayland-server.so` pointer
    pub unsafe fn from_ptr(ptr: *mut wl_client) -> Client {
        // check if we are already registered
        let listener = ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_client_get_destroy_listener,
            ptr,
            client_destroy
        );
        if listener.is_null() {
            // need to init this client
            let listener = signal::rust_listener_create(client_destroy);
            let internal = Arc::new(ClientInternal::new());
            signal::rust_listener_set_user_data(
                listener,
                Box::into_raw(Box::new(internal.clone())) as *mut c_void,
            );
            ffi_dispatch!(
                WAYLAND_SERVER_HANDLE,
                wl_client_add_destroy_listener,
                ptr,
                listener
            );
            Client {
                internal: internal,
                ptr: ptr,
            }
        } else {
            // client already initialized
            let internal = signal::rust_listener_get_user_data(listener) as *mut Arc<ClientInternal>;
            Client {
                internal: (*internal).clone(),
                ptr: ptr,
            }
        }
    }

    #[cfg(feature = "native_lib")]
    /// Retrieve a pointer to the underlying `wl_client` of `wayland-server.so`
    pub fn c_ptr(&self) -> *mut wl_client {
        self.ptr
    }

    /// Check whether this client is still connected to the server
    pub fn alive(&self) -> bool {
        self.internal.alive.load(Ordering::Acquire)
    }

    /// Check whether this client handle refers to the same client as
    /// an other
    pub fn equals(&self, other: &Client) -> bool {
        Arc::ptr_eq(&self.internal, &other.internal)
    }

    /// Flush the pending events to this client
    pub fn flush(&self) {
        if !self.alive() {
            return;
        }
        unsafe {
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_client_flush, self.ptr);
        }
    }

    /// Associate an arbitrary payload to this client
    ///
    /// The pointer you associate here can be retrieved from any
    /// other handle to the same client.
    ///
    /// 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, data: *mut ()) {
        self.internal.user_data.store(data, Ordering::Release);
    }

    /// Retrieve the arbitrary payload associated to this client
    ///
    /// See `set_user_data` for explanations.
    pub fn get_user_data(&self) -> *mut () {
        self.internal.user_data.load(Ordering::Acquire)
    }

    /// Set a destructor for this client
    ///
    /// the provided function will be called when the client disconnects
    /// or is killed. It's argument is what you would get from calling
    /// `get_user_data`.
    pub fn set_destructor(&self, destructor: fn(*mut ())) {
        self.internal
            .destructor
            .store(destructor as *const () as *mut (), Ordering::Release);
    }
}

unsafe extern "C" fn client_destroy(listener: *mut wl_listener, _data: *mut c_void) {
    let internal = Box::from_raw(signal::rust_listener_get_user_data(listener) as *mut Arc<ClientInternal>);
    signal::rust_listener_set_user_data(listener, ptr::null_mut());
    // Store that we are dead
    internal.alive.store(false, Ordering::Release);
    // TODO: call the user callback
    let destructor = internal.destructor.load(Ordering::Acquire);
    if !destructor.is_null() {
        let destructor_func: fn(*mut ()) = ::std::mem::transmute(destructor);
        destructor_func(internal.user_data.load(Ordering::Acquire));
    }
    signal::rust_listener_destroy(listener);
}