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