Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit a44b0b0

Browse files
committed
For setting properties and the return value of signal handlers relax the type checks
Instead of requiring that the type of the Value itself has to be compatible, we are checking for Object subclasses also if the type of the contained object is compatible and if it is make sure that everything works correctly. This can happen for example if a button is stored in a gtk::Widget typed variable and then converted to a glib::Value. The Value will have the type of Widget and not Button, and type checks would fail.
1 parent d6a3b03 commit a44b0b0

File tree

2 files changed

+39
-6
lines changed

2 files changed

+39
-6
lines changed

src/object.rs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ impl<T: ObjectType> ObjectExt for T {
947947

948948
fn set_property<'a, N: Into<&'a str>>(&self, property_name: N, value: &ToValue) -> Result<(), BoolError> {
949949
let property_name = property_name.into();
950-
let property_value = value.to_value();
950+
let mut property_value = value.to_value();
951951

952952
let pspec = match self.find_property(property_name) {
953953
Some(pspec) => pspec,
@@ -968,12 +968,28 @@ impl<T: ObjectType> ObjectExt for T {
968968
let valid_type: bool = from_glib(gobject_ffi::g_type_check_value_holds(
969969
mut_override(property_value.to_glib_none().0),
970970
pspec.get_value_type().to_glib()));
971-
if !valid_type {
971+
972+
// If it's not directly a valid type but an object type, we check if the
973+
// actual type of the contained object is compatible and if so create
974+
// a properly type Value. This can happen if the type field in the
975+
// Value is set to a more generic type than the contained value
976+
if !valid_type && property_value.type_().is_a(&Object::static_type()) {
977+
if let Some(obj) = property_value.get::<Object>() {
978+
if obj.get_type().is_a(&pspec.get_value_type()) {
979+
property_value.0.g_type = pspec.get_value_type().to_glib();
980+
} else {
981+
return Err(glib_bool_error!("property can't be set from the given object type"));
982+
}
983+
} else {
984+
// Otherwise if the value is None then the type is compatible too
985+
property_value.0.g_type = pspec.get_value_type().to_glib();
986+
}
987+
} else if !valid_type {
972988
return Err(glib_bool_error!("property can't be set from the given type"));
973989
}
974990

975991
let changed: bool = from_glib(gobject_ffi::g_param_value_validate(
976-
pspec.to_glib_none().0, mut_override(property_value.to_glib_none().0)));
992+
pspec.to_glib_none().0, property_value.to_glib_none_mut().0));
977993
let change_allowed = pspec.get_flags().contains(::ParamFlags::LAX_VALIDATION);
978994
if changed && !change_allowed {
979995
return Err(glib_bool_error!(
@@ -1139,11 +1155,28 @@ impl<T: ObjectType> ObjectExt for T {
11391155
None
11401156
} else {
11411157
match ret {
1142-
Some(ret) => {
1158+
Some(mut ret) => {
11431159
let valid_type: bool = from_glib(gobject_ffi::g_type_check_value_holds(
11441160
mut_override(ret.to_glib_none().0),
11451161
return_type.to_glib()));
1146-
if !valid_type {
1162+
1163+
// If it's not directly a valid type but an object type, we check if the
1164+
// actual typed of the contained object is compatible and if so create
1165+
// a properly typed Value. This can happen if the type field in the
1166+
// Value is set to a more generic type than the contained value
1167+
if !valid_type && ret.type_().is_a(&Object::static_type()) {
1168+
if let Some(obj) = ret.get::<Object>() {
1169+
if obj.get_type().is_a(&return_type) {
1170+
ret.0.g_type = return_type.to_glib();
1171+
} else {
1172+
panic!("Signal required return value of type {} but got {} (actual {})",
1173+
return_type.name(), ret.type_().name(), obj.get_type().name());
1174+
}
1175+
} else {
1176+
// Otherwise if the value is None then the type is compatible too
1177+
ret.0.g_type = return_type.to_glib();
1178+
}
1179+
} else if !valid_type {
11471180
panic!("Signal required return value of type {} but got {}",
11481181
return_type.name(), ret.type_().name());
11491182
}

src/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ use gobject_ffi;
103103
/// See the [module documentation](index.html) for more details.
104104
// TODO: Should use impl !Send for Value {} once stable
105105
#[repr(C)]
106-
pub struct Value(gobject_ffi::GValue, PhantomData<*const c_void>);
106+
pub struct Value(pub(crate) gobject_ffi::GValue, PhantomData<*const c_void>);
107107

108108
impl Value {
109109
/// Creates a new `Value` that is initialized with `type_`

0 commit comments

Comments
 (0)