Skip to content

Commit 8426bdb

Browse files
authored
Merge pull request #835 from gtk-rs/bilelmoussaoui/gdk-pixbuf-subclassing
gdk-pixbuf: Add subclassing support
2 parents 6653861 + a2feeee commit 8426bdb

File tree

6 files changed

+512
-1
lines changed

6 files changed

+512
-1
lines changed

gdk-pixbuf/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub use glib;
1111
#[allow(unused_imports)]
1212
mod auto;
1313

14+
pub mod subclass;
15+
1416
mod pixbuf;
1517
mod pixbuf_animation;
1618
mod pixbuf_animation_iter;

gdk-pixbuf/src/pixbuf_animation_iter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::time::SystemTime;
77

88
glib::wrapper! {
99
#[doc(alias = "GdkPixbufAnimationIter")]
10-
pub struct PixbufAnimationIter(Object<ffi::GdkPixbufAnimationIter>);
10+
pub struct PixbufAnimationIter(Object<ffi::GdkPixbufAnimationIter, ffi::GdkPixbufAnimationIterClass>);
1111

1212
match fn {
1313
type_ => || ffi::gdk_pixbuf_animation_iter_get_type(),

gdk-pixbuf/src/subclass/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
// rustdoc-stripper-ignore-next
4+
//! Traits intended for creating custom types.
5+
6+
pub mod pixbuf_animation;
7+
pub mod pixbuf_animation_iter;
8+
pub mod pixbuf_loader;
9+
10+
pub mod prelude {
11+
pub use gio::subclass::prelude::*;
12+
pub use glib::subclass::prelude::*;
13+
14+
pub use super::pixbuf_animation::{PixbufAnimationImpl, PixbufAnimationImplExt};
15+
pub use super::pixbuf_animation_iter::{PixbufAnimationIterImpl, PixbufAnimationIterImplExt};
16+
pub use super::pixbuf_loader::{PixbufLoaderImpl, PixbufLoaderImplExt};
17+
}
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
// rustdoc-stripper-ignore-next
4+
//! Traits intended for subclassing [`PixbufAnimation`](crate::PixbufAnimation).
5+
6+
use std::mem::MaybeUninit;
7+
use std::time::Duration;
8+
9+
use crate::{Pixbuf, PixbufAnimation, PixbufAnimationIter};
10+
use glib::subclass::prelude::*;
11+
use glib::translate::*;
12+
use glib::Cast;
13+
14+
pub trait PixbufAnimationImpl: ObjectImpl {
15+
fn is_static_image(&self) -> bool {
16+
self.parent_is_static_image()
17+
}
18+
19+
fn static_image(&self) -> Option<Pixbuf> {
20+
self.parent_static_image()
21+
}
22+
23+
fn size(&self) -> (i32, i32) {
24+
self.parent_size()
25+
}
26+
27+
fn iter(&self, start_time: Duration) -> PixbufAnimationIter {
28+
self.parent_iter(start_time)
29+
}
30+
}
31+
32+
pub trait PixbufAnimationImplExt: ObjectSubclass {
33+
fn parent_is_static_image(&self) -> bool;
34+
fn parent_static_image(&self) -> Option<Pixbuf>;
35+
fn parent_size(&self) -> (i32, i32);
36+
fn parent_iter(&self, start_time: Duration) -> PixbufAnimationIter;
37+
}
38+
39+
impl<T: PixbufAnimationImpl> PixbufAnimationImplExt for T {
40+
fn parent_is_static_image(&self) -> bool {
41+
unsafe {
42+
let data = T::type_data();
43+
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationClass;
44+
let f = (*parent_class)
45+
.is_static_image
46+
.expect("No parent class implementation for \"is_static_image\"");
47+
48+
from_glib(f(self
49+
.obj()
50+
.unsafe_cast_ref::<PixbufAnimation>()
51+
.to_glib_none()
52+
.0))
53+
}
54+
}
55+
56+
fn parent_static_image(&self) -> Option<Pixbuf> {
57+
unsafe {
58+
let data = T::type_data();
59+
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationClass;
60+
let f = (*parent_class)
61+
.get_static_image
62+
.expect("No parent class implementation for \"get_static_image\"");
63+
64+
from_glib_none(f(self
65+
.obj()
66+
.unsafe_cast_ref::<PixbufAnimation>()
67+
.to_glib_none()
68+
.0))
69+
}
70+
}
71+
72+
fn parent_size(&self) -> (i32, i32) {
73+
unsafe {
74+
let data = T::type_data();
75+
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationClass;
76+
let f = (*parent_class)
77+
.get_size
78+
.expect("No parent class implementation for \"get_size\"");
79+
let mut width = MaybeUninit::uninit();
80+
let mut height = MaybeUninit::uninit();
81+
f(
82+
self.obj()
83+
.unsafe_cast_ref::<PixbufAnimation>()
84+
.to_glib_none()
85+
.0,
86+
width.as_mut_ptr(),
87+
height.as_mut_ptr(),
88+
);
89+
(width.assume_init(), height.assume_init())
90+
}
91+
}
92+
93+
fn parent_iter(&self, start_time: Duration) -> PixbufAnimationIter {
94+
unsafe {
95+
let data = T::type_data();
96+
let parent_class = data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationClass;
97+
let f = (*parent_class)
98+
.get_iter
99+
.expect("No parent class implementation for \"get_iter\"");
100+
101+
let time = glib::ffi::GTimeVal {
102+
tv_sec: start_time.as_secs() as _,
103+
tv_usec: start_time.subsec_micros() as _,
104+
};
105+
from_glib_full(f(
106+
self.obj()
107+
.unsafe_cast_ref::<PixbufAnimation>()
108+
.to_glib_none()
109+
.0,
110+
&time as *const _,
111+
))
112+
}
113+
}
114+
}
115+
116+
unsafe impl<T: PixbufAnimationImpl> IsSubclassable<T> for PixbufAnimation {
117+
fn class_init(class: &mut ::glib::Class<Self>) {
118+
Self::parent_class_init::<T>(class);
119+
120+
let klass = class.as_mut();
121+
klass.get_static_image = Some(animation_get_static_image::<T>);
122+
klass.get_size = Some(animation_get_size::<T>);
123+
klass.get_iter = Some(animation_get_iter::<T>);
124+
klass.is_static_image = Some(animation_is_static_image::<T>);
125+
}
126+
}
127+
128+
unsafe extern "C" fn animation_is_static_image<T: PixbufAnimationImpl>(
129+
ptr: *mut ffi::GdkPixbufAnimation,
130+
) -> glib::ffi::gboolean {
131+
let instance = &*(ptr as *mut T::Instance);
132+
let imp = instance.imp();
133+
134+
imp.is_static_image().into_glib()
135+
}
136+
137+
unsafe extern "C" fn animation_get_size<T: PixbufAnimationImpl>(
138+
ptr: *mut ffi::GdkPixbufAnimation,
139+
width_ptr: *mut libc::c_int,
140+
height_ptr: *mut libc::c_int,
141+
) {
142+
let instance = &*(ptr as *mut T::Instance);
143+
let imp = instance.imp();
144+
145+
let (width, height) = imp.size();
146+
*width_ptr = width;
147+
*height_ptr = height;
148+
}
149+
150+
unsafe extern "C" fn animation_get_static_image<T: PixbufAnimationImpl>(
151+
ptr: *mut ffi::GdkPixbufAnimation,
152+
) -> *mut ffi::GdkPixbuf {
153+
let instance = &*(ptr as *mut T::Instance);
154+
let imp = instance.imp();
155+
156+
imp.static_image().to_glib_none().0
157+
}
158+
159+
unsafe extern "C" fn animation_get_iter<T: PixbufAnimationImpl>(
160+
ptr: *mut ffi::GdkPixbufAnimation,
161+
start_time_ptr: *const glib::ffi::GTimeVal,
162+
) -> *mut ffi::GdkPixbufAnimationIter {
163+
let instance = &*(ptr as *mut T::Instance);
164+
let imp = instance.imp();
165+
166+
let total = Duration::from_secs((*start_time_ptr).tv_sec.try_into().unwrap())
167+
+ Duration::from_micros((*start_time_ptr).tv_usec.try_into().unwrap());
168+
169+
imp.iter(total).to_glib_full()
170+
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
// Take a look at the license at the top of the repository in the LICENSE file.
2+
3+
// rustdoc-stripper-ignore-next
4+
//! Traits intended for subclassing [`PixbufAnimationIter`](crate::PixbufAnimationIter).
5+
6+
use std::time::Duration;
7+
8+
use glib::subclass::prelude::*;
9+
use glib::translate::*;
10+
use glib::Cast;
11+
12+
use crate::{Pixbuf, PixbufAnimationIter};
13+
14+
pub trait PixbufAnimationIterImpl: ObjectImpl {
15+
// rustdoc-stripper-ignore-next
16+
/// Time in milliseconds, returning `None` implies showing the same pixbuf forever.
17+
fn delay_time(&self) -> Option<Duration> {
18+
self.parent_delay_time()
19+
}
20+
21+
fn pixbuf(&self) -> Pixbuf {
22+
self.parent_pixbuf()
23+
}
24+
25+
fn on_currently_loading_frame(&self) -> bool {
26+
self.parent_on_currently_loading_frame()
27+
}
28+
29+
fn advance(&self, time: Duration) -> bool {
30+
self.parent_advance(time)
31+
}
32+
}
33+
34+
pub trait PixbufAnimationIterImplExt: ObjectSubclass {
35+
fn parent_delay_time(&self) -> Option<Duration>;
36+
fn parent_pixbuf(&self) -> Pixbuf;
37+
fn parent_on_currently_loading_frame(&self) -> bool;
38+
fn parent_advance(&self, time: Duration) -> bool;
39+
}
40+
41+
impl<T: PixbufAnimationIterImpl> PixbufAnimationIterImplExt for T {
42+
fn parent_delay_time(&self) -> Option<Duration> {
43+
unsafe {
44+
let data = T::type_data();
45+
let parent_class =
46+
data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
47+
let f = (*parent_class)
48+
.get_delay_time
49+
.expect("No parent class implementation for \"get_delay_time\"");
50+
51+
let time = f(self
52+
.obj()
53+
.unsafe_cast_ref::<PixbufAnimationIter>()
54+
.to_glib_none()
55+
.0);
56+
if time == -1 {
57+
None
58+
} else {
59+
Some(Duration::from_millis(time.try_into().unwrap()))
60+
}
61+
}
62+
}
63+
64+
fn parent_pixbuf(&self) -> Pixbuf {
65+
unsafe {
66+
let data = T::type_data();
67+
let parent_class =
68+
data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
69+
let f = (*parent_class)
70+
.get_pixbuf
71+
.expect("No parent class implementation for \"get_pixbuf\"");
72+
73+
from_glib_none(f(self
74+
.obj()
75+
.unsafe_cast_ref::<PixbufAnimationIter>()
76+
.to_glib_none()
77+
.0))
78+
}
79+
}
80+
81+
fn parent_on_currently_loading_frame(&self) -> bool {
82+
unsafe {
83+
let data = T::type_data();
84+
let parent_class =
85+
data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
86+
let f = (*parent_class)
87+
.on_currently_loading_frame
88+
.expect("No parent class implementation for \"on_currently_loading_frame\"");
89+
90+
from_glib(f(self
91+
.obj()
92+
.unsafe_cast_ref::<PixbufAnimationIter>()
93+
.to_glib_none()
94+
.0))
95+
}
96+
}
97+
98+
fn parent_advance(&self, time: Duration) -> bool {
99+
unsafe {
100+
let data = T::type_data();
101+
let parent_class =
102+
data.as_ref().parent_class() as *mut ffi::GdkPixbufAnimationIterClass;
103+
let f = (*parent_class)
104+
.advance
105+
.expect("No parent class implementation for \"advance\"");
106+
107+
let time = glib::ffi::GTimeVal {
108+
tv_sec: time.as_secs() as _,
109+
tv_usec: time.subsec_micros() as _,
110+
};
111+
from_glib(f(
112+
self.obj()
113+
.unsafe_cast_ref::<PixbufAnimationIter>()
114+
.to_glib_none()
115+
.0,
116+
&time as *const _,
117+
))
118+
}
119+
}
120+
}
121+
122+
unsafe impl<T: PixbufAnimationIterImpl> IsSubclassable<T> for PixbufAnimationIter {
123+
fn class_init(class: &mut ::glib::Class<Self>) {
124+
Self::parent_class_init::<T>(class);
125+
126+
let klass = class.as_mut();
127+
klass.get_delay_time = Some(animation_iter_get_delay_time::<T>);
128+
klass.get_pixbuf = Some(animation_iter_get_pixbuf::<T>);
129+
klass.on_currently_loading_frame = Some(animation_iter_on_currently_loading_frame::<T>);
130+
klass.advance = Some(animation_iter_advance::<T>);
131+
}
132+
}
133+
134+
unsafe extern "C" fn animation_iter_get_delay_time<T: PixbufAnimationIterImpl>(
135+
ptr: *mut ffi::GdkPixbufAnimationIter,
136+
) -> i32 {
137+
let instance = &*(ptr as *mut T::Instance);
138+
let imp = instance.imp();
139+
140+
imp.delay_time().map(|t| t.as_millis() as i32).unwrap_or(-1)
141+
}
142+
143+
unsafe extern "C" fn animation_iter_get_pixbuf<T: PixbufAnimationIterImpl>(
144+
ptr: *mut ffi::GdkPixbufAnimationIter,
145+
) -> *mut ffi::GdkPixbuf {
146+
let instance = &*(ptr as *mut T::Instance);
147+
let imp = instance.imp();
148+
149+
imp.pixbuf().to_glib_none().0
150+
}
151+
152+
unsafe extern "C" fn animation_iter_on_currently_loading_frame<T: PixbufAnimationIterImpl>(
153+
ptr: *mut ffi::GdkPixbufAnimationIter,
154+
) -> glib::ffi::gboolean {
155+
let instance = &*(ptr as *mut T::Instance);
156+
let imp = instance.imp();
157+
158+
imp.on_currently_loading_frame().into_glib()
159+
}
160+
161+
unsafe extern "C" fn animation_iter_advance<T: PixbufAnimationIterImpl>(
162+
ptr: *mut ffi::GdkPixbufAnimationIter,
163+
time_ptr: *const glib::ffi::GTimeVal,
164+
) -> glib::ffi::gboolean {
165+
let instance = &*(ptr as *mut T::Instance);
166+
let imp = instance.imp();
167+
168+
let total = Duration::from_secs((*time_ptr).tv_sec.try_into().unwrap())
169+
+ Duration::from_micros((*time_ptr).tv_usec.try_into().unwrap());
170+
171+
imp.advance(total).into_glib()
172+
}

0 commit comments

Comments
 (0)