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
use std::os::raw::c_void;

use wayland_commons::{Implementation, Interface};

use NewResource;

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

/// A handle to a global object
///
/// This is given to you when you register a global to the event loop.
///
/// This handle allows you do destroy the global when needed.
///
/// If you know you will never destroy this global, you can let this
/// handle go out of scope.
pub struct Global<I: Interface> {
    _i: ::std::marker::PhantomData<*const I>,
    #[cfg(feature = "native_lib")]
    ptr: *mut wl_global,
    #[cfg(feature = "native_lib")]
    data: *mut Box<Implementation<NewResource<I>, u32>>,
}

impl<I: Interface> Global<I> {
    #[cfg(feature = "native_lib")]
    pub(crate) unsafe fn create(
        ptr: *mut wl_global,
        data: Box<Box<Implementation<NewResource<I>, u32>>>,
    ) -> Global<I> {
        Global {
            _i: ::std::marker::PhantomData,
            ptr: ptr,
            data: Box::into_raw(data),
        }
    }

    /// Destroy the associated global object.
    pub fn destroy(self) {
        #[cfg(not(feature = "native_lib"))]
        {}
        #[cfg(feature = "native_lib")]
        unsafe {
            // destroy the global
            ffi_dispatch!(WAYLAND_SERVER_HANDLE, wl_global_destroy, self.ptr);
            // free the user data
            let data = Box::from_raw(self.data);
            drop(data);
        }
    }
}

pub(crate) unsafe extern "C" fn global_bind<I: Interface>(
    client: *mut wl_client,
    data: *mut c_void,
    version: u32,
    id: u32,
) {
    // safety of this function is the same as dispatch_func
    let ret = ::std::panic::catch_unwind(move || {
        let implem = &mut *(data as *mut Box<Implementation<NewResource<I>, u32>>);
        let ptr = ffi_dispatch!(
            WAYLAND_SERVER_HANDLE,
            wl_resource_create,
            client,
            I::c_interface(),
            version as i32, // wayland already checks the validity of the version
            id
        );
        let resource = NewResource::from_c_ptr(ptr as *mut wl_resource);
        implem.receive(version, resource);
    });
    match ret {
        Ok(()) => (), // all went well
        Err(_) => {
            // a panic occured
            eprintln!(
                "[wayland-server error] A global handler for {} panicked, aborting.",
                I::NAME
            );
            ::libc::abort();
        }
    }
}