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
use super::Event;

use ffi;
use libc;

use std::mem;
use std::os::unix::io::AsRawFd;
use std::rc::{Rc, Weak};

/// Type representing a registered event source
///
/// Dropping this will deregister the event source and drop the associated io
/// struct and callback
pub struct EventSource(*mut ffi::wlc_event_source, Rc<()>);

/// Implement this to react to events
///
/// An Implementation for `FnMut` is provided, so you may use a (anonymous)
/// function instead
pub trait IoCallback<R> {
    /// called when a new event happened
    fn ready(&mut self, io: &mut R, event: Event::Flags);
}
impl<R, F> IoCallback<R> for F
    where F: FnMut(&mut R, Event::Flags)
{
    fn ready(&mut self, io: &mut R, event: Event::Flags) {
        self(io, event)
    }
}

impl Drop for EventSource {
    fn drop(&mut self) {
        unsafe {
            ffi::wlc_event_source_remove(self.0);
        }
    }
}

/// Register an IO type implementing `AsRawFd` for event loop callbacks on
/// specified events
///
/// # Safety
/// Dont call this function on another thread, then the main thread.
pub fn event_loop_add_io<R: AsRawFd, T: IoCallback<R>>(io: R, mask: Event::Flags, callback: T)
                                                       -> EventSource {
    let notification = Rc::new(());

    let event_source = unsafe {
        ffi::wlc_event_loop_add_fd(io.as_raw_fd(),
                                   mask.bits(),
                                   Some(event_loop_io_cb::<R, T>),
                                   Box::into_raw(Box::new((io, callback, Rc::downgrade(&notification)))) as
                                   *mut _)
    };

    EventSource(event_source, notification)
}

#[cfg_attr(feature = "cargo-clippy", allow(deref_addrof))]
unsafe extern "C" fn event_loop_io_cb<R, T: IoCallback<R>>(_fd: i32, mask: u32, userdata: *mut libc::c_void)
                                                           -> i32 {
    let mut boxed: Box<(R, T, Weak<()>)> = Box::from_raw(userdata as *mut _);

    let _guard = match boxed.2.upgrade() {
        Some(val) => val,
        None => return 0, //drops io and callback
    };

    {
        let (ref mut io, ref mut callback, _) = *&mut *boxed;
        callback.ready(io, Event::Flags::from_bits_truncate(mask))
    };

    mem::forget(boxed);

    0
}