gtk4/subclass/
widget.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for subclassing [`Widget`].
5
6use std::{boxed::Box as Box_, collections::HashMap, fmt, future::Future};
7
8use glib::{
9    clone::Downgrade,
10    property::{Property, PropertyGet},
11    subclass::SignalId,
12    translate::*,
13    GString, Variant,
14};
15
16use crate::{
17    ffi, prelude::*, subclass::prelude::*, Accessible, AccessibleRole, Buildable, BuilderRustScope,
18    BuilderScope, ConstraintTarget, DirectionType, LayoutManager, Orientation, Shortcut,
19    SizeRequestMode, Snapshot, StateFlags, SystemSetting, TextDirection, Tooltip, Widget,
20};
21
22#[derive(Debug, Default)]
23struct Internal {
24    pub(crate) actions: HashMap<String, glib::ffi::gpointer>,
25    pub(crate) scope: Option<*mut <<BuilderRustScope as glib::object::ObjectSubclassIs>::Subclass as ObjectSubclass>::Instance>,
26}
27unsafe impl Sync for Internal {}
28unsafe impl Send for Internal {}
29
30pub struct WidgetActionIter(*mut ffi::GtkWidgetClass, u32);
31
32pub struct WidgetAction(
33    glib::Type,
34    GString,
35    Option<glib::VariantType>,
36    Option<GString>,
37);
38
39impl WidgetAction {
40    // rustdoc-stripper-ignore-next
41    /// The type where the action was defined
42    pub fn owner(&self) -> glib::Type {
43        self.0
44    }
45
46    // rustdoc-stripper-ignore-next
47    /// The action name
48    pub fn name(&self) -> &str {
49        self.1.as_ref()
50    }
51
52    // rustdoc-stripper-ignore-next
53    /// The action parameter type
54    pub fn parameter_type(&self) -> Option<&glib::VariantType> {
55        self.2.as_ref()
56    }
57
58    // rustdoc-stripper-ignore-next
59    /// The action property name
60    pub fn property_name(&self) -> Option<&str> {
61        self.3.as_ref().map(|s| s.as_ref())
62    }
63}
64
65impl fmt::Debug for WidgetAction {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.debug_struct("WidgetAction")
68            .field("owner", &self.owner())
69            .field("name", &self.name())
70            .field("parameter_type", &self.parameter_type())
71            .field("property_name", &self.property_name())
72            .finish()
73    }
74}
75
76impl Iterator for WidgetActionIter {
77    type Item = WidgetAction;
78
79    fn next(&mut self) -> Option<Self::Item> {
80        unsafe {
81            let mut owner = std::mem::MaybeUninit::uninit();
82            let mut action_name_ptr = std::ptr::null();
83            let mut parameter_type = std::ptr::null();
84            let mut property_name_ptr = std::ptr::null();
85            let found: bool = from_glib(ffi::gtk_widget_class_query_action(
86                self.0,
87                self.1,
88                owner.as_mut_ptr(),
89                &mut action_name_ptr,
90                &mut parameter_type,
91                &mut property_name_ptr,
92            ));
93            if found {
94                self.1 += 1;
95                let property_name: Option<GString> = from_glib_none(property_name_ptr);
96                let action_name: GString = from_glib_none(action_name_ptr);
97
98                Some(WidgetAction(
99                    from_glib(owner.assume_init()),
100                    action_name,
101                    from_glib_none(parameter_type),
102                    property_name,
103                ))
104            } else {
105                None
106            }
107        }
108    }
109}
110
111impl std::iter::FusedIterator for WidgetActionIter {}
112
113pub trait WidgetImpl:
114    ObjectImpl
115    + ObjectSubclass<Type: IsA<Widget> + IsA<Accessible> + IsA<Buildable> + IsA<ConstraintTarget>>
116{
117    fn compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
118        self.parent_compute_expand(hexpand, vexpand)
119    }
120
121    fn contains(&self, x: f64, y: f64) -> bool {
122        self.parent_contains(x, y)
123    }
124
125    fn direction_changed(&self, previous_direction: TextDirection) {
126        self.parent_direction_changed(previous_direction)
127    }
128
129    fn focus(&self, direction_type: DirectionType) -> bool {
130        self.parent_focus(direction_type)
131    }
132
133    #[doc(alias = "get_request_mode")]
134    fn request_mode(&self) -> SizeRequestMode {
135        self.parent_request_mode()
136    }
137
138    fn grab_focus(&self) -> bool {
139        self.parent_grab_focus()
140    }
141
142    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
143    #[allow(deprecated)]
144    fn hide(&self) {
145        self.parent_hide()
146    }
147
148    fn keynav_failed(&self, direction_type: DirectionType) -> bool {
149        self.parent_keynav_failed(direction_type)
150    }
151
152    fn map(&self) {
153        self.parent_map()
154    }
155
156    fn measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
157        self.parent_measure(orientation, for_size)
158    }
159
160    fn mnemonic_activate(&self, group_cycling: bool) -> bool {
161        self.parent_mnemonic_activate(group_cycling)
162    }
163
164    fn move_focus(&self, direction_type: DirectionType) {
165        self.parent_move_focus(direction_type)
166    }
167
168    fn query_tooltip(&self, x: i32, y: i32, keyboard_tooltip: bool, tooltip: &Tooltip) -> bool {
169        self.parent_query_tooltip(x, y, keyboard_tooltip, tooltip)
170    }
171
172    fn realize(&self) {
173        self.parent_realize()
174    }
175
176    fn root(&self) {
177        self.parent_root()
178    }
179
180    fn set_focus_child(&self, child: Option<&Widget>) {
181        self.parent_set_focus_child(child)
182    }
183
184    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
185    #[allow(deprecated)]
186    fn show(&self) {
187        self.parent_show()
188    }
189
190    fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
191        self.parent_size_allocate(width, height, baseline)
192    }
193
194    fn snapshot(&self, snapshot: &Snapshot) {
195        self.parent_snapshot(snapshot)
196    }
197
198    fn state_flags_changed(&self, state_flags: &StateFlags) {
199        self.parent_state_flags_changed(state_flags)
200    }
201
202    fn system_setting_changed(&self, settings: &SystemSetting) {
203        self.parent_system_setting_changed(settings)
204    }
205
206    fn unmap(&self) {
207        self.parent_unmap()
208    }
209
210    fn unrealize(&self) {
211        self.parent_unrealize()
212    }
213
214    fn unroot(&self) {
215        self.parent_unroot()
216    }
217}
218
219pub trait WidgetImplExt: WidgetImpl {
220    fn parent_compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
221        unsafe {
222            let data = Self::type_data();
223            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
224            if let Some(f) = (*parent_class).compute_expand {
225                let mut hexpand_glib = hexpand.into_glib();
226                let mut vexpand_glib = vexpand.into_glib();
227                f(
228                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
229                    &mut hexpand_glib,
230                    &mut vexpand_glib,
231                );
232                *hexpand = from_glib(hexpand_glib);
233                *vexpand = from_glib(vexpand_glib);
234            }
235        }
236    }
237
238    // true if the widget contains (x, y)
239    fn parent_contains(&self, x: f64, y: f64) -> bool {
240        unsafe {
241            let data = Self::type_data();
242            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
243            if let Some(f) = (*parent_class).contains {
244                from_glib(f(
245                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
246                    x,
247                    y,
248                ))
249            } else {
250                false
251            }
252        }
253    }
254
255    fn parent_direction_changed(&self, previous_direction: TextDirection) {
256        unsafe {
257            let data = Self::type_data();
258            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
259            if let Some(f) = (*parent_class).direction_changed {
260                f(
261                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
262                    previous_direction.into_glib(),
263                )
264            }
265        }
266    }
267
268    // Returns true if focus ended up inside widget
269    fn parent_focus(&self, direction_type: DirectionType) -> bool {
270        unsafe {
271            let data = Self::type_data();
272            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
273            if let Some(f) = (*parent_class).focus {
274                from_glib(f(
275                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
276                    direction_type.into_glib(),
277                ))
278            } else {
279                false
280            }
281        }
282    }
283
284    fn parent_request_mode(&self) -> SizeRequestMode {
285        unsafe {
286            let data = Self::type_data();
287            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
288            let f = (*parent_class)
289                .get_request_mode
290                .expect("No parent class impl for \"get_request_mode\"");
291            from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
292        }
293    }
294
295    // Returns true if focus ended up inside widget
296    fn parent_grab_focus(&self) -> bool {
297        unsafe {
298            let data = Self::type_data();
299            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
300            if let Some(f) = (*parent_class).grab_focus {
301                from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
302            } else {
303                false
304            }
305        }
306    }
307
308    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
309    #[allow(deprecated)]
310    fn parent_hide(&self) {
311        unsafe {
312            let data = Self::type_data();
313            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
314            if let Some(f) = (*parent_class).hide {
315                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
316            }
317        }
318    }
319
320    // TRUE if stopping keyboard navigation is fine,
321    // FALSE if the emitting widget should try to handle the keyboard navigation
322    // attempt in its parent container(s).
323    fn parent_keynav_failed(&self, direction_type: DirectionType) -> bool {
324        unsafe {
325            let data = Self::type_data();
326            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
327            if let Some(f) = (*parent_class).keynav_failed {
328                from_glib(f(
329                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
330                    direction_type.into_glib(),
331                ))
332            } else {
333                false
334            }
335        }
336    }
337
338    fn parent_map(&self) {
339        unsafe {
340            let data = Self::type_data();
341            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
342            if let Some(f) = (*parent_class).map {
343                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
344            }
345        }
346    }
347
348    fn parent_measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
349        unsafe {
350            let data = Self::type_data();
351            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
352
353            let f = (*parent_class)
354                .measure
355                .expect("No parent class impl for \"measure\"");
356
357            let mut min = 0;
358            let mut nat = 0;
359            let mut min_base = -1;
360            let mut nat_base = -1;
361            f(
362                self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
363                orientation.into_glib(),
364                for_size,
365                &mut min,
366                &mut nat,
367                &mut min_base,
368                &mut nat_base,
369            );
370            (min, nat, min_base, nat_base)
371        }
372    }
373
374    // True if the signal has been handled
375    fn parent_mnemonic_activate(&self, group_cycling: bool) -> bool {
376        unsafe {
377            let data = Self::type_data();
378            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
379            if let Some(f) = (*parent_class).mnemonic_activate {
380                from_glib(f(
381                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
382                    group_cycling.into_glib(),
383                ))
384            } else {
385                false
386            }
387        }
388    }
389
390    fn parent_move_focus(&self, direction_type: DirectionType) {
391        unsafe {
392            let data = Self::type_data();
393            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
394            if let Some(f) = (*parent_class).move_focus {
395                f(
396                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
397                    direction_type.into_glib(),
398                )
399            }
400        }
401    }
402
403    fn parent_query_tooltip(
404        &self,
405        x: i32,
406        y: i32,
407        keyboard_tooltip: bool,
408        tooltip: &Tooltip,
409    ) -> bool {
410        unsafe {
411            let data = Self::type_data();
412            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
413            if let Some(f) = (*parent_class).query_tooltip {
414                from_glib(f(
415                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
416                    x,
417                    y,
418                    keyboard_tooltip.into_glib(),
419                    tooltip.to_glib_none().0,
420                ))
421            } else {
422                false
423            }
424        }
425    }
426
427    fn parent_realize(&self) {
428        unsafe {
429            let data = Self::type_data();
430            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
431            if let Some(f) = (*parent_class).realize {
432                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
433            }
434        }
435    }
436
437    fn parent_root(&self) {
438        unsafe {
439            let data = Self::type_data();
440            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
441            if let Some(f) = (*parent_class).root {
442                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
443            }
444        }
445    }
446
447    fn parent_set_focus_child(&self, child: Option<&Widget>) {
448        unsafe {
449            let data = Self::type_data();
450            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
451            if let Some(f) = (*parent_class).set_focus_child {
452                f(
453                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
454                    child.to_glib_none().0,
455                )
456            }
457        }
458    }
459
460    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
461    #[allow(deprecated)]
462    fn parent_show(&self) {
463        unsafe {
464            let data = Self::type_data();
465            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
466            if let Some(f) = (*parent_class).show {
467                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
468            }
469        }
470    }
471
472    fn parent_size_allocate(&self, width: i32, height: i32, baseline: i32) {
473        unsafe {
474            let data = Self::type_data();
475            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
476            if let Some(f) = (*parent_class).size_allocate {
477                f(
478                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
479                    width,
480                    height,
481                    baseline,
482                )
483            }
484        }
485    }
486
487    fn parent_snapshot(&self, snapshot: &Snapshot) {
488        unsafe {
489            let data = Self::type_data();
490            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
491            if let Some(f) = (*parent_class).snapshot {
492                f(
493                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
494                    snapshot.to_glib_none().0,
495                )
496            }
497        }
498    }
499
500    fn parent_state_flags_changed(&self, state_flags: &StateFlags) {
501        unsafe {
502            let data = Self::type_data();
503            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
504            if let Some(f) = (*parent_class).state_flags_changed {
505                f(
506                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
507                    state_flags.into_glib(),
508                )
509            }
510        }
511    }
512
513    fn parent_system_setting_changed(&self, settings: &SystemSetting) {
514        unsafe {
515            let data = Self::type_data();
516            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
517            if let Some(f) = (*parent_class).system_setting_changed {
518                f(
519                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
520                    settings.into_glib(),
521                )
522            }
523        }
524    }
525
526    fn parent_unmap(&self) {
527        unsafe {
528            let data = Self::type_data();
529            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
530            if let Some(f) = (*parent_class).unmap {
531                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
532            }
533        }
534    }
535
536    fn parent_unrealize(&self) {
537        unsafe {
538            let data = Self::type_data();
539            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
540            if let Some(f) = (*parent_class).unrealize {
541                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
542            }
543        }
544    }
545
546    fn parent_unroot(&self) {
547        unsafe {
548            let data = Self::type_data();
549            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
550            if let Some(f) = (*parent_class).unroot {
551                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
552            }
553        }
554    }
555}
556
557impl<T: WidgetImpl> WidgetImplExt for T {}
558
559unsafe impl<T: WidgetImpl> IsSubclassable<T> for Widget {
560    fn class_init(class: &mut ::glib::Class<Self>) {
561        Self::parent_class_init::<T>(class);
562
563        assert_initialized_main_thread!();
564
565        let klass = class.as_mut();
566        unsafe {
567            let mut data = T::type_data();
568            let data = data.as_mut();
569            // Used to store actions for `install_action` and `rust_builder_scope`
570            data.set_class_data(<T as ObjectSubclassType>::type_(), Internal::default());
571        }
572
573        klass.compute_expand = Some(widget_compute_expand::<T>);
574        klass.contains = Some(widget_contains::<T>);
575        klass.direction_changed = Some(widget_direction_changed::<T>);
576        klass.focus = Some(widget_focus::<T>);
577        klass.get_request_mode = Some(widget_get_request_mode::<T>);
578        klass.grab_focus = Some(widget_grab_focus::<T>);
579        klass.hide = Some(widget_hide::<T>);
580        klass.keynav_failed = Some(widget_keynav_failed::<T>);
581        klass.map = Some(widget_map::<T>);
582        klass.measure = Some(widget_measure::<T>);
583        klass.mnemonic_activate = Some(widget_mnemonic_activate::<T>);
584        klass.move_focus = Some(widget_move_focus::<T>);
585        klass.query_tooltip = Some(widget_query_tooltip::<T>);
586        klass.realize = Some(widget_realize::<T>);
587        klass.root = Some(widget_root::<T>);
588        klass.set_focus_child = Some(widget_set_focus_child::<T>);
589        klass.show = Some(widget_show::<T>);
590        klass.size_allocate = Some(widget_size_allocate::<T>);
591        klass.snapshot = Some(widget_snapshot::<T>);
592        klass.state_flags_changed = Some(widget_state_flags_changed::<T>);
593        klass.system_setting_changed = Some(widget_system_setting_changed::<T>);
594        klass.unmap = Some(widget_unmap::<T>);
595        klass.unrealize = Some(widget_unrealize::<T>);
596        klass.unroot = Some(widget_unroot::<T>);
597    }
598}
599
600unsafe extern "C" fn widget_compute_expand<T: WidgetImpl>(
601    ptr: *mut ffi::GtkWidget,
602    hexpand_ptr: *mut glib::ffi::gboolean,
603    vexpand_ptr: *mut glib::ffi::gboolean,
604) {
605    let instance = &*(ptr as *mut T::Instance);
606    let imp = instance.imp();
607
608    let widget = imp.obj();
609    let widget = widget.unsafe_cast_ref::<Widget>();
610    let mut hexpand: bool = if widget.is_hexpand_set() {
611        widget.hexpands()
612    } else {
613        from_glib(*hexpand_ptr)
614    };
615    let mut vexpand: bool = if widget.is_vexpand_set() {
616        widget.vexpands()
617    } else {
618        from_glib(*vexpand_ptr)
619    };
620
621    imp.compute_expand(&mut hexpand, &mut vexpand);
622
623    *hexpand_ptr = hexpand.into_glib();
624    *vexpand_ptr = vexpand.into_glib();
625}
626
627unsafe extern "C" fn widget_contains<T: WidgetImpl>(
628    ptr: *mut ffi::GtkWidget,
629    x: f64,
630    y: f64,
631) -> glib::ffi::gboolean {
632    let instance = &*(ptr as *mut T::Instance);
633    let imp = instance.imp();
634
635    imp.contains(x, y).into_glib()
636}
637
638unsafe extern "C" fn widget_direction_changed<T: WidgetImpl>(
639    ptr: *mut ffi::GtkWidget,
640    direction_ptr: ffi::GtkTextDirection,
641) {
642    let instance = &*(ptr as *mut T::Instance);
643    let imp = instance.imp();
644    let direction_wrap = from_glib(direction_ptr);
645
646    imp.direction_changed(direction_wrap)
647}
648
649unsafe extern "C" fn widget_focus<T: WidgetImpl>(
650    ptr: *mut ffi::GtkWidget,
651    direction_type_ptr: ffi::GtkDirectionType,
652) -> glib::ffi::gboolean {
653    let instance = &*(ptr as *mut T::Instance);
654    let imp = instance.imp();
655    let direction_type = from_glib(direction_type_ptr);
656
657    imp.focus(direction_type).into_glib()
658}
659
660unsafe extern "C" fn widget_get_request_mode<T: WidgetImpl>(
661    ptr: *mut ffi::GtkWidget,
662) -> ffi::GtkSizeRequestMode {
663    let instance = &*(ptr as *mut T::Instance);
664    let imp = instance.imp();
665
666    imp.request_mode().into_glib()
667}
668
669unsafe extern "C" fn widget_grab_focus<T: WidgetImpl>(
670    ptr: *mut ffi::GtkWidget,
671) -> glib::ffi::gboolean {
672    let instance = &*(ptr as *mut T::Instance);
673    let imp = instance.imp();
674
675    imp.grab_focus().into_glib()
676}
677
678unsafe extern "C" fn widget_hide<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
679    let instance = &*(ptr as *mut T::Instance);
680    let imp = instance.imp();
681
682    imp.hide()
683}
684
685unsafe extern "C" fn widget_keynav_failed<T: WidgetImpl>(
686    ptr: *mut ffi::GtkWidget,
687    direction_type_ptr: ffi::GtkDirectionType,
688) -> glib::ffi::gboolean {
689    let instance = &*(ptr as *mut T::Instance);
690    let imp = instance.imp();
691    let direction_type = from_glib(direction_type_ptr);
692
693    imp.keynav_failed(direction_type).into_glib()
694}
695
696unsafe extern "C" fn widget_map<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
697    let instance = &*(ptr as *mut T::Instance);
698    let imp = instance.imp();
699
700    imp.map()
701}
702
703unsafe extern "C" fn widget_measure<T: WidgetImpl>(
704    ptr: *mut ffi::GtkWidget,
705    orientation_ptr: ffi::GtkOrientation,
706    for_size: i32,
707    min_ptr: *mut libc::c_int,
708    nat_ptr: *mut libc::c_int,
709    min_base_ptr: *mut libc::c_int,
710    nat_base_ptr: *mut libc::c_int,
711) {
712    let instance = &*(ptr as *mut T::Instance);
713    let imp = instance.imp();
714    let orientation = from_glib(orientation_ptr);
715    let (min, nat, min_base, nat_base) = imp.measure(orientation, for_size);
716    if !min_ptr.is_null() {
717        *min_ptr = min;
718    }
719    if !nat_ptr.is_null() {
720        *nat_ptr = nat;
721    }
722    if !min_base_ptr.is_null() {
723        *min_base_ptr = min_base;
724    }
725    if !nat_base_ptr.is_null() {
726        *nat_base_ptr = nat_base;
727    }
728}
729
730unsafe extern "C" fn widget_mnemonic_activate<T: WidgetImpl>(
731    ptr: *mut ffi::GtkWidget,
732    group_cycling_ptr: glib::ffi::gboolean,
733) -> glib::ffi::gboolean {
734    let instance = &*(ptr as *mut T::Instance);
735    let imp = instance.imp();
736    let group_cycling: bool = from_glib(group_cycling_ptr);
737
738    imp.mnemonic_activate(group_cycling).into_glib()
739}
740
741unsafe extern "C" fn widget_move_focus<T: WidgetImpl>(
742    ptr: *mut ffi::GtkWidget,
743    direction_type_ptr: ffi::GtkDirectionType,
744) {
745    let instance = &*(ptr as *mut T::Instance);
746    let imp = instance.imp();
747    let direction_type = from_glib(direction_type_ptr);
748
749    imp.move_focus(direction_type)
750}
751
752unsafe extern "C" fn widget_query_tooltip<T: WidgetImpl>(
753    ptr: *mut ffi::GtkWidget,
754    x: i32,
755    y: i32,
756    keyboard_tooltip_ptr: glib::ffi::gboolean,
757    tooltip_ptr: *mut ffi::GtkTooltip,
758) -> glib::ffi::gboolean {
759    let instance = &*(ptr as *mut T::Instance);
760    let imp = instance.imp();
761
762    let keyboard_tooltip: bool = from_glib(keyboard_tooltip_ptr);
763    let tooltip = from_glib_borrow(tooltip_ptr);
764
765    imp.query_tooltip(x, y, keyboard_tooltip, &tooltip)
766        .into_glib()
767}
768
769unsafe extern "C" fn widget_realize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
770    let instance = &*(ptr as *mut T::Instance);
771    let imp = instance.imp();
772
773    imp.realize()
774}
775
776unsafe extern "C" fn widget_root<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
777    let instance = &*(ptr as *mut T::Instance);
778    let imp = instance.imp();
779
780    imp.root()
781}
782
783unsafe extern "C" fn widget_set_focus_child<T: WidgetImpl>(
784    ptr: *mut ffi::GtkWidget,
785    child_ptr: *mut ffi::GtkWidget,
786) {
787    let instance = &*(ptr as *mut T::Instance);
788    let imp = instance.imp();
789    let child: Borrowed<Option<Widget>> = from_glib_borrow(child_ptr);
790
791    imp.set_focus_child(child.as_ref().as_ref())
792}
793
794unsafe extern "C" fn widget_show<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
795    let instance = &*(ptr as *mut T::Instance);
796    let imp = instance.imp();
797
798    imp.show()
799}
800
801unsafe extern "C" fn widget_size_allocate<T: WidgetImpl>(
802    ptr: *mut ffi::GtkWidget,
803    width: i32,
804    height: i32,
805    baseline: i32,
806) {
807    let instance = &*(ptr as *mut T::Instance);
808    let imp = instance.imp();
809
810    imp.size_allocate(width, height, baseline)
811}
812
813unsafe extern "C" fn widget_snapshot<T: WidgetImpl>(
814    ptr: *mut ffi::GtkWidget,
815    snapshot_ptr: *mut ffi::GtkSnapshot,
816) {
817    let instance = &*(ptr as *mut T::Instance);
818    let imp = instance.imp();
819    let snapshot = from_glib_borrow(snapshot_ptr);
820
821    imp.snapshot(&snapshot)
822}
823
824unsafe extern "C" fn widget_state_flags_changed<T: WidgetImpl>(
825    ptr: *mut ffi::GtkWidget,
826    state_flags_ptr: ffi::GtkStateFlags,
827) {
828    let instance = &*(ptr as *mut T::Instance);
829    let imp = instance.imp();
830    let state_flags = from_glib(state_flags_ptr);
831
832    imp.state_flags_changed(&state_flags)
833}
834
835unsafe extern "C" fn widget_system_setting_changed<T: WidgetImpl>(
836    ptr: *mut ffi::GtkWidget,
837    settings_ptr: ffi::GtkSystemSetting,
838) {
839    let instance = &*(ptr as *mut T::Instance);
840    let imp = instance.imp();
841    let settings = from_glib(settings_ptr);
842
843    imp.system_setting_changed(&settings)
844}
845
846unsafe extern "C" fn widget_unmap<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
847    let instance = &*(ptr as *mut T::Instance);
848    let imp = instance.imp();
849
850    imp.unmap()
851}
852
853unsafe extern "C" fn widget_unrealize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
854    let instance = &*(ptr as *mut T::Instance);
855    let imp = instance.imp();
856
857    imp.unrealize()
858}
859
860unsafe extern "C" fn widget_unroot<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
861    let instance = &*(ptr as *mut T::Instance);
862    let imp = instance.imp();
863
864    imp.unroot()
865}
866
867#[allow(clippy::missing_safety_doc)]
868pub unsafe trait WidgetClassExt: ClassStruct {
869    #[doc(alias = "gtk_widget_class_set_template")]
870    fn set_template_bytes(&mut self, template: &glib::Bytes) {
871        unsafe {
872            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
873            ffi::gtk_widget_class_set_template(widget_class, template.to_glib_none().0);
874        }
875    }
876
877    fn set_template(&mut self, template: &[u8]) {
878        let template_bytes = glib::Bytes::from(template);
879        self.set_template_bytes(&template_bytes);
880    }
881
882    fn set_template_static(&mut self, template: &'static [u8]) {
883        let template_bytes = glib::Bytes::from_static(template);
884        self.set_template_bytes(&template_bytes);
885    }
886
887    #[doc(alias = "gtk_widget_class_set_template_from_resource")]
888    fn set_template_from_resource(&mut self, resource_name: &str) {
889        unsafe {
890            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
891            ffi::gtk_widget_class_set_template_from_resource(
892                widget_class,
893                resource_name.to_glib_none().0,
894            );
895        }
896    }
897
898    fn install_action_async<Fut, F>(
899        &mut self,
900        action_name: &str,
901        parameter_type: Option<&glib::VariantTy>,
902        activate: F,
903    ) where
904        F: Fn(
905                <<Self as ClassStruct>::Type as ObjectSubclass>::Type,
906                String,
907                Option<Variant>,
908            ) -> Fut
909            + 'static
910            + Clone,
911        Fut: Future<Output = ()>,
912    {
913        self.install_action(
914            action_name,
915            parameter_type,
916            move |this, action_name, parameter_type| {
917                let ctx = glib::MainContext::default();
918                let action_name = action_name.to_owned();
919                let parameter_type = parameter_type.map(ToOwned::to_owned);
920                ctx.spawn_local(glib::clone!(
921                    #[strong]
922                    this,
923                    #[strong]
924                    action_name,
925                    #[strong]
926                    parameter_type,
927                    #[strong]
928                    activate,
929                    async move {
930                        activate(this, action_name, parameter_type).await;
931                    }
932                ));
933            },
934        );
935    }
936
937    #[doc(alias = "gtk_widget_class_install_action")]
938    fn install_action<F>(
939        &mut self,
940        action_name: &str,
941        parameter_type: Option<&glib::VariantTy>,
942        activate: F,
943    ) where
944        F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
945            + 'static,
946    {
947        unsafe {
948            // We store the activate callbacks in a HashMap<action_name, activate>
949            // so that we can retrieve f later on the activate_trampoline call
950            let mut data = <Self::Type as ObjectSubclassType>::type_data();
951            let data = data.as_mut();
952
953            let f: Box_<F> = Box_::new(activate);
954
955            let internal = data
956                .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
957                .expect("Something bad happened at class_init, the internal class_data is missing");
958            let callback_ptr = Box_::into_raw(f) as glib::ffi::gpointer;
959            internal
960                .actions
961                .insert(action_name.to_string(), callback_ptr);
962
963            unsafe extern "C" fn activate_trampoline<F, S>(
964                this: *mut ffi::GtkWidget,
965                action_name: *const libc::c_char,
966                parameter: *mut glib::ffi::GVariant,
967            ) where
968                S: ClassStruct,
969                <S as ClassStruct>::Type: ObjectSubclass,
970                F: Fn(&<<S as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
971                    + 'static,
972            {
973                let action_name = GString::from_glib_borrow(action_name);
974
975                let data = <S::Type as ObjectSubclassType>::type_data();
976                let internal = data
977                    .as_ref()
978                    .class_data::<Internal>(<S::Type as ObjectSubclassType>::type_())
979                    .unwrap();
980                let activate_callback = *internal
981                    .actions
982                    .get(&action_name.to_string())
983                    .unwrap_or_else(|| {
984                        panic!("Action name '{}' was not found", action_name.as_str());
985                    });
986
987                let widget = Widget::from_glib_borrow(this);
988
989                let f: &F = &*(activate_callback as *const F);
990                f(
991                    widget.unsafe_cast_ref(),
992                    &action_name,
993                    Option::<Variant>::from_glib_borrow(parameter)
994                        .as_ref()
995                        .as_ref(),
996                )
997            }
998            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
999            let callback = activate_trampoline::<F, Self>;
1000            ffi::gtk_widget_class_install_action(
1001                widget_class,
1002                action_name.to_glib_none().0,
1003                parameter_type.map(|p| p.as_str()).to_glib_none().0,
1004                Some(callback),
1005            );
1006        }
1007    }
1008
1009    #[doc(alias = "gtk_widget_class_query_action")]
1010    fn query_action(&self) -> WidgetActionIter {
1011        let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1012        WidgetActionIter(widget_class, 0)
1013    }
1014
1015    #[doc(alias = "gtk_widget_class_set_template_scope")]
1016    fn set_template_scope<S: IsA<BuilderScope>>(&mut self, scope: &S) {
1017        unsafe {
1018            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1019            ffi::gtk_widget_class_set_template_scope(widget_class, scope.as_ref().to_glib_none().0);
1020        }
1021    }
1022
1023    #[doc(alias = "gtk_widget_class_add_binding")]
1024    fn add_binding<
1025        F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type) -> glib::Propagation + 'static,
1026    >(
1027        &mut self,
1028        keyval: gdk::Key,
1029        mods: gdk::ModifierType,
1030        callback: F,
1031    ) {
1032        let shortcut = crate::Shortcut::new(
1033            Some(crate::KeyvalTrigger::new(keyval, mods)),
1034            Some(crate::CallbackAction::new(
1035                move |widget, _| -> glib::Propagation {
1036                    unsafe { callback(widget.unsafe_cast_ref()) }
1037                },
1038            )),
1039        );
1040        self.add_shortcut(&shortcut);
1041    }
1042
1043    #[doc(alias = "gtk_widget_class_add_binding_action")]
1044    fn add_binding_action(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, action_name: &str) {
1045        let shortcut = crate::Shortcut::new(
1046            Some(crate::KeyvalTrigger::new(keyval, mods)),
1047            Some(crate::NamedAction::new(action_name)),
1048        );
1049        self.add_shortcut(&shortcut);
1050    }
1051
1052    #[doc(alias = "gtk_widget_class_add_binding_signal")]
1053    fn add_binding_signal(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, signal_name: &str) {
1054        let type_ = <Self::Type as ObjectSubclassType>::type_();
1055        assert!(
1056            SignalId::lookup(signal_name, type_).is_some(),
1057            "Signal '{signal_name}' doesn't exists for type '{type_}'",
1058        );
1059
1060        let shortcut = crate::Shortcut::new(
1061            Some(crate::KeyvalTrigger::new(keyval, mods)),
1062            Some(crate::SignalAction::new(signal_name)),
1063        );
1064        self.add_shortcut(&shortcut);
1065    }
1066
1067    #[doc(alias = "gtk_widget_class_add_shortcut")]
1068    fn add_shortcut(&mut self, shortcut: &Shortcut) {
1069        unsafe {
1070            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1071            ffi::gtk_widget_class_add_shortcut(widget_class, shortcut.to_glib_none().0);
1072        }
1073    }
1074
1075    #[doc(alias = "gtk_widget_class_install_property_action")]
1076    fn install_property_action(&mut self, action_name: &str, property_name: &str) {
1077        unsafe {
1078            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1079            ffi::gtk_widget_class_install_property_action(
1080                widget_class,
1081                action_name.to_glib_none().0,
1082                property_name.to_glib_none().0,
1083            );
1084        }
1085    }
1086
1087    #[doc(alias = "gtk_widget_class_get_activate_signal")]
1088    #[doc(alias = "get_activate_signal")]
1089    fn activate_signal(&self) -> Option<SignalId> {
1090        unsafe {
1091            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1092            let signal_id = ffi::gtk_widget_class_get_activate_signal(widget_class);
1093            if signal_id == 0 {
1094                None
1095            } else {
1096                Some(from_glib(signal_id))
1097            }
1098        }
1099    }
1100
1101    #[doc(alias = "gtk_widget_class_set_activate_signal")]
1102    fn set_activate_signal(&mut self, signal_id: SignalId) {
1103        unsafe {
1104            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1105            ffi::gtk_widget_class_set_activate_signal(widget_class, signal_id.into_glib())
1106        }
1107    }
1108
1109    #[doc(alias = "gtk_widget_class_set_activate_signal_from_name")]
1110    fn set_activate_signal_from_name(&mut self, signal_name: &str) {
1111        let type_ = <Self::Type as ObjectSubclassType>::type_();
1112        assert!(
1113            SignalId::lookup(signal_name, type_).is_some(),
1114            "Signal '{signal_name}' doesn't exists for type '{type_}'",
1115        );
1116
1117        unsafe {
1118            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1119            ffi::gtk_widget_class_set_activate_signal_from_name(
1120                widget_class,
1121                signal_name.to_glib_none().0,
1122            );
1123        }
1124    }
1125
1126    #[doc(alias = "gtk_widget_class_set_layout_manager_type")]
1127    fn set_layout_manager_type<T: IsA<LayoutManager>>(&mut self) {
1128        unsafe {
1129            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1130            ffi::gtk_widget_class_set_layout_manager_type(
1131                widget_class,
1132                T::static_type().into_glib(),
1133            );
1134        }
1135    }
1136
1137    #[doc(alias = "gtk_widget_class_get_layout_manager_type")]
1138    #[doc(alias = "get_layout_manager_type")]
1139    fn layout_manager_type(&self) -> glib::Type {
1140        unsafe {
1141            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1142            from_glib(ffi::gtk_widget_class_get_layout_manager_type(widget_class))
1143        }
1144    }
1145
1146    #[doc(alias = "gtk_widget_class_set_css_name")]
1147    fn set_css_name(&mut self, name: &str) {
1148        unsafe {
1149            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1150            ffi::gtk_widget_class_set_css_name(widget_class, name.to_glib_none().0);
1151        }
1152    }
1153
1154    #[doc(alias = "gtk_widget_class_get_css_name")]
1155    #[doc(alias = "get_css_name")]
1156    fn css_name(&self) -> glib::GString {
1157        unsafe {
1158            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1159            from_glib_none(ffi::gtk_widget_class_get_css_name(widget_class))
1160        }
1161    }
1162
1163    #[doc(alias = "gtk_widget_class_set_accessible_role")]
1164    fn set_accessible_role(&mut self, role: AccessibleRole) {
1165        unsafe {
1166            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1167            ffi::gtk_widget_class_set_accessible_role(widget_class, role.into_glib());
1168        }
1169    }
1170
1171    #[doc(alias = "gtk_widget_class_get_accessible_role")]
1172    #[doc(alias = "get_accessible_role")]
1173    fn accessible_role(&self) -> AccessibleRole {
1174        unsafe {
1175            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1176            from_glib(ffi::gtk_widget_class_get_accessible_role(widget_class))
1177        }
1178    }
1179
1180    #[allow(clippy::missing_safety_doc)]
1181    #[doc(alias = "gtk_widget_class_bind_template_child_full")]
1182    unsafe fn bind_template_child_with_offset<T>(
1183        &mut self,
1184        name: &str,
1185        internal: bool,
1186        offset: field_offset::FieldOffset<Self::Type, TemplateChild<T>>,
1187    ) where
1188        T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1189    {
1190        let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1191        let private_offset = <Self::Type as ObjectSubclassType>::type_data()
1192            .as_ref()
1193            .impl_offset();
1194        ffi::gtk_widget_class_bind_template_child_full(
1195            widget_class,
1196            name.to_glib_none().0,
1197            internal.into_glib(),
1198            private_offset + (offset.get_byte_offset() as isize),
1199        )
1200    }
1201
1202    fn rust_template_scope(&mut self) -> BuilderRustScope {
1203        assert_initialized_main_thread!();
1204        unsafe {
1205            let mut data = <Self::Type as ObjectSubclassType>::type_data();
1206            let internal = data
1207                .as_mut()
1208                .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1209                .expect("Something bad happened at class_init, the internal class_data is missing");
1210            let scope = internal.scope.get_or_insert_with(|| {
1211                let scope = BuilderRustScope::new();
1212                self.set_template_scope(&scope);
1213                scope.into_glib_ptr()
1214            });
1215            from_glib_none(*scope)
1216        }
1217    }
1218}
1219
1220unsafe impl<T: ClassStruct> WidgetClassExt for T where T::Type: WidgetImpl {}
1221
1222#[derive(Debug, PartialEq, Eq)]
1223#[repr(transparent)]
1224pub struct TemplateChild<T>
1225where
1226    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1227{
1228    ptr: *mut <T as ObjectType>::GlibType,
1229}
1230
1231impl<T: Property> Property for TemplateChild<T>
1232where
1233    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1234{
1235    type Value = T::Value;
1236}
1237
1238impl<T> Default for TemplateChild<T>
1239where
1240    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1241{
1242    fn default() -> Self {
1243        T::static_type();
1244
1245        Self {
1246            ptr: std::ptr::null_mut(),
1247        }
1248    }
1249}
1250
1251impl<T> PropertyGet for TemplateChild<T>
1252where
1253    T: Property + ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1254{
1255    type Value = T;
1256
1257    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
1258        f(&self.get())
1259    }
1260}
1261
1262impl<T> std::ops::Deref for TemplateChild<T>
1263where
1264    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1265{
1266    type Target = T;
1267
1268    #[inline]
1269    fn deref(&self) -> &Self::Target {
1270        unsafe {
1271            if !self.is_bound() {
1272                let name = Self::name();
1273                panic!("Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute.");
1274            }
1275            &*(&self.ptr as *const _ as *const T)
1276        }
1277    }
1278}
1279
1280impl<T> Downgrade for TemplateChild<T>
1281where
1282    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType> + Downgrade,
1283{
1284    type Weak = T::Weak;
1285
1286    fn downgrade(&self) -> Self::Weak {
1287        T::downgrade(&self.get())
1288    }
1289}
1290
1291impl<T> TemplateChild<T>
1292where
1293    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1294{
1295    pub(crate) fn name<'a>() -> &'a str {
1296        T::static_type().name()
1297    }
1298
1299    #[track_caller]
1300    pub fn get(&self) -> T {
1301        self.try_get()
1302            .unwrap_or_else(|| {
1303                let name = Self::name();
1304                panic!("Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute.");
1305            })
1306    }
1307
1308    // rustdoc-stripper-ignore-next
1309    /// Determines if the child has been bound. This is primarily
1310    /// useful for implementing the [`Buildable`][`crate::Buildable`] interface.
1311    pub fn is_bound(&self) -> bool {
1312        !self.ptr.is_null()
1313    }
1314
1315    // rustdoc-stripper-ignore-next
1316    /// Returns Some(child) if the widget has been bound.
1317    pub fn try_get(&self) -> Option<T> {
1318        unsafe { Option::<T>::from_glib_none(self.ptr) }
1319    }
1320}
1321
1322// rustdoc-stripper-ignore-next
1323/// A trait for setting up template children inside
1324/// [`class_init`](glib::subclass::types::ObjectSubclass::class_init). This
1325/// trait is implemented automatically by the
1326/// [`CompositeTemplate`](crate::CompositeTemplate) macro.
1327pub trait CompositeTemplate: WidgetImpl {
1328    fn bind_template(klass: &mut Self::Class);
1329    fn check_template_children(widget: &<Self as ObjectSubclass>::Type);
1330}
1331
1332// rustdoc-stripper-ignore-next
1333/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1334/// types to allow binding a composite template directly on `self`. This is a
1335/// convenience wrapper around the [`CompositeTemplate`] trait.
1336pub trait CompositeTemplateClass {
1337    // rustdoc-stripper-ignore-next
1338    /// Binds the template callbacks from this type into the default template
1339    /// scope for `self`.
1340    fn bind_template(&mut self);
1341}
1342
1343impl<T, U> CompositeTemplateClass for T
1344where
1345    T: ClassStruct<Type = U>,
1346    U: ObjectSubclass<Class = T> + CompositeTemplate,
1347{
1348    fn bind_template(&mut self) {
1349        <U as CompositeTemplate>::bind_template(self);
1350    }
1351}
1352
1353pub type TemplateCallback = (&'static str, fn(&[glib::Value]) -> Option<glib::Value>);
1354
1355// rustdoc-stripper-ignore-next
1356/// A trait for setting up template callbacks inside
1357/// [`class_init`](glib::subclass::types::ObjectSubclass::class_init). This
1358/// trait is implemented automatically by the
1359/// [`template_callbacks`](crate::template_callbacks) macro.
1360pub trait CompositeTemplateCallbacks {
1361    const CALLBACKS: &'static [TemplateCallback];
1362
1363    // rustdoc-stripper-ignore-next
1364    /// Binds the template callbacks from this type into the default template
1365    /// scope for `klass`.
1366    fn bind_template_callbacks<T: WidgetClassExt>(klass: &mut T) {
1367        Self::add_callbacks_to_scope(&klass.rust_template_scope());
1368    }
1369    // rustdoc-stripper-ignore-next
1370    /// Binds the template callbacks from this type into the default template
1371    /// scope for `klass`, prepending `prefix` to each callback name.
1372    fn bind_template_callbacks_prefixed<T: WidgetClassExt>(klass: &mut T, prefix: &str) {
1373        Self::add_callbacks_to_scope_prefixed(&klass.rust_template_scope(), prefix);
1374    }
1375    // rustdoc-stripper-ignore-next
1376    /// Binds the template callbacks from this type into `scope`.
1377    fn add_callbacks_to_scope(scope: &BuilderRustScope) {
1378        for (name, func) in Self::CALLBACKS {
1379            scope.add_callback(*name, func);
1380        }
1381    }
1382    // rustdoc-stripper-ignore-next
1383    /// Binds the template callbacks from this type into `scope`, prepending
1384    /// `prefix` to each callback name.
1385    fn add_callbacks_to_scope_prefixed(scope: &BuilderRustScope, prefix: &str) {
1386        for (name, func) in Self::CALLBACKS {
1387            scope.add_callback(format!("{prefix}{name}"), func);
1388        }
1389    }
1390}
1391
1392// rustdoc-stripper-ignore-next
1393/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1394/// types to allow binding private template callbacks directly on `self`. This
1395/// is a convenience wrapper around the [`CompositeTemplateCallbacks`] trait.
1396pub trait CompositeTemplateCallbacksClass {
1397    // rustdoc-stripper-ignore-next
1398    /// Binds the template callbacks from the subclass type into the default
1399    /// template scope for `self`.
1400    fn bind_template_callbacks(&mut self);
1401}
1402
1403impl<T, U> CompositeTemplateCallbacksClass for T
1404where
1405    T: ClassStruct<Type = U> + WidgetClassExt,
1406    U: ObjectSubclass<Class = T> + CompositeTemplateCallbacks,
1407{
1408    fn bind_template_callbacks(&mut self) {
1409        <U as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1410    }
1411}
1412
1413// rustdoc-stripper-ignore-next
1414/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1415/// types to allow binding the instance template callbacks directly on `self`.
1416/// This is a convenience wrapper around the [`CompositeTemplateCallbacks`]
1417/// trait.
1418pub trait CompositeTemplateInstanceCallbacksClass {
1419    // rustdoc-stripper-ignore-next
1420    /// Binds the template callbacks from the instance type into the default
1421    /// template scope for `self`.
1422    fn bind_template_instance_callbacks(&mut self);
1423}
1424
1425impl<T, U, V> CompositeTemplateInstanceCallbacksClass for T
1426where
1427    T: ClassStruct<Type = U> + WidgetClassExt,
1428    U: ObjectSubclass<Class = T, Type = V>,
1429    V: CompositeTemplateCallbacks,
1430{
1431    fn bind_template_instance_callbacks(&mut self) {
1432        <V as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1433    }
1434}
1435
1436pub trait CompositeTemplateInitializingExt {
1437    fn init_template(&self);
1438}
1439
1440impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateInitializingExt
1441    for glib::subclass::InitializingObject<T>
1442{
1443    fn init_template(&self) {
1444        unsafe {
1445            let widget = self
1446                .as_ref()
1447                .unsafe_cast_ref::<<T as ObjectSubclass>::Type>();
1448            ffi::gtk_widget_init_template(AsRef::<Widget>::as_ref(widget).to_glib_none().0);
1449
1450            <T as CompositeTemplate>::check_template_children(widget);
1451        }
1452    }
1453}
1454
1455pub trait CompositeTemplateDisposeExt {
1456    #[cfg(feature = "v4_8")]
1457    #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1458    fn dispose_template(&self);
1459}
1460
1461impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateDisposeExt for T {
1462    #[cfg(feature = "v4_8")]
1463    #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1464    fn dispose_template(&self) {
1465        unsafe {
1466            ffi::gtk_widget_dispose_template(
1467                self.obj().upcast_ref::<Widget>().to_glib_none().0,
1468                <T as ObjectSubclass>::Type::static_type().into_glib(),
1469            );
1470        }
1471    }
1472}