gdk_pixbuf/subclass/
pixbuf_animation_iter.rs
1use 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}