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