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