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: ObjectImpl {
16 fn delay_time(&self) -> Option<Duration> {
19 self.parent_delay_time()
20 }
21
22 fn pixbuf(&self) -> Pixbuf {
23 self.parent_pixbuf()
24 }
25
26 fn on_currently_loading_frame(&self) -> bool {
27 self.parent_on_currently_loading_frame()
28 }
29
30 fn advance(&self, current_time: SystemTime) -> bool {
31 self.parent_advance(current_time)
32 }
33}
34
35mod sealed {
36 pub trait Sealed {}
37 impl<T: super::PixbufAnimationIterImplExt> Sealed for T {}
38}
39
40pub trait PixbufAnimationIterImplExt: sealed::Sealed + ObjectSubclass {
41 fn parent_delay_time(&self) -> Option<Duration> {
42 unsafe {
43 let data = Self::type_data();
44 let parent_class =
45 data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
46 let f = (*parent_class)
47 .get_delay_time
48 .expect("No parent class implementation for \"get_delay_time\"");
49
50 let time = f(self
51 .obj()
52 .unsafe_cast_ref::<PixbufAnimationIter>()
53 .to_glib_none()
54 .0);
55 if time < 0 {
56 None
57 } else {
58 Some(Duration::from_millis(time as u64))
59 }
60 }
61 }
62
63 fn parent_pixbuf(&self) -> Pixbuf {
64 unsafe {
65 let data = Self::type_data();
66 let parent_class =
67 data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
68 let f = (*parent_class)
69 .get_pixbuf
70 .expect("No parent class implementation for \"get_pixbuf\"");
71
72 from_glib_none(f(self
73 .obj()
74 .unsafe_cast_ref::<PixbufAnimationIter>()
75 .to_glib_none()
76 .0))
77 }
78 }
79
80 fn parent_on_currently_loading_frame(&self) -> bool {
81 unsafe {
82 let data = Self::type_data();
83 let parent_class =
84 data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
85 let f = (*parent_class)
86 .on_currently_loading_frame
87 .expect("No parent class implementation for \"on_currently_loading_frame\"");
88
89 from_glib(f(self
90 .obj()
91 .unsafe_cast_ref::<PixbufAnimationIter>()
92 .to_glib_none()
93 .0))
94 }
95 }
96
97 fn parent_advance(&self, current_time: SystemTime) -> bool {
98 unsafe {
99 let data = Self::type_data();
100 let parent_class =
101 data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
102 let f = (*parent_class)
103 .advance
104 .expect("No parent class implementation for \"advance\"");
105
106 let diff = current_time
107 .duration_since(SystemTime::UNIX_EPOCH)
108 .expect("failed to convert time");
109 let time = glib::ffi::GTimeVal {
110 tv_sec: diff.as_secs() as _,
111 tv_usec: diff.subsec_micros() as _,
112 };
113 from_glib(f(
114 self.obj()
115 .unsafe_cast_ref::<PixbufAnimationIter>()
116 .to_glib_none()
117 .0,
118 &time,
119 ))
120 }
121 }
122}
123
124impl<T: PixbufAnimationIterImpl> PixbufAnimationIterImplExt for T {}
125
126unsafe impl<T: PixbufAnimationIterImpl> IsSubclassable<T> for PixbufAnimationIter {
127 fn class_init(class: &mut ::glib::Class<Self>) {
128 Self::parent_class_init::<T>(class);
129
130 let klass = class.as_mut();
131 klass.get_delay_time = Some(animation_iter_get_delay_time::<T>);
132 klass.get_pixbuf = Some(animation_iter_get_pixbuf::<T>);
133 klass.on_currently_loading_frame = Some(animation_iter_on_currently_loading_frame::<T>);
134 klass.advance = Some(animation_iter_advance::<T>);
135 }
136}
137
138unsafe extern "C" fn animation_iter_get_delay_time<T: PixbufAnimationIterImpl>(
139 ptr: *mut ffi::GdkPixbufAnimationIter,
140) -> i32 {
141 let instance = &*(ptr as *mut T::Instance);
142 let imp = instance.imp();
143
144 imp.delay_time().map(|t| t.as_millis() as i32).unwrap_or(-1)
145}
146
147unsafe extern "C" fn animation_iter_get_pixbuf<T: PixbufAnimationIterImpl>(
148 ptr: *mut ffi::GdkPixbufAnimationIter,
149) -> *mut ffi::GdkPixbuf {
150 let instance = &*(ptr as *mut T::Instance);
151 let imp = instance.imp();
152
153 let pixbuf = imp.pixbuf();
154 let pixbuf_quark = {
156 static QUARK: OnceLock<glib::Quark> = OnceLock::new();
157 *QUARK.get_or_init(|| glib::Quark::from_str("gtk-rs-subclass-pixbuf"))
158 };
159 imp.obj().set_qdata(pixbuf_quark, pixbuf.clone());
160 pixbuf.to_glib_none().0
161}
162
163unsafe extern "C" fn animation_iter_on_currently_loading_frame<T: PixbufAnimationIterImpl>(
164 ptr: *mut ffi::GdkPixbufAnimationIter,
165) -> glib::ffi::gboolean {
166 let instance = &*(ptr as *mut T::Instance);
167 let imp = instance.imp();
168
169 imp.on_currently_loading_frame().into_glib()
170}
171
172unsafe extern "C" fn animation_iter_advance<T: PixbufAnimationIterImpl>(
173 ptr: *mut ffi::GdkPixbufAnimationIter,
174 current_time_ptr: *const glib::ffi::GTimeVal,
175) -> glib::ffi::gboolean {
176 let instance = &*(ptr as *mut T::Instance);
177 let imp = instance.imp();
178
179 let current_time = SystemTime::UNIX_EPOCH
180 + Duration::from_secs((*current_time_ptr).tv_sec.try_into().unwrap())
181 + Duration::from_micros((*current_time_ptr).tv_usec.try_into().unwrap());
182
183 imp.advance(current_time).into_glib()
184}