Repository: gtk-rs/gtk3-rs (language: rust)

Issue:
gtk: Generate Container::[get|set]_propert_child
Fixes #131.

It was mentioned in #131 that we needed to be careful how we would expose this API in rust. Is there anything special to do?


Discussion / hints:

Fix patch:
diff --git a/gtk/Gir.toml b/gtk/Gir.toml
index 9f4dd4d72dea..07bd5a4c9fc3 100644
--- a/gtk/Gir.toml
+++ b/gtk/Gir.toml
@@ -854,9 +854,10 @@ generate_builder = true
 [[object]]
 name = "Gtk.Container"
 status = "generate"
+manual_traits = ["ContainerExtManual"]
     [[object.function]]
     pattern = "child_[gs]et_property"
-    ignore = true
+    manual = true
     [[object.function]]
     name = "propagate_draw"
         [[object.function.parameter]]
diff --git a/gtk/src/container.rs b/gtk/src/container.rs
new file mode 100644
index 000000000000..5958c3c0c002
--- /dev/null
+++ b/gtk/src/container.rs
@@ -0,0 +1,110 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use crate::{Container, Widget};
+use glib::translate::*;
+use glib::{value::FromValue, IsA, ToValue};
+
+pub trait ContainerExtManual: 'static {
+    #[doc(alias = "gtk_container_child_get_property")]
+    fn child_property_value(&self, child: &impl IsA<Widget>, property_name: &str) -> glib::Value;
+
+    #[doc(alias = "gtk_container_child_get_property")]
+    fn child_property<V: for<'b> FromValue<'b> + 'static>(
+        &self,
+        child: &impl IsA<Widget>,
+        property_name: &str,
+    ) -> V;
+
+    #[doc(alias = "gtk_container_child_set_property")]
+    fn child_set_property(
+        &self,
+        child: &impl IsA<Widget>,
+        property_name: &str,
+        value: &dyn ToValue,
+    );
+}
+
+impl<O: IsA<Container>> ContainerExtManual for O {
+    fn child_property_value(&self, child: &impl IsA<Widget>, property_name: &str) -> glib::Value {
+        unsafe {
+            let container_class = glib::Class::<Container>::from_type(O::static_type()).unwrap();
+            let pspec: Option<glib::ParamSpec> =
+                from_glib_none(ffi::gtk_container_class_find_child_property(
+                    container_class.as_ref() as *const _ as *const glib::gobject_ffi::GObjectClass,
+                    property_name.to_glib_none().0,
+                ));
+            let pspec = pspec.unwrap_or_else(|| {
+                panic!("The Container property '{}' doesn't exists", property_name)
+            });
+
+            if !pspec.flags().contains(glib::ParamFlags::READABLE)
+                || !pspec.flags().contains(glib::ParamFlags::READWRITE)
+            {
+                panic!("The Container property '{}' is not readable", property_name);
+            }
+
+            let mut value = glib::Value::from_type(pspec.value_type());
+            ffi::gtk_container_child_get_property(
+                self.as_ref().to_glib_none().0,
+                child.as_ref().to_glib_none().0,
+                property_name.to_glib_none().0,
+                value.to_glib_none_mut().0,
+            );
+            value
+        }
+    }
+
+    fn child_property<V: for<'b> FromValue<'b> + 'static>(
+        &self,
+        child: &impl IsA<Widget>,
+        property_name: &str,
+    ) -> V {
+        let value = self.child_property_value(child, property_name);
+        value
+            .get_owned::<V>()
+            .expect("Failed to get value of container")
+    }
+
+    fn child_set_property(
+        &self,
+        child: &impl IsA<Widget>,
+        property_name: &str,
+        value: &dyn ToValue,
+    ) {
+        unsafe {
+            let container_class = glib::Class::<Container>::from_type(O::static_type()).unwrap();
+            let pspec: Option<glib::ParamSpec> =
+                from_glib_none(ffi::gtk_container_class_find_child_property(
+                    container_class.as_ref() as *const _ as *const glib::gobject_ffi::GObjectClass,
+                    property_name.to_glib_none().0,
+                ));
+            let pspec = pspec.unwrap_or_else(|| {
+                panic!("The Container property '{}' doesn't exists", property_name)
+            });
+
+            if !pspec.flags().contains(glib::ParamFlags::WRITABLE)
+                || !pspec.flags().contains(glib::ParamFlags::READWRITE)
+            {
+                panic!(
+                    "The Container property '{}' is not writeable",
+                    property_name
+                );
+            }
+
+            assert!(
+                pspec.value_type().is_a(value.value_type()),
+                "The Container property '{}' is value is of wrong type. Expected '{}' but got '{}'",
+                property_name,
+                pspec.value_type(),
+                value.value_type()
+            );
+
+            ffi::gtk_container_child_set_property(
+                self.as_ref().to_glib_none().0,
+                child.as_ref().to_glib_none().0,
+                property_name.to_glib_none().0,
+                value.to_value().to_glib_none().0,
+            );
+        }
+    }
+}
diff --git a/gtk/src/lib.rs b/gtk/src/lib.rs
index b0786650ceae..e134f53d16fe 100644
--- a/gtk/src/lib.rs
+++ b/gtk/src/lib.rs
@@ -72,6 +72,7 @@ mod clipboard;
 mod color_button;
 mod color_chooser;
 mod combo_box;
+mod container;
 mod dialog;
 mod drag_context;
 mod entry;
diff --git a/gtk/src/prelude.rs b/gtk/src/prelude.rs
index 736d638ac7b5..5d3bb6701fb6 100644
--- a/gtk/src/prelude.rs
+++ b/gtk/src/prelude.rs
@@ -25,6 +25,7 @@ pub use crate::cell_renderer_pixbuf::CellRendererPixbufExtManual;
 pub use crate::color_button::ColorButtonExtManual;
 pub use crate::color_chooser::ColorChooserExtManual;
 pub use crate::combo_box::ComboBoxExtManual;
+pub use crate::container::ContainerExtManual;
 pub use crate::dialog::DialogExtManual;
 pub use crate::drag_context::DragContextExtManual;
 pub use crate::entry::EntryExtManual;
diff --git a/gtk/sys/src/manual.rs b/gtk/sys/src/manual.rs
index cc39b0570cf0..f6644ffa87ef 100644
--- a/gtk/sys/src/manual.rs
+++ b/gtk/sys/src/manual.rs
@@ -3,3 +3,14 @@
 pub mod xlib {
     pub type Window = i32;
 }
+
+//=========================================================================
+// GtkContainerClass
+//=========================================================================
+
+extern "C" {
+    pub fn gtk_container_class_find_child_property(
+        cclass: *const gobject::GObjectClass,
+        property_name: *const libc::c_char,
+    ) -> *mut gobject::GParamSpec;
+}


Test patch: