Skip to content

Commit 0b7cc69

Browse files
authored
Merge pull request #934 from sdroege/pixbuf-transfer-none-subclass-returns
gdk-pixbuf: Ensure that transfer-none return values in subclassing ar…
2 parents a99f6ad + e7aa384 commit 0b7cc69

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

gdk-pixbuf/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ bitflags = "1.3"
3232
ffi = { package = "gdk-pixbuf-sys", path = "sys" }
3333
glib = { path = "../glib" }
3434
gio = { path = "../gio" }
35+
once_cell = "1"
3536

3637
[dev-dependencies]
3738
gir-format-check = "^0.1"

gdk-pixbuf/src/subclass/pixbuf_animation.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
66
use std::{mem::MaybeUninit, time::Duration};
77

8-
use glib::{subclass::prelude::*, translate::*, Cast};
8+
use glib::{prelude::*, subclass::prelude::*, translate::*};
9+
use once_cell::sync::Lazy;
910

1011
use crate::{Pixbuf, PixbufAnimation, PixbufAnimationIter};
1112

@@ -153,13 +154,32 @@ unsafe extern "C" fn animation_get_size<T: PixbufAnimationImpl>(
153154
}
154155
}
155156

157+
static STATIC_IMAGE_QUARK: Lazy<glib::Quark> =
158+
Lazy::new(|| glib::Quark::from_str("gtk-rs-subclass-static-image"));
159+
156160
unsafe extern "C" fn animation_get_static_image<T: PixbufAnimationImpl>(
157161
ptr: *mut ffi::GdkPixbufAnimation,
158162
) -> *mut ffi::GdkPixbuf {
159163
let instance = &*(ptr as *mut T::Instance);
160164
let imp = instance.imp();
161165

162-
imp.static_image().to_glib_none().0
166+
let instance = imp.obj();
167+
let static_image = imp.static_image();
168+
// Ensure that a) the static image stays alive as long as the animation instance and b) that
169+
// the same static image is returned every time. This is a requirement by the gdk-pixbuf API.
170+
if let Some(old_image) = instance.qdata::<Option<Pixbuf>>(*STATIC_IMAGE_QUARK) {
171+
let old_image = old_image.as_ref();
172+
173+
if let Some(old_image) = old_image {
174+
assert_eq!(
175+
Some(old_image),
176+
static_image.as_ref(),
177+
"Did not return same static image again"
178+
);
179+
}
180+
}
181+
instance.set_qdata(*STATIC_IMAGE_QUARK, static_image.clone());
182+
static_image.to_glib_none().0
163183
}
164184

165185
unsafe extern "C" fn animation_get_iter<T: PixbufAnimationImpl>(

gdk-pixbuf/src/subclass/pixbuf_animation_iter.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
66
use std::time::Duration;
77

8-
use glib::{subclass::prelude::*, translate::*, Cast};
8+
use glib::{prelude::*, subclass::prelude::*, translate::*};
9+
use once_cell::sync::Lazy;
910

1011
use crate::{Pixbuf, PixbufAnimationIter};
1112

@@ -138,13 +139,19 @@ unsafe extern "C" fn animation_iter_get_delay_time<T: PixbufAnimationIterImpl>(
138139
imp.delay_time().map(|t| t.as_millis() as i32).unwrap_or(-1)
139140
}
140141

142+
static PIXBUF_QUARK: Lazy<glib::Quark> =
143+
Lazy::new(|| glib::Quark::from_str("gtk-rs-subclass-pixbuf"));
144+
141145
unsafe extern "C" fn animation_iter_get_pixbuf<T: PixbufAnimationIterImpl>(
142146
ptr: *mut ffi::GdkPixbufAnimationIter,
143147
) -> *mut ffi::GdkPixbuf {
144148
let instance = &*(ptr as *mut T::Instance);
145149
let imp = instance.imp();
146150

147-
imp.pixbuf().to_glib_none().0
151+
let pixbuf = imp.pixbuf();
152+
// Ensure that the pixbuf stays alive until the next call
153+
imp.obj().set_qdata(*PIXBUF_QUARK, pixbuf.clone());
154+
pixbuf.to_glib_none().0
148155
}
149156

150157
unsafe extern "C" fn animation_iter_on_currently_loading_frame<T: PixbufAnimationIterImpl>(

0 commit comments

Comments
 (0)