1use std::sync::OnceLock;
6
7use glib::{GString, Object, Quark, Value, translate::*};
8
9use crate::{Buildable, Builder, ffi, prelude::*, subclass::prelude::*};
10
11use super::{BuildableParser, PtrHolder};
12
13pub trait BuildableImpl: ObjectImpl + ObjectSubclass<Type: IsA<Buildable>> {
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 fn custom_tag_start(
36 &self,
37 builder: &Builder,
38 child: Option<&Object>,
39 tag_name: &str,
40 ) -> Option<BuildableParser> {
41 self.parent_custom_tag_start(builder, child, tag_name)
42 }
43 unsafe fn custom_tag_end(
50 &self,
51 builder: &Builder,
52 child: Option<&Object>,
53 tag_name: &str,
54 data: glib::ffi::gpointer,
55 ) {
56 unsafe { self.parent_custom_tag_end(builder, child, tag_name, data) }
57 }
58 unsafe fn custom_finished(
65 &self,
66 builder: &Builder,
67 child: Option<&Object>,
68 tag_name: &str,
69 data: glib::ffi::gpointer,
70 ) {
71 unsafe { self.parent_custom_finished(builder, child, tag_name, data) }
72 }
73}
74
75pub trait BuildableImplExt: BuildableImpl {
76 fn parent_set_id(&self, id: &str);
77 fn parent_id(&self) -> Option<GString>;
78 fn parent_add_child(&self, builder: &Builder, child: &Object, type_: Option<&str>);
79 fn parent_set_buildable_property(&self, builder: &Builder, name: &str, value: &Value);
80 fn parent_parser_finished(&self, builder: &Builder);
81 fn parent_internal_child(&self, builder: &Builder, name: &str) -> Option<Object>;
82 fn parent_construct_child(&self, builder: &Builder, name: &str) -> Object;
83 fn parent_custom_tag_start(
84 &self,
85 builder: &Builder,
86 child: Option<&Object>,
87 tag_name: &str,
88 ) -> Option<BuildableParser>;
89 unsafe fn parent_custom_tag_end(
96 &self,
97 builder: &Builder,
98 child: Option<&Object>,
99 tag_name: &str,
100 data: glib::ffi::gpointer,
101 );
102 unsafe fn parent_custom_finished(
109 &self,
110 builder: &Builder,
111 child: Option<&Object>,
112 tag_name: &str,
113 data: glib::ffi::gpointer,
114 );
115}
116
117impl<T: BuildableImpl> BuildableImplExt for T {
118 fn parent_set_id(&self, id: &str) {
119 unsafe {
120 let type_data = Self::type_data();
121 let parent_iface =
122 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
123
124 let func = (*parent_iface)
125 .set_id
126 .expect("no parent \"set_id\" implementation");
127
128 func(
129 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
130 id.to_glib_none().0,
131 )
132 }
133 }
134
135 fn parent_id(&self) -> Option<GString> {
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 let func = (*parent_iface)
142 .get_id
143 .expect("no parent \"get_id\" implementation");
144
145 from_glib_none(func(
146 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
147 ))
148 }
149 }
150
151 fn parent_add_child(&self, builder: &Builder, child: &Object, type_: Option<&str>) {
152 unsafe {
153 let type_data = Self::type_data();
154 let parent_iface =
155 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
156
157 let func = (*parent_iface)
158 .add_child
159 .expect("no parent \"add_child\" implementation");
160
161 func(
162 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
163 builder.to_glib_none().0,
164 child.to_glib_none().0,
165 type_.to_glib_none().0,
166 )
167 }
168 }
169
170 fn parent_set_buildable_property(&self, builder: &Builder, name: &str, value: &Value) {
171 unsafe {
172 let type_data = Self::type_data();
173 let parent_iface =
174 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
175
176 if let Some(func) = (*parent_iface).set_buildable_property {
179 func(
180 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
181 builder.to_glib_none().0,
182 name.to_glib_none().0,
183 value.to_glib_none().0,
184 )
185 } else {
186 self.obj().set_property_from_value(name, value);
187 }
188 }
189 }
190
191 fn parent_parser_finished(&self, builder: &Builder) {
192 unsafe {
193 let type_data = Self::type_data();
194 let parent_iface =
195 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
196
197 if let Some(func) = (*parent_iface).parser_finished {
198 func(
199 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
200 builder.to_glib_none().0,
201 )
202 }
203 }
204 }
205
206 fn parent_internal_child(&self, builder: &Builder, name: &str) -> Option<Object> {
207 unsafe {
208 let type_data = Self::type_data();
209 let parent_iface =
210 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
211
212 if let Some(func) = (*parent_iface).get_internal_child {
213 from_glib_none(func(
214 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
215 builder.to_glib_none().0,
216 name.to_glib_none().0,
217 ))
218 } else {
219 None
220 }
221 }
222 }
223
224 fn parent_construct_child(&self, builder: &Builder, name: &str) -> Object {
225 unsafe {
226 let type_data = Self::type_data();
227 let parent_iface =
228 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
229
230 let func = (*parent_iface)
231 .construct_child
232 .expect("no parent \"construct_child\" implementation");
233
234 from_glib_full(func(
235 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
236 builder.to_glib_none().0,
237 name.to_glib_none().0,
238 ))
239 }
240 }
241
242 fn parent_custom_tag_start(
243 &self,
244 builder: &Builder,
245 child: Option<&Object>,
246 tag_name: &str,
247 ) -> Option<BuildableParser> {
248 unsafe {
249 let type_data = Self::type_data();
250 let parent_iface =
251 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
252
253 let func = (*parent_iface)
254 .custom_tag_start
255 .expect("no parent \"custom_tag_start\" implementation");
256
257 let mut parser = std::mem::MaybeUninit::<ffi::GtkBuildableParser>::uninit();
258 let mut data: glib::ffi::gpointer = std::ptr::null_mut();
259
260 let ret: bool = from_glib(func(
261 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
262 builder.to_glib_none().0,
263 child.to_glib_none().0,
264 tag_name.to_glib_none().0,
265 parser.as_mut_ptr(),
266 &mut data,
267 ));
268 if ret {
269 Some(BuildableParser::from_raw_parts(parser.assume_init(), data))
270 } else {
271 None
272 }
273 }
274 }
275
276 unsafe fn parent_custom_tag_end(
277 &self,
278 builder: &Builder,
279 child: Option<&Object>,
280 tag_name: &str,
281 data: glib::ffi::gpointer,
282 ) {
283 unsafe {
284 let type_data = Self::type_data();
285 let parent_iface =
286 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
287
288 let func = (*parent_iface)
289 .custom_tag_end
290 .expect("no parent \"custom_tag_end\" implementation");
291
292 func(
293 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
294 builder.to_glib_none().0,
295 child.to_glib_none().0,
296 tag_name.to_glib_none().0,
297 data,
298 )
299 }
300 }
301
302 unsafe fn parent_custom_finished(
303 &self,
304 builder: &Builder,
305 child: Option<&Object>,
306 tag_name: &str,
307 data: glib::ffi::gpointer,
308 ) {
309 unsafe {
310 let type_data = Self::type_data();
311 let parent_iface =
312 type_data.as_ref().parent_interface::<Buildable>() as *const ffi::GtkBuildableIface;
313
314 let func = (*parent_iface)
315 .custom_finished
316 .expect("no parent \"custom_finished\" implementation");
317
318 func(
319 self.obj().unsafe_cast_ref::<Buildable>().to_glib_none().0,
320 builder.to_glib_none().0,
321 child.to_glib_none().0,
322 tag_name.to_glib_none().0,
323 data,
324 )
325 }
326 }
327}
328
329unsafe impl<T: BuildableImpl> IsImplementable<T> for Buildable {
330 fn interface_init(iface: &mut glib::Interface<Self>) {
331 let iface = iface.as_mut();
332
333 iface.set_id = Some(buildable_set_id::<T>);
334 iface.get_id = Some(buildable_get_id::<T>);
335 iface.add_child = Some(buildable_add_child::<T>);
336 iface.set_buildable_property = Some(buildable_set_buildable_property::<T>);
337 iface.construct_child = Some(buildable_construct_child::<T>);
338 iface.parser_finished = Some(buildable_parser_finished::<T>);
339 iface.get_internal_child = Some(buildable_get_internal_child::<T>);
340 iface.custom_tag_start = Some(buildable_custom_tag_start::<T>);
341 iface.custom_tag_end = Some(buildable_custom_tag_end::<T>);
342 iface.custom_finished = Some(buildable_custom_finished::<T>);
343 }
344}
345
346unsafe extern "C" fn buildable_set_id<T: BuildableImpl>(
347 buildable: *mut ffi::GtkBuildable,
348 id: *const libc::c_char,
349) {
350 unsafe {
351 let instance = &*(buildable as *mut T::Instance);
352 let imp = instance.imp();
353 let id = from_glib_borrow::<_, GString>(id);
354
355 imp.set_id(&id)
356 }
357}
358
359unsafe extern "C" fn buildable_get_id<T: BuildableImpl>(
360 buildable: *mut ffi::GtkBuildable,
361) -> *const libc::c_char {
362 unsafe {
363 let instance = &*(buildable as *mut T::Instance);
364 let imp = instance.imp();
365
366 imp.id().into_glib_ptr()
367 }
368}
369
370unsafe extern "C" fn buildable_add_child<T: BuildableImpl>(
371 buildable: *mut ffi::GtkBuildable,
372 builderptr: *mut ffi::GtkBuilder,
373 objectptr: *mut glib::gobject_ffi::GObject,
374 typeptr: *const libc::c_char,
375) {
376 unsafe {
377 let instance = &*(buildable as *mut T::Instance);
378 let imp = instance.imp();
379 let type_ = from_glib_borrow::<_, Option<GString>>(typeptr);
380
381 imp.add_child(
382 &from_glib_borrow(builderptr),
383 &from_glib_borrow(objectptr),
384 type_.as_ref().as_ref().map(|s| s.as_ref()),
385 )
386 }
387}
388
389unsafe extern "C" fn buildable_set_buildable_property<T: BuildableImpl>(
390 buildable: *mut ffi::GtkBuildable,
391 builderptr: *mut ffi::GtkBuilder,
392 nameptr: *const libc::c_char,
393 valueptr: *const glib::gobject_ffi::GValue,
394) {
395 unsafe {
396 let instance = &*(buildable as *mut T::Instance);
397 let imp = instance.imp();
398 let name = from_glib_borrow::<_, GString>(nameptr);
399
400 imp.set_buildable_property(
401 &from_glib_borrow(builderptr),
402 &name,
403 &from_glib_none(valueptr),
404 )
405 }
406}
407
408unsafe extern "C" fn buildable_construct_child<T: BuildableImpl>(
409 buildable: *mut ffi::GtkBuildable,
410 builderptr: *mut ffi::GtkBuilder,
411 nameptr: *const libc::c_char,
412) -> *mut glib::gobject_ffi::GObject {
413 unsafe {
414 let instance = &*(buildable as *mut T::Instance);
415 let imp = instance.imp();
416 let name = from_glib_borrow::<_, GString>(nameptr);
417
418 imp.construct_child(&from_glib_borrow(builderptr), &name)
419 .into_glib_ptr()
420 }
421}
422
423unsafe extern "C" fn buildable_parser_finished<T: BuildableImpl>(
424 buildable: *mut ffi::GtkBuildable,
425 builderptr: *mut ffi::GtkBuilder,
426) {
427 unsafe {
428 let instance = &*(buildable as *mut T::Instance);
429 let imp = instance.imp();
430
431 imp.parser_finished(&from_glib_borrow(builderptr))
432 }
433}
434
435unsafe extern "C" fn buildable_get_internal_child<T: BuildableImpl>(
436 buildable: *mut ffi::GtkBuildable,
437 builderptr: *mut ffi::GtkBuilder,
438 nameptr: *const libc::c_char,
439) -> *mut glib::gobject_ffi::GObject {
440 unsafe {
441 let instance = &*(buildable as *mut T::Instance);
442 let imp = instance.imp();
443 let name = from_glib_borrow::<_, GString>(nameptr);
444
445 let ret = imp.internal_child(&from_glib_borrow(builderptr), &name);
446
447 static QUARK: OnceLock<Quark> = OnceLock::new();
448 let quark =
449 *QUARK.get_or_init(|| Quark::from_str("gtk4-rs-subclass-buildable-get-internal-child"));
450
451 let ret = ret.into_glib_ptr();
454 imp.obj().set_qdata(
455 quark,
456 PtrHolder(ret, |ptr| {
457 glib::gobject_ffi::g_object_unref(ptr as *mut _);
458 }),
459 );
460 ret
461 }
462}
463
464unsafe extern "C" fn buildable_custom_tag_start<T: BuildableImpl>(
465 buildable: *mut ffi::GtkBuildable,
466 builderptr: *mut ffi::GtkBuilder,
467 child: *mut glib::gobject_ffi::GObject,
468 nameptr: *const libc::c_char,
469 parserptr: *mut ffi::GtkBuildableParser,
470 data: *mut glib::ffi::gpointer,
471) -> glib::ffi::gboolean {
472 unsafe {
473 let instance = &*(buildable as *mut T::Instance);
474 let imp = instance.imp();
475 let name = from_glib_borrow::<_, GString>(nameptr);
476 let child = from_glib_borrow::<_, Option<Object>>(child);
477
478 if let Some(parser) = imp.custom_tag_start(
479 &from_glib_borrow(builderptr),
480 child.as_ref().as_ref(),
481 &name,
482 ) {
483 let (raw_parser, user_data) = parser.into_raw_parts();
484 std::ptr::write(parserptr, raw_parser);
485 *data = user_data;
486 true.into_glib()
487 } else {
488 false.into_glib()
489 }
490 }
491}
492
493unsafe extern "C" fn buildable_custom_tag_end<T: BuildableImpl>(
494 buildable: *mut ffi::GtkBuildable,
495 builderptr: *mut ffi::GtkBuilder,
496 child: *mut glib::gobject_ffi::GObject,
497 nameptr: *const libc::c_char,
498 data: glib::ffi::gpointer,
499) {
500 unsafe {
501 let instance = &*(buildable as *mut T::Instance);
502 let imp = instance.imp();
503 let name = from_glib_borrow::<_, GString>(nameptr);
504 let child = from_glib_borrow::<_, Option<Object>>(child);
505
506 imp.custom_tag_end(
507 &from_glib_borrow(builderptr),
508 child.as_ref().as_ref(),
509 &name,
510 data,
511 )
512 }
513}
514
515unsafe extern "C" fn buildable_custom_finished<T: BuildableImpl>(
516 buildable: *mut ffi::GtkBuildable,
517 builderptr: *mut ffi::GtkBuilder,
518 child: *mut glib::gobject_ffi::GObject,
519 nameptr: *const libc::c_char,
520 data: glib::ffi::gpointer,
521) {
522 unsafe {
523 let instance = &*(buildable as *mut T::Instance);
524 let imp = instance.imp();
525 let name = from_glib_borrow::<_, GString>(nameptr);
526 let child = from_glib_borrow::<_, Option<Object>>(child);
527
528 imp.custom_finished(
529 &from_glib_borrow(builderptr),
530 child.as_ref().as_ref(),
531 &name,
532 data,
533 )
534 }
535}