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