1use std::sync::OnceLock;
6
7use glib::{GString, Object, Quark, Value, translate::*};
8
9use super::PtrHolder;
10use crate::{Buildable, Builder, ffi, prelude::*, subclass::prelude::*};
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 unsafe {
212 let instance = &*(buildable as *mut T::Instance);
213 let imp = instance.imp();
214 let id = from_glib_borrow::<_, GString>(id);
215
216 imp.set_id(&id)
217 }
218}
219
220unsafe extern "C" fn buildable_get_id<T: BuildableImpl>(
221 buildable: *mut ffi::GtkBuildable,
222) -> *const libc::c_char {
223 unsafe {
224 let instance = &*(buildable as *mut T::Instance);
225 let imp = instance.imp();
226
227 imp.id().into_glib_ptr()
228 }
229}
230
231unsafe extern "C" fn buildable_add_child<T: BuildableImpl>(
232 buildable: *mut ffi::GtkBuildable,
233 builderptr: *mut ffi::GtkBuilder,
234 objectptr: *mut glib::gobject_ffi::GObject,
235 typeptr: *const libc::c_char,
236) {
237 unsafe {
238 let instance = &*(buildable as *mut T::Instance);
239 let imp = instance.imp();
240 let type_ = from_glib_borrow::<_, Option<GString>>(typeptr);
241
242 imp.add_child(
243 &from_glib_borrow(builderptr),
244 &from_glib_borrow(objectptr),
245 type_.as_ref().as_ref().map(|s| s.as_ref()),
246 )
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 unsafe {
257 let instance = &*(buildable as *mut T::Instance);
258 let imp = instance.imp();
259 let name = from_glib_borrow::<_, GString>(nameptr);
260
261 imp.set_buildable_property(
262 &from_glib_borrow(builderptr),
263 &name,
264 &from_glib_none(valueptr),
265 )
266 }
267}
268
269unsafe extern "C" fn buildable_construct_child<T: BuildableImpl>(
270 buildable: *mut ffi::GtkBuildable,
271 builderptr: *mut ffi::GtkBuilder,
272 nameptr: *const libc::c_char,
273) -> *mut glib::gobject_ffi::GObject {
274 unsafe {
275 let instance = &*(buildable as *mut T::Instance);
276 let imp = instance.imp();
277 let name = from_glib_borrow::<_, GString>(nameptr);
278
279 imp.construct_child(&from_glib_borrow(builderptr), &name)
280 .into_glib_ptr()
281 }
282}
283
284unsafe extern "C" fn buildable_parser_finished<T: BuildableImpl>(
285 buildable: *mut ffi::GtkBuildable,
286 builderptr: *mut ffi::GtkBuilder,
287) {
288 unsafe {
289 let instance = &*(buildable as *mut T::Instance);
290 let imp = instance.imp();
291
292 imp.parser_finished(&from_glib_borrow(builderptr))
293 }
294}
295
296unsafe extern "C" fn buildable_get_internal_child<T: BuildableImpl>(
297 buildable: *mut ffi::GtkBuildable,
298 builderptr: *mut ffi::GtkBuilder,
299 nameptr: *const libc::c_char,
300) -> *mut glib::gobject_ffi::GObject {
301 unsafe {
302 let instance = &*(buildable as *mut T::Instance);
303 let imp = instance.imp();
304 let name = from_glib_borrow::<_, GString>(nameptr);
305
306 let ret = imp.internal_child(&from_glib_borrow(builderptr), &name);
307
308 static QUARK: OnceLock<Quark> = OnceLock::new();
309 let quark =
310 *QUARK.get_or_init(|| Quark::from_str("gtk4-rs-subclass-buildable-get-internal-child"));
311
312 let ret = ret.into_glib_ptr();
315 imp.obj().set_qdata(
316 quark,
317 PtrHolder(ret, |ptr| {
318 glib::gobject_ffi::g_object_unref(ptr as *mut _);
319 }),
320 );
321 ret
322 }
323}