1use std::sync::OnceLock;
6
7use glib::{translate::*, GString, Object, Quark, Value};
8
9use super::PtrHolder;
10use crate::{ffi, prelude::*, subclass::prelude::*, Buildable, Builder};
11
12pub trait BuildableImpl: ObjectImpl + ObjectSubclass<Type: IsA<Buildable>> {
13 fn set_id(&self, id: &str) {
14 self.parent_set_id(id)
15 }
16 fn id(&self) -> Option<GString> {
17 self.parent_id()
18 }
19 fn add_child(&self, builder: &Builder, child: &Object, type_: Option<&str>) {
20 self.parent_add_child(builder, child, type_)
21 }
22 fn set_buildable_property(&self, builder: &Builder, name: &str, value: &Value) {
23 self.parent_set_buildable_property(builder, name, value)
24 }
25 fn parser_finished(&self, builder: &Builder) {
26 self.parent_parser_finished(builder)
27 }
28 fn internal_child(&self, builder: &Builder, name: &str) -> Option<Object> {
29 self.parent_internal_child(builder, name)
30 }
31 fn construct_child(&self, builder: &Builder, name: &str) -> Object {
32 self.parent_construct_child(builder, name)
33 }
34 }
60
61pub trait BuildableImplExt: BuildableImpl {
62 fn parent_set_id(&self, id: &str) {
63 unsafe {
64 let type_data = Self::type_data();
65 let parent_iface =
66 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
67
68 let func = (*parent_iface)
69 .set_id
70 .expect("no parent \"set_id\" implementation");
71
72 func(
73 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
74 id.to_glib_none().0,
75 )
76 }
77 }
78
79 fn parent_id(&self) -> Option<GString> {
80 unsafe {
81 let type_data = Self::type_data();
82 let parent_iface =
83 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
84
85 let func = (*parent_iface)
86 .get_id
87 .expect("no parent \"get_id\" implementation");
88
89 from_glib_none(func(
90 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
91 ))
92 }
93 }
94
95 fn parent_add_child(&self, builder: &Builder, child: &Object, type_: Option<&str>) {
96 unsafe {
97 let type_data = Self::type_data();
98 let parent_iface =
99 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
100
101 let func = (*parent_iface)
102 .add_child
103 .expect("no parent \"add_child\" implementation");
104
105 func(
106 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
107 builder.to_glib_none().0,
108 child.to_glib_none().0,
109 type_.to_glib_none().0,
110 )
111 }
112 }
113
114 fn parent_set_buildable_property(&self, builder: &Builder, name: &str, value: &Value) {
115 unsafe {
116 let type_data = Self::type_data();
117 let parent_iface =
118 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
119
120 if let Some(func) = (*parent_iface).set_buildable_property {
123 func(
124 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
125 builder.to_glib_none().0,
126 name.to_glib_none().0,
127 value.to_glib_none().0,
128 )
129 } else {
130 self.obj().set_property_from_value(name, value);
131 }
132 }
133 }
134
135 fn parent_parser_finished(&self, builder: &Builder) {
136 unsafe {
137 let type_data = Self::type_data();
138 let parent_iface =
139 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
140
141 if let Some(func) = (*parent_iface).parser_finished {
142 func(
143 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
144 builder.to_glib_none().0,
145 )
146 }
147 }
148 }
149
150 fn parent_internal_child(&self, builder: &Builder, name: &str) -> Option<Object> {
151 unsafe {
152 let type_data = Self::type_data();
153 let parent_iface =
154 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
155
156 if let Some(func) = (*parent_iface).get_internal_child {
157 from_glib_none(func(
158 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
159 builder.to_glib_none().0,
160 name.to_glib_none().0,
161 ))
162 } else {
163 None
164 }
165 }
166 }
167
168 fn parent_construct_child(&self, builder: &Builder, name: &str) -> Object {
169 unsafe {
170 let type_data = Self::type_data();
171 let parent_iface =
172 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
173
174 let func = (*parent_iface)
175 .construct_child
176 .expect("no parent \"construct_child\" implementation");
177
178 from_glib_full(func(
179 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
180 builder.to_glib_none().0,
181 name.to_glib_none().0,
182 ))
183 }
184 }
185}
186
187impl<T: BuildableImpl> BuildableImplExt for T {}
188
189unsafe impl<T: BuildableImpl> IsImplementable<T> for Buildable {
190 fn interface_init(iface: &mut glib::Interface<Self>) {
191 let iface = iface.as_mut();
192
193 iface.set_id = Some(buildable_set_id::<T>);
194 iface.get_id = Some(buildable_get_id::<T>);
195 iface.add_child = Some(buildable_add_child::<T>);
196 iface.set_buildable_property = Some(buildable_set_buildable_property::<T>);
197 iface.construct_child = Some(buildable_construct_child::<T>);
198 iface.parser_finished = Some(buildable_parser_finished::<T>);
199 iface.get_internal_child = Some(buildable_get_internal_child::<T>);
200 }
205}
206
207unsafe extern "C" fn buildable_set_id<T: BuildableImpl>(
208 buildable: *mut ffi::GtkBuildable,
209 id: *const libc::c_char,
210) {
211 let instance = &*(buildable as *mut T::Instance);
212 let imp = instance.imp();
213 let id = from_glib_borrow::<_, GString>(id);
214
215 imp.set_id(&id)
216}
217
218unsafe extern "C" fn buildable_get_id<T: BuildableImpl>(
219 buildable: *mut ffi::GtkBuildable,
220) -> *const libc::c_char {
221 let instance = &*(buildable as *mut T::Instance);
222 let imp = instance.imp();
223
224 imp.id().into_glib_ptr()
225}
226
227unsafe extern "C" fn buildable_add_child<T: BuildableImpl>(
228 buildable: *mut ffi::GtkBuildable,
229 builderptr: *mut ffi::GtkBuilder,
230 objectptr: *mut glib::gobject_ffi::GObject,
231 typeptr: *const libc::c_char,
232) {
233 let instance = &*(buildable as *mut T::Instance);
234 let imp = instance.imp();
235 let type_ = from_glib_borrow::<_, Option<GString>>(typeptr);
236
237 imp.add_child(
238 &from_glib_borrow(builderptr),
239 &from_glib_borrow(objectptr),
240 type_.as_ref().as_ref().map(|s| s.as_ref()),
241 )
242}
243
244unsafe extern "C" fn buildable_set_buildable_property<T: BuildableImpl>(
245 buildable: *mut ffi::GtkBuildable,
246 builderptr: *mut ffi::GtkBuilder,
247 nameptr: *const libc::c_char,
248 valueptr: *const glib::gobject_ffi::GValue,
249) {
250 let instance = &*(buildable as *mut T::Instance);
251 let imp = instance.imp();
252 let name = from_glib_borrow::<_, GString>(nameptr);
253
254 imp.set_buildable_property(
255 &from_glib_borrow(builderptr),
256 &name,
257 &from_glib_none(valueptr),
258 )
259}
260
261unsafe extern "C" fn buildable_construct_child<T: BuildableImpl>(
262 buildable: *mut ffi::GtkBuildable,
263 builderptr: *mut ffi::GtkBuilder,
264 nameptr: *const libc::c_char,
265) -> *mut glib::gobject_ffi::GObject {
266 let instance = &*(buildable as *mut T::Instance);
267 let imp = instance.imp();
268 let name = from_glib_borrow::<_, GString>(nameptr);
269
270 imp.construct_child(&from_glib_borrow(builderptr), &name)
271 .into_glib_ptr()
272}
273
274unsafe extern "C" fn buildable_parser_finished<T: BuildableImpl>(
275 buildable: *mut ffi::GtkBuildable,
276 builderptr: *mut ffi::GtkBuilder,
277) {
278 let instance = &*(buildable as *mut T::Instance);
279 let imp = instance.imp();
280
281 imp.parser_finished(&from_glib_borrow(builderptr))
282}
283
284unsafe extern "C" fn buildable_get_internal_child<T: BuildableImpl>(
285 buildable: *mut ffi::GtkBuildable,
286 builderptr: *mut ffi::GtkBuilder,
287 nameptr: *const libc::c_char,
288) -> *mut glib::gobject_ffi::GObject {
289 let instance = &*(buildable as *mut T::Instance);
290 let imp = instance.imp();
291 let name = from_glib_borrow::<_, GString>(nameptr);
292
293 let ret = imp.internal_child(&from_glib_borrow(builderptr), &name);
294
295 static QUARK: OnceLock<Quark> = OnceLock::new();
296 let quark =
297 *QUARK.get_or_init(|| Quark::from_str("gtk4-rs-subclass-buildable-get-internal-child"));
298
299 let ret = ret.into_glib_ptr();
302 imp.obj().set_qdata(
303 quark,
304 PtrHolder(ret, |ptr| {
305 glib::gobject_ffi::g_object_unref(ptr as *mut _);
306 }),
307 );
308 ret
309}