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
145
use crate::Actor;
use glib::{
    object::{Cast, IsA},
    signal::{connect_raw, SignalHandlerId},
    translate::*,
};
use std::boxed::Box as Box_;
use std::{fmt, mem, mem::transmute};

glib_wrapper! {
    pub struct Content(Interface<ffi::ClutterContent>);

    match fn {
        get_type => || ffi::clutter_content_get_type(),
    }
}

/// Trait containing all `Content` methods.
///
/// # Implementors
///
/// [`Canvas`](struct.Canvas.html), [`Content`](struct.Content.html), [`Image`](struct.Image.html)
pub trait ContentExt: 'static {
    /// Retrieves the natural size of the `self`, if any.
    ///
    /// The natural size of a `Content` is defined as the size the content
    /// would have regardless of the allocation of the actor that is painting it,
    /// for instance the size of an image data.
    /// ## `width`
    /// return location for the natural width of the content
    /// ## `height`
    /// return location for the natural height of the content
    ///
    /// # Returns
    ///
    /// `true` if the content has a preferred size, and `false`
    ///  otherwise
    fn get_preferred_size(&self) -> Option<(f32, f32)>;

    /// Invalidates a `Content`.
    ///
    /// This function should be called by `Content` implementations when
    /// they change the way a the content should be painted regardless of the
    /// actor state.
    fn invalidate(&self);

    /// This signal is emitted each time a `Content` implementation is
    /// assigned to a `Actor`.
    /// ## `actor`
    /// a `Actor`
    fn connect_attached<F: Fn(&Self, &Actor) + 'static>(&self, f: F) -> SignalHandlerId;

    /// This signal is emitted each time a `Content` implementation is
    /// removed from a `Actor`.
    /// ## `actor`
    /// a `Actor`
    fn connect_detached<F: Fn(&Self, &Actor) + 'static>(&self, f: F) -> SignalHandlerId;
}

impl<O: IsA<Content>> ContentExt for O {
    fn get_preferred_size(&self) -> Option<(f32, f32)> {
        unsafe {
            let mut width = mem::MaybeUninit::uninit();
            let mut height = mem::MaybeUninit::uninit();
            let ret = from_glib(ffi::clutter_content_get_preferred_size(
                self.as_ref().to_glib_none().0,
                width.as_mut_ptr(),
                height.as_mut_ptr(),
            ));
            let width = width.assume_init();
            let height = height.assume_init();
            if ret {
                Some((width, height))
            } else {
                None
            }
        }
    }

    fn invalidate(&self) {
        unsafe {
            ffi::clutter_content_invalidate(self.as_ref().to_glib_none().0);
        }
    }

    fn connect_attached<F: Fn(&Self, &Actor) + 'static>(&self, f: F) -> SignalHandlerId {
        unsafe extern "C" fn attached_trampoline<P, F: Fn(&P, &Actor) + 'static>(
            this: *mut ffi::ClutterContent,
            actor: *mut ffi::ClutterActor,
            f: glib_sys::gpointer,
        ) where
            P: IsA<Content>,
        {
            let f: &F = &*(f as *const F);
            f(
                &Content::from_glib_borrow(this).unsafe_cast_ref(),
                &from_glib_borrow(actor),
            )
        }
        unsafe {
            let f: Box_<F> = Box_::new(f);
            connect_raw(
                self.as_ptr() as *mut _,
                b"attached\0".as_ptr() as *const _,
                Some(transmute::<_, unsafe extern "C" fn()>(
                    attached_trampoline::<Self, F> as *const (),
                )),
                Box_::into_raw(f),
            )
        }
    }

    fn connect_detached<F: Fn(&Self, &Actor) + 'static>(&self, f: F) -> SignalHandlerId {
        unsafe extern "C" fn detached_trampoline<P, F: Fn(&P, &Actor) + 'static>(
            this: *mut ffi::ClutterContent,
            actor: *mut ffi::ClutterActor,
            f: glib_sys::gpointer,
        ) where
            P: IsA<Content>,
        {
            let f: &F = &*(f as *const F);
            f(
                &Content::from_glib_borrow(this).unsafe_cast_ref(),
                &from_glib_borrow(actor),
            )
        }
        unsafe {
            let f: Box_<F> = Box_::new(f);
            connect_raw(
                self.as_ptr() as *mut _,
                b"detached\0".as_ptr() as *const _,
                Some(transmute::<_, unsafe extern "C" fn()>(
                    detached_trampoline::<Self, F> as *const (),
                )),
                Box_::into_raw(f),
            )
        }
    }
}

impl fmt::Display for Content {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Content")
    }
}