gdk_pixbuf/subclass/
pixbuf_animation_iter.rs1use std::{
7    sync::OnceLock,
8    time::{Duration, SystemTime},
9};
10
11use glib::{prelude::*, subclass::prelude::*, translate::*};
12
13use crate::{ffi, Pixbuf, PixbufAnimationIter};
14
15pub trait PixbufAnimationIterImpl:
16    ObjectImpl + ObjectSubclass<Type: IsA<PixbufAnimationIter>>
17{
18    fn delay_time(&self) -> Option<Duration> {
35        self.parent_delay_time()
36    }
37
38    fn pixbuf(&self) -> Pixbuf {
58        self.parent_pixbuf()
59    }
60
61    fn on_currently_loading_frame(&self) -> bool {
72        self.parent_on_currently_loading_frame()
73    }
74
75    fn advance(&self, current_time: SystemTime) -> bool {
103        self.parent_advance(current_time)
104    }
105}
106
107pub trait PixbufAnimationIterImplExt: PixbufAnimationIterImpl {
108    fn parent_delay_time(&self) -> Option<Duration> {
109        unsafe {
110            let data = Self::type_data();
111            let parent_class =
112                data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
113            let f = (*parent_class)
114                .get_delay_time
115                .expect("No parent class implementation for \"get_delay_time\"");
116
117            let time = f(self
118                .obj()
119                .unsafe_cast_ref::<PixbufAnimationIter>()
120                .to_glib_none()
121                .0);
122            if time < 0 {
123                None
124            } else {
125                Some(Duration::from_millis(time as u64))
126            }
127        }
128    }
129
130    fn parent_pixbuf(&self) -> Pixbuf {
131        unsafe {
132            let data = Self::type_data();
133            let parent_class =
134                data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
135            let f = (*parent_class)
136                .get_pixbuf
137                .expect("No parent class implementation for \"get_pixbuf\"");
138
139            from_glib_none(f(self
140                .obj()
141                .unsafe_cast_ref::<PixbufAnimationIter>()
142                .to_glib_none()
143                .0))
144        }
145    }
146
147    fn parent_on_currently_loading_frame(&self) -> bool {
148        unsafe {
149            let data = Self::type_data();
150            let parent_class =
151                data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
152            let f = (*parent_class)
153                .on_currently_loading_frame
154                .expect("No parent class implementation for \"on_currently_loading_frame\"");
155
156            from_glib(f(self
157                .obj()
158                .unsafe_cast_ref::<PixbufAnimationIter>()
159                .to_glib_none()
160                .0))
161        }
162    }
163
164    fn parent_advance(&self, current_time: SystemTime) -> bool {
165        unsafe {
166            let data = Self::type_data();
167            let parent_class =
168                data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
169            let f = (*parent_class)
170                .advance
171                .expect("No parent class implementation for \"advance\"");
172
173            let diff = current_time
174                .duration_since(SystemTime::UNIX_EPOCH)
175                .expect("failed to convert time");
176            let time = glib::ffi::GTimeVal {
177                tv_sec: diff.as_secs() as _,
178                tv_usec: diff.subsec_micros() as _,
179            };
180            from_glib(f(
181                self.obj()
182                    .unsafe_cast_ref::<PixbufAnimationIter>()
183                    .to_glib_none()
184                    .0,
185                &time,
186            ))
187        }
188    }
189}
190
191impl<T: PixbufAnimationIterImpl> PixbufAnimationIterImplExt for T {}
192
193unsafe impl<T: PixbufAnimationIterImpl> IsSubclassable<T> for PixbufAnimationIter {
194    fn class_init(class: &mut ::glib::Class<Self>) {
195        Self::parent_class_init::<T>(class);
196
197        let klass = class.as_mut();
198        klass.get_delay_time = Some(animation_iter_get_delay_time::<T>);
199        klass.get_pixbuf = Some(animation_iter_get_pixbuf::<T>);
200        klass.on_currently_loading_frame = Some(animation_iter_on_currently_loading_frame::<T>);
201        klass.advance = Some(animation_iter_advance::<T>);
202    }
203}
204
205unsafe extern "C" fn animation_iter_get_delay_time<T: PixbufAnimationIterImpl>(
206    ptr: *mut ffi::GdkPixbufAnimationIter,
207) -> i32 {
208    let instance = &*(ptr as *mut T::Instance);
209    let imp = instance.imp();
210
211    imp.delay_time().map(|t| t.as_millis() as i32).unwrap_or(-1)
212}
213
214unsafe extern "C" fn animation_iter_get_pixbuf<T: PixbufAnimationIterImpl>(
215    ptr: *mut ffi::GdkPixbufAnimationIter,
216) -> *mut ffi::GdkPixbuf {
217    let instance = &*(ptr as *mut T::Instance);
218    let imp = instance.imp();
219
220    let pixbuf = imp.pixbuf();
221    let pixbuf_quark = {
223        static QUARK: OnceLock<glib::Quark> = OnceLock::new();
224        *QUARK.get_or_init(|| glib::Quark::from_str("gtk-rs-subclass-pixbuf"))
225    };
226    imp.obj().set_qdata(pixbuf_quark, pixbuf.clone());
227    pixbuf.to_glib_none().0
228}
229
230unsafe extern "C" fn animation_iter_on_currently_loading_frame<T: PixbufAnimationIterImpl>(
231    ptr: *mut ffi::GdkPixbufAnimationIter,
232) -> glib::ffi::gboolean {
233    let instance = &*(ptr as *mut T::Instance);
234    let imp = instance.imp();
235
236    imp.on_currently_loading_frame().into_glib()
237}
238
239unsafe extern "C" fn animation_iter_advance<T: PixbufAnimationIterImpl>(
240    ptr: *mut ffi::GdkPixbufAnimationIter,
241    current_time_ptr: *const glib::ffi::GTimeVal,
242) -> glib::ffi::gboolean {
243    let instance = &*(ptr as *mut T::Instance);
244    let imp = instance.imp();
245
246    let current_time = SystemTime::UNIX_EPOCH
247        + Duration::from_secs((*current_time_ptr).tv_sec.try_into().unwrap())
248        + Duration::from_micros((*current_time_ptr).tv_usec.try_into().unwrap());
249
250    imp.advance(current_time).into_glib()
251}