Skip to main content

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    GString, Variant,
10    clone::Downgrade,
11    property::{Property, PropertyGet},
12    subclass::SignalId,
13    translate::*,
14};
15
16use crate::{
17    AccessibleRole, Buildable, BuilderRustScope, BuilderScope, ConstraintTarget, DirectionType,
18    LayoutManager, Orientation, Shortcut, SizeRequestMode, Snapshot, StateFlags, SystemSetting,
19    TextDirection, Tooltip, Widget, ffi, prelude::*, subclass::prelude::*,
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
32impl WidgetActionIter {
33    pub(crate) fn new(widget_class: *mut ffi::GtkWidgetClass) -> Self {
34        Self(widget_class, 0)
35    }
36}
37
38pub struct WidgetAction(
39    glib::Type,
40    GString,
41    Option<glib::VariantType>,
42    Option<GString>,
43);
44
45impl WidgetAction {
46    // rustdoc-stripper-ignore-next
47    /// The type where the action was defined
48    pub fn owner(&self) -> glib::Type {
49        self.0
50    }
51
52    // rustdoc-stripper-ignore-next
53    /// The action name
54    pub fn name(&self) -> &str {
55        self.1.as_ref()
56    }
57
58    // rustdoc-stripper-ignore-next
59    /// The action parameter type
60    pub fn parameter_type(&self) -> Option<&glib::VariantType> {
61        self.2.as_ref()
62    }
63
64    // rustdoc-stripper-ignore-next
65    /// The action property name
66    pub fn property_name(&self) -> Option<&str> {
67        self.3.as_ref().map(|s| s.as_ref())
68    }
69}
70
71impl fmt::Debug for WidgetAction {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        f.debug_struct("WidgetAction")
74            .field("owner", &self.owner())
75            .field("name", &self.name())
76            .field("parameter_type", &self.parameter_type())
77            .field("property_name", &self.property_name())
78            .finish()
79    }
80}
81
82impl Iterator for WidgetActionIter {
83    type Item = WidgetAction;
84
85    fn next(&mut self) -> Option<Self::Item> {
86        unsafe {
87            let mut owner = std::mem::MaybeUninit::uninit();
88            let mut action_name_ptr = std::ptr::null();
89            let mut parameter_type = std::ptr::null();
90            let mut property_name_ptr = std::ptr::null();
91            let found: bool = from_glib(ffi::gtk_widget_class_query_action(
92                self.0,
93                self.1,
94                owner.as_mut_ptr(),
95                &mut action_name_ptr,
96                &mut parameter_type,
97                &mut property_name_ptr,
98            ));
99            if found {
100                self.1 += 1;
101                let property_name: Option<GString> = from_glib_none(property_name_ptr);
102                let action_name: GString = from_glib_none(action_name_ptr);
103
104                Some(WidgetAction(
105                    from_glib(owner.assume_init()),
106                    action_name,
107                    from_glib_none(parameter_type),
108                    property_name,
109                ))
110            } else {
111                None
112            }
113        }
114    }
115}
116
117impl std::iter::FusedIterator for WidgetActionIter {}
118
119#[cfg(feature = "v4_10")]
120#[doc(hidden)]
121pub trait WidgetImplBounds:
122    IsA<Widget> + IsA<crate::Accessible> + IsA<Buildable> + IsA<ConstraintTarget>
123{
124}
125#[cfg(feature = "v4_10")]
126impl<T: IsA<Widget> + IsA<crate::Accessible> + IsA<Buildable> + IsA<ConstraintTarget>>
127    WidgetImplBounds for T
128{
129}
130
131#[cfg(not(feature = "v4_10"))]
132#[doc(hidden)]
133pub trait WidgetImplBounds: IsA<Widget> + IsA<Buildable> + IsA<ConstraintTarget> {}
134#[cfg(not(feature = "v4_10"))]
135impl<T: IsA<Widget> + IsA<Buildable> + IsA<ConstraintTarget>> WidgetImplBounds for T {}
136
137pub trait WidgetImpl: ObjectImpl + ObjectSubclass<Type: WidgetImplBounds> {
138    /// Computes whether a container should give this
139    ///   widget extra space when possible.
140    fn compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
141        self.parent_compute_expand(hexpand, vexpand)
142    }
143
144    /// Tests if a given point is contained in the widget.
145    ///
146    /// The coordinates for (x, y) must be in widget coordinates, so
147    /// (0, 0) is assumed to be the top left of @self's content area.
148    /// ## `x`
149    /// X coordinate to test, relative to @self's origin
150    /// ## `y`
151    /// Y coordinate to test, relative to @self's origin
152    ///
153    /// # Returns
154    ///
155    /// true if @self contains the point (x, y)
156    fn contains(&self, x: f64, y: f64) -> bool {
157        self.parent_contains(x, y)
158    }
159
160    /// Signal emitted when the text direction of a
161    ///   widget changes.
162    fn direction_changed(&self, previous_direction: TextDirection) {
163        self.parent_direction_changed(previous_direction)
164    }
165
166    /// Vfunc for gtk_widget_child_focus()
167    fn focus(&self, direction_type: DirectionType) -> bool {
168        self.parent_focus(direction_type)
169    }
170
171    /// Gets whether the widget prefers a height-for-width layout
172    /// or a width-for-height layout.
173    ///
174    /// Single-child widgets generally propagate the preference of
175    /// their child, more complex widgets need to request something
176    /// either in context of their children or in context of their
177    /// allocation capabilities.
178    ///
179    /// # Returns
180    ///
181    /// The [`SizeRequestMode`][crate::SizeRequestMode] preferred by @self.
182    #[doc(alias = "get_request_mode")]
183    fn request_mode(&self) -> SizeRequestMode {
184        self.parent_request_mode()
185    }
186
187    /// Causes @self to have the keyboard focus for the window
188    /// that it belongs to.
189    ///
190    /// If @self is not focusable, or its [`WidgetImpl::grab_focus()`][crate::subclass::prelude::WidgetImpl::grab_focus()]
191    /// implementation cannot transfer the focus to a descendant of @self
192    /// that is focusable, it will not take focus and false will be returned.
193    ///
194    /// Calling [`WidgetExt::grab_focus()`][crate::prelude::WidgetExt::grab_focus()] on an already focused widget
195    /// is allowed, should not have an effect, and return true.
196    ///
197    /// # Returns
198    ///
199    /// true if focus is now inside @self
200    fn grab_focus(&self) -> bool {
201        self.parent_grab_focus()
202    }
203
204    /// Reverses the effects of [method.Gtk.Widget.show].
205    ///
206    /// This is causing the widget to be hidden (invisible to the user).
207    ///
208    /// # Deprecated since 4.10
209    ///
210    /// Use [`WidgetExt::set_visible()`][crate::prelude::WidgetExt::set_visible()] instead
211    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
212    #[allow(deprecated)]
213    fn hide(&self) {
214        self.parent_hide()
215    }
216
217    /// Emits the [`keynav-failed`][struct@crate::Widget#keynav-failed] signal on the widget.
218    ///
219    /// This function should be called whenever keyboard navigation
220    /// within a single widget hits a boundary.
221    ///
222    /// The return value of this function should be interpreted
223    /// in a way similar to the return value of
224    /// [`WidgetExt::child_focus()`][crate::prelude::WidgetExt::child_focus()]. When true is returned,
225    /// stay in the widget, the failed keyboard navigation is ok
226    /// and/or there is nowhere we can/should move the focus to.
227    /// When false is returned, the caller should continue with
228    /// keyboard navigation outside the widget, e.g. by calling
229    /// [`WidgetExt::child_focus()`][crate::prelude::WidgetExt::child_focus()] on the widget’s toplevel.
230    ///
231    /// The default [`keynav-failed`][struct@crate::Widget#keynav-failed] handler returns
232    /// false for [enum@Gtk.DirectionType.tab-forward] and
233    /// [enum@Gtk.DirectionType.tab-backward]. For the other values
234    /// of [`DirectionType`][crate::DirectionType] it returns true.
235    ///
236    /// Whenever the default handler returns true, it also calls
237    /// [`WidgetExt::error_bell()`][crate::prelude::WidgetExt::error_bell()] to notify the user of the
238    /// failed keyboard navigation.
239    ///
240    /// A use case for providing an own implementation of `::keynav-failed`
241    /// (either by connecting to it or by overriding it) would be a row of
242    /// [`Entry`][crate::Entry] widgets where the user should be able to navigate
243    /// the entire row with the cursor keys, as e.g. known from user
244    /// interfaces that require entering license keys.
245    /// ## `direction`
246    /// direction of focus movement
247    ///
248    /// # Returns
249    ///
250    /// true if stopping keyboard navigation is fine, false
251    ///   if the emitting widget should try to handle the keyboard
252    ///   navigation attempt in its parent widget
253    fn keynav_failed(&self, direction_type: DirectionType) -> bool {
254        self.parent_keynav_failed(direction_type)
255    }
256
257    /// Causes a widget to be mapped if it isn’t already.
258    ///
259    /// This function is only for use in widget implementations.
260    fn map(&self) {
261        self.parent_map()
262    }
263
264    /// Measures @self in the orientation @orientation and for the given @for_size.
265    ///
266    /// As an example, if @orientation is [`Orientation::Horizontal`][crate::Orientation::Horizontal] and @for_size
267    /// is 300, this functions will compute the minimum and natural width of @self
268    /// if it is allocated at a height of 300 pixels.
269    ///
270    /// See [GtkWidget’s geometry management section](class.Widget.html#height-for-width-geometry-management) for
271    /// a more details on implementing `GtkWidgetClass.measure()`.
272    /// ## `orientation`
273    /// the orientation to measure
274    /// ## `for_size`
275    /// Size for the opposite of @orientation, i.e.
276    ///   if @orientation is [`Orientation::Horizontal`][crate::Orientation::Horizontal], this is
277    ///   the height the widget should be measured with. The [`Orientation::Vertical`][crate::Orientation::Vertical]
278    ///   case is analogous. This way, both height-for-width and width-for-height
279    ///   requests can be implemented. If no size is known, -1 can be passed.
280    ///
281    /// # Returns
282    ///
283    ///
284    /// ## `minimum`
285    /// location to store the minimum size
286    ///
287    /// ## `natural`
288    /// location to store the natural size
289    ///
290    /// ## `minimum_baseline`
291    /// location to store the baseline
292    ///   position for the minimum size, or -1 to report no baseline
293    ///
294    /// ## `natural_baseline`
295    /// location to store the baseline
296    ///   position for the natural size, or -1 to report no baseline
297    fn measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
298        self.parent_measure(orientation, for_size)
299    }
300
301    /// Emits the [`mnemonic-activate`][struct@crate::Widget#mnemonic-activate] signal.
302    /// ## `group_cycling`
303    /// true if there are other widgets with the same mnemonic
304    ///
305    /// # Returns
306    ///
307    /// true if the signal has been handled
308    fn mnemonic_activate(&self, group_cycling: bool) -> bool {
309        self.parent_mnemonic_activate(group_cycling)
310    }
311
312    /// Signal emitted when a change of focus is requested
313    fn move_focus(&self, direction_type: DirectionType) {
314        self.parent_move_focus(direction_type)
315    }
316
317    /// Signal emitted when “has-tooltip” is [`true`] and the
318    ///   hover timeout has expired with the cursor hovering “above”
319    ///   widget; or emitted when widget got focus in keyboard mode.
320    fn query_tooltip(&self, x: i32, y: i32, keyboard_tooltip: bool, tooltip: &Tooltip) -> bool {
321        self.parent_query_tooltip(x, y, keyboard_tooltip, tooltip)
322    }
323
324    /// Creates the GDK resources associated with a widget.
325    ///
326    /// Normally realization happens implicitly; if you show a widget
327    /// and all its parent containers, then the widget will be realized
328    /// and mapped automatically.
329    ///
330    /// Realizing a widget requires all the widget’s parent widgets to be
331    /// realized; calling this function realizes the widget’s parents
332    /// in addition to @self itself. If a widget is not yet inside a
333    /// toplevel window when you realize it, bad things will happen.
334    ///
335    /// This function is primarily used in widget implementations, and
336    /// isn’t very useful otherwise. Many times when you think you might
337    /// need it, a better approach is to connect to a signal that will be
338    /// called after the widget is realized automatically, such as
339    /// [`realize`][struct@crate::Widget#realize].
340    fn realize(&self) {
341        self.parent_realize()
342    }
343
344    /// Called when the widget gets added to a [`Root`][crate::Root] widget. Must
345    ///   chain up
346    fn root(&self) {
347        self.parent_root()
348    }
349
350    /// Set the focus child of the widget.
351    ///
352    /// This function is only suitable for widget implementations.
353    /// If you want a certain widget to get the input focus, call
354    /// [`WidgetExt::grab_focus()`][crate::prelude::WidgetExt::grab_focus()] on it.
355    /// ## `child`
356    /// a direct child widget of @self
357    ///   or `NULL` to unset the focus child
358    fn set_focus_child(&self, child: Option<&Widget>) {
359        self.parent_set_focus_child(child)
360    }
361
362    /// Flags a widget to be displayed.
363    ///
364    /// Any widget that isn’t shown will not appear on the screen.
365    ///
366    /// Remember that you have to show the containers containing a widget,
367    /// in addition to the widget itself, before it will appear onscreen.
368    ///
369    /// When a toplevel widget is shown, it is immediately realized and
370    /// mapped; other shown widgets are realized and mapped when their
371    /// toplevel widget is realized and mapped.
372    ///
373    /// # Deprecated since 4.10
374    ///
375    /// Use [`WidgetExt::set_visible()`][crate::prelude::WidgetExt::set_visible()] instead
376    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
377    #[allow(deprecated)]
378    fn show(&self) {
379        self.parent_show()
380    }
381
382    /// Called to set the allocation, if the widget does
383    ///   not have a layout manager.
384    fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
385        self.parent_size_allocate(width, height, baseline)
386    }
387
388    /// Vfunc called when a new snapshot of the widget has to be taken.
389    fn snapshot(&self, snapshot: &Snapshot) {
390        self.parent_snapshot(snapshot)
391    }
392
393    /// Signal emitted when the widget state changes,
394    ///   see gtk_widget_get_state_flags().
395    fn state_flags_changed(&self, state_flags: &StateFlags) {
396        self.parent_state_flags_changed(state_flags)
397    }
398
399    /// Emitted when a system setting was changed. Must chain up.
400    fn system_setting_changed(&self, settings: &SystemSetting) {
401        self.parent_system_setting_changed(settings)
402    }
403
404    /// Causes a widget to be unmapped if it’s currently mapped.
405    ///
406    /// This function is only for use in widget implementations.
407    fn unmap(&self) {
408        self.parent_unmap()
409    }
410
411    /// Causes a widget to be unrealized.
412    ///
413    /// This frees all GDK resources associated with the widget.
414    ///
415    /// This function is only useful in widget implementations.
416    fn unrealize(&self) {
417        self.parent_unrealize()
418    }
419
420    /// Called when the widget is about to be removed from its
421    ///   [`Root`][crate::Root] widget. Must chain up
422    fn unroot(&self) {
423        self.parent_unroot()
424    }
425}
426
427pub trait WidgetImplExt: WidgetImpl {
428    fn parent_compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
429        unsafe {
430            let data = Self::type_data();
431            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
432            if let Some(f) = (*parent_class).compute_expand {
433                let mut hexpand_glib = hexpand.into_glib();
434                let mut vexpand_glib = vexpand.into_glib();
435                f(
436                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
437                    &mut hexpand_glib,
438                    &mut vexpand_glib,
439                );
440                *hexpand = from_glib(hexpand_glib);
441                *vexpand = from_glib(vexpand_glib);
442            }
443        }
444    }
445
446    // true if the widget contains (x, y)
447    fn parent_contains(&self, x: f64, y: f64) -> bool {
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).contains {
452                from_glib(f(
453                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
454                    x,
455                    y,
456                ))
457            } else {
458                false
459            }
460        }
461    }
462
463    fn parent_direction_changed(&self, previous_direction: TextDirection) {
464        unsafe {
465            let data = Self::type_data();
466            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
467            if let Some(f) = (*parent_class).direction_changed {
468                f(
469                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
470                    previous_direction.into_glib(),
471                )
472            }
473        }
474    }
475
476    // Returns true if focus ended up inside widget
477    fn parent_focus(&self, direction_type: DirectionType) -> bool {
478        unsafe {
479            let data = Self::type_data();
480            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
481            if let Some(f) = (*parent_class).focus {
482                from_glib(f(
483                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
484                    direction_type.into_glib(),
485                ))
486            } else {
487                false
488            }
489        }
490    }
491
492    fn parent_request_mode(&self) -> SizeRequestMode {
493        unsafe {
494            let data = Self::type_data();
495            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
496            let f = (*parent_class)
497                .get_request_mode
498                .expect("No parent class impl for \"get_request_mode\"");
499            from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
500        }
501    }
502
503    // Returns true if focus ended up inside widget
504    fn parent_grab_focus(&self) -> bool {
505        unsafe {
506            let data = Self::type_data();
507            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
508            if let Some(f) = (*parent_class).grab_focus {
509                from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
510            } else {
511                false
512            }
513        }
514    }
515
516    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
517    #[allow(deprecated)]
518    fn parent_hide(&self) {
519        unsafe {
520            let data = Self::type_data();
521            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
522            if let Some(f) = (*parent_class).hide {
523                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
524            }
525        }
526    }
527
528    // TRUE if stopping keyboard navigation is fine,
529    // FALSE if the emitting widget should try to handle the keyboard navigation
530    // attempt in its parent container(s).
531    fn parent_keynav_failed(&self, direction_type: DirectionType) -> bool {
532        unsafe {
533            let data = Self::type_data();
534            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
535            if let Some(f) = (*parent_class).keynav_failed {
536                from_glib(f(
537                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
538                    direction_type.into_glib(),
539                ))
540            } else {
541                false
542            }
543        }
544    }
545
546    fn parent_map(&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).map {
551                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
552            }
553        }
554    }
555
556    fn parent_measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
557        unsafe {
558            let data = Self::type_data();
559            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
560
561            let f = (*parent_class)
562                .measure
563                .expect("No parent class impl for \"measure\"");
564
565            let mut min = 0;
566            let mut nat = 0;
567            let mut min_base = -1;
568            let mut nat_base = -1;
569            f(
570                self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
571                orientation.into_glib(),
572                for_size,
573                &mut min,
574                &mut nat,
575                &mut min_base,
576                &mut nat_base,
577            );
578            (min, nat, min_base, nat_base)
579        }
580    }
581
582    // True if the signal has been handled
583    fn parent_mnemonic_activate(&self, group_cycling: bool) -> bool {
584        unsafe {
585            let data = Self::type_data();
586            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
587            if let Some(f) = (*parent_class).mnemonic_activate {
588                from_glib(f(
589                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
590                    group_cycling.into_glib(),
591                ))
592            } else {
593                false
594            }
595        }
596    }
597
598    fn parent_move_focus(&self, direction_type: DirectionType) {
599        unsafe {
600            let data = Self::type_data();
601            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
602            if let Some(f) = (*parent_class).move_focus {
603                f(
604                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
605                    direction_type.into_glib(),
606                )
607            }
608        }
609    }
610
611    fn parent_query_tooltip(
612        &self,
613        x: i32,
614        y: i32,
615        keyboard_tooltip: bool,
616        tooltip: &Tooltip,
617    ) -> bool {
618        unsafe {
619            let data = Self::type_data();
620            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
621            if let Some(f) = (*parent_class).query_tooltip {
622                from_glib(f(
623                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
624                    x,
625                    y,
626                    keyboard_tooltip.into_glib(),
627                    tooltip.to_glib_none().0,
628                ))
629            } else {
630                false
631            }
632        }
633    }
634
635    fn parent_realize(&self) {
636        unsafe {
637            let data = Self::type_data();
638            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
639            if let Some(f) = (*parent_class).realize {
640                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
641            }
642        }
643    }
644
645    fn parent_root(&self) {
646        unsafe {
647            let data = Self::type_data();
648            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
649            if let Some(f) = (*parent_class).root {
650                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
651            }
652        }
653    }
654
655    fn parent_set_focus_child(&self, child: Option<&Widget>) {
656        unsafe {
657            let data = Self::type_data();
658            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
659            if let Some(f) = (*parent_class).set_focus_child {
660                f(
661                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
662                    child.to_glib_none().0,
663                )
664            }
665        }
666    }
667
668    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
669    #[allow(deprecated)]
670    fn parent_show(&self) {
671        unsafe {
672            let data = Self::type_data();
673            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
674            if let Some(f) = (*parent_class).show {
675                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
676            }
677        }
678    }
679
680    fn parent_size_allocate(&self, width: i32, height: i32, baseline: i32) {
681        unsafe {
682            let data = Self::type_data();
683            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
684            if let Some(f) = (*parent_class).size_allocate {
685                f(
686                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
687                    width,
688                    height,
689                    baseline,
690                )
691            }
692        }
693    }
694
695    fn parent_snapshot(&self, snapshot: &Snapshot) {
696        unsafe {
697            let data = Self::type_data();
698            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
699            if let Some(f) = (*parent_class).snapshot {
700                f(
701                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
702                    snapshot.to_glib_none().0,
703                )
704            }
705        }
706    }
707
708    fn parent_state_flags_changed(&self, state_flags: &StateFlags) {
709        unsafe {
710            let data = Self::type_data();
711            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
712            if let Some(f) = (*parent_class).state_flags_changed {
713                f(
714                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
715                    state_flags.into_glib(),
716                )
717            }
718        }
719    }
720
721    fn parent_system_setting_changed(&self, settings: &SystemSetting) {
722        unsafe {
723            let data = Self::type_data();
724            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
725            if let Some(f) = (*parent_class).system_setting_changed {
726                f(
727                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
728                    settings.into_glib(),
729                )
730            }
731        }
732    }
733
734    fn parent_unmap(&self) {
735        unsafe {
736            let data = Self::type_data();
737            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
738            if let Some(f) = (*parent_class).unmap {
739                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
740            }
741        }
742    }
743
744    fn parent_unrealize(&self) {
745        unsafe {
746            let data = Self::type_data();
747            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
748            if let Some(f) = (*parent_class).unrealize {
749                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
750            }
751        }
752    }
753
754    fn parent_unroot(&self) {
755        unsafe {
756            let data = Self::type_data();
757            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
758            if let Some(f) = (*parent_class).unroot {
759                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
760            }
761        }
762    }
763}
764
765impl<T: WidgetImpl> WidgetImplExt for T {}
766
767unsafe impl<T: WidgetImpl> IsSubclassable<T> for Widget {
768    fn class_init(class: &mut ::glib::Class<Self>) {
769        Self::parent_class_init::<T>(class);
770
771        assert_initialized_main_thread!();
772
773        let klass = class.as_mut();
774        unsafe {
775            let mut data = T::type_data();
776            let data = data.as_mut();
777            // Used to store actions for `install_action` and `rust_builder_scope`
778            data.set_class_data(<T as ObjectSubclassType>::type_(), Internal::default());
779        }
780
781        klass.compute_expand = Some(widget_compute_expand::<T>);
782        klass.contains = Some(widget_contains::<T>);
783        klass.direction_changed = Some(widget_direction_changed::<T>);
784        klass.focus = Some(widget_focus::<T>);
785        klass.get_request_mode = Some(widget_get_request_mode::<T>);
786        klass.grab_focus = Some(widget_grab_focus::<T>);
787        klass.hide = Some(widget_hide::<T>);
788        klass.keynav_failed = Some(widget_keynav_failed::<T>);
789        klass.map = Some(widget_map::<T>);
790        klass.measure = Some(widget_measure::<T>);
791        klass.mnemonic_activate = Some(widget_mnemonic_activate::<T>);
792        klass.move_focus = Some(widget_move_focus::<T>);
793        klass.query_tooltip = Some(widget_query_tooltip::<T>);
794        klass.realize = Some(widget_realize::<T>);
795        klass.root = Some(widget_root::<T>);
796        klass.set_focus_child = Some(widget_set_focus_child::<T>);
797        klass.show = Some(widget_show::<T>);
798        klass.size_allocate = Some(widget_size_allocate::<T>);
799        klass.snapshot = Some(widget_snapshot::<T>);
800        klass.state_flags_changed = Some(widget_state_flags_changed::<T>);
801        klass.system_setting_changed = Some(widget_system_setting_changed::<T>);
802        klass.unmap = Some(widget_unmap::<T>);
803        klass.unrealize = Some(widget_unrealize::<T>);
804        klass.unroot = Some(widget_unroot::<T>);
805    }
806}
807
808unsafe extern "C" fn widget_compute_expand<T: WidgetImpl>(
809    ptr: *mut ffi::GtkWidget,
810    hexpand_ptr: *mut glib::ffi::gboolean,
811    vexpand_ptr: *mut glib::ffi::gboolean,
812) {
813    unsafe {
814        let instance = &*(ptr as *mut T::Instance);
815        let imp = instance.imp();
816
817        let widget = imp.obj();
818        let widget = widget.unsafe_cast_ref::<Widget>();
819        let mut hexpand: bool = if widget.is_hexpand_set() {
820            widget.hexpands()
821        } else {
822            from_glib(*hexpand_ptr)
823        };
824        let mut vexpand: bool = if widget.is_vexpand_set() {
825            widget.vexpands()
826        } else {
827            from_glib(*vexpand_ptr)
828        };
829
830        imp.compute_expand(&mut hexpand, &mut vexpand);
831
832        *hexpand_ptr = hexpand.into_glib();
833        *vexpand_ptr = vexpand.into_glib();
834    }
835}
836
837unsafe extern "C" fn widget_contains<T: WidgetImpl>(
838    ptr: *mut ffi::GtkWidget,
839    x: f64,
840    y: f64,
841) -> glib::ffi::gboolean {
842    unsafe {
843        let instance = &*(ptr as *mut T::Instance);
844        let imp = instance.imp();
845
846        imp.contains(x, y).into_glib()
847    }
848}
849
850unsafe extern "C" fn widget_direction_changed<T: WidgetImpl>(
851    ptr: *mut ffi::GtkWidget,
852    direction_ptr: ffi::GtkTextDirection,
853) {
854    unsafe {
855        let instance = &*(ptr as *mut T::Instance);
856        let imp = instance.imp();
857        let direction_wrap = from_glib(direction_ptr);
858
859        imp.direction_changed(direction_wrap)
860    }
861}
862
863unsafe extern "C" fn widget_focus<T: WidgetImpl>(
864    ptr: *mut ffi::GtkWidget,
865    direction_type_ptr: ffi::GtkDirectionType,
866) -> glib::ffi::gboolean {
867    unsafe {
868        let instance = &*(ptr as *mut T::Instance);
869        let imp = instance.imp();
870        let direction_type = from_glib(direction_type_ptr);
871
872        imp.focus(direction_type).into_glib()
873    }
874}
875
876unsafe extern "C" fn widget_get_request_mode<T: WidgetImpl>(
877    ptr: *mut ffi::GtkWidget,
878) -> ffi::GtkSizeRequestMode {
879    unsafe {
880        let instance = &*(ptr as *mut T::Instance);
881        let imp = instance.imp();
882
883        imp.request_mode().into_glib()
884    }
885}
886
887unsafe extern "C" fn widget_grab_focus<T: WidgetImpl>(
888    ptr: *mut ffi::GtkWidget,
889) -> glib::ffi::gboolean {
890    unsafe {
891        let instance = &*(ptr as *mut T::Instance);
892        let imp = instance.imp();
893
894        imp.grab_focus().into_glib()
895    }
896}
897
898unsafe extern "C" fn widget_hide<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
899    unsafe {
900        let instance = &*(ptr as *mut T::Instance);
901        let imp = instance.imp();
902
903        imp.hide()
904    }
905}
906
907unsafe extern "C" fn widget_keynav_failed<T: WidgetImpl>(
908    ptr: *mut ffi::GtkWidget,
909    direction_type_ptr: ffi::GtkDirectionType,
910) -> glib::ffi::gboolean {
911    unsafe {
912        let instance = &*(ptr as *mut T::Instance);
913        let imp = instance.imp();
914        let direction_type = from_glib(direction_type_ptr);
915
916        imp.keynav_failed(direction_type).into_glib()
917    }
918}
919
920unsafe extern "C" fn widget_map<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
921    unsafe {
922        let instance = &*(ptr as *mut T::Instance);
923        let imp = instance.imp();
924
925        imp.map()
926    }
927}
928
929unsafe extern "C" fn widget_measure<T: WidgetImpl>(
930    ptr: *mut ffi::GtkWidget,
931    orientation_ptr: ffi::GtkOrientation,
932    for_size: i32,
933    min_ptr: *mut libc::c_int,
934    nat_ptr: *mut libc::c_int,
935    min_base_ptr: *mut libc::c_int,
936    nat_base_ptr: *mut libc::c_int,
937) {
938    unsafe {
939        let instance = &*(ptr as *mut T::Instance);
940        let imp = instance.imp();
941        let orientation = from_glib(orientation_ptr);
942        let (min, nat, min_base, nat_base) = imp.measure(orientation, for_size);
943        if !min_ptr.is_null() {
944            *min_ptr = min;
945        }
946        if !nat_ptr.is_null() {
947            *nat_ptr = nat;
948        }
949        if !min_base_ptr.is_null() {
950            *min_base_ptr = min_base;
951        }
952        if !nat_base_ptr.is_null() {
953            *nat_base_ptr = nat_base;
954        }
955    }
956}
957
958unsafe extern "C" fn widget_mnemonic_activate<T: WidgetImpl>(
959    ptr: *mut ffi::GtkWidget,
960    group_cycling_ptr: glib::ffi::gboolean,
961) -> glib::ffi::gboolean {
962    unsafe {
963        let instance = &*(ptr as *mut T::Instance);
964        let imp = instance.imp();
965        let group_cycling: bool = from_glib(group_cycling_ptr);
966
967        imp.mnemonic_activate(group_cycling).into_glib()
968    }
969}
970
971unsafe extern "C" fn widget_move_focus<T: WidgetImpl>(
972    ptr: *mut ffi::GtkWidget,
973    direction_type_ptr: ffi::GtkDirectionType,
974) {
975    unsafe {
976        let instance = &*(ptr as *mut T::Instance);
977        let imp = instance.imp();
978        let direction_type = from_glib(direction_type_ptr);
979
980        imp.move_focus(direction_type)
981    }
982}
983
984unsafe extern "C" fn widget_query_tooltip<T: WidgetImpl>(
985    ptr: *mut ffi::GtkWidget,
986    x: i32,
987    y: i32,
988    keyboard_tooltip_ptr: glib::ffi::gboolean,
989    tooltip_ptr: *mut ffi::GtkTooltip,
990) -> glib::ffi::gboolean {
991    unsafe {
992        let instance = &*(ptr as *mut T::Instance);
993        let imp = instance.imp();
994
995        let keyboard_tooltip: bool = from_glib(keyboard_tooltip_ptr);
996        let tooltip = from_glib_borrow(tooltip_ptr);
997
998        imp.query_tooltip(x, y, keyboard_tooltip, &tooltip)
999            .into_glib()
1000    }
1001}
1002
1003unsafe extern "C" fn widget_realize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1004    unsafe {
1005        let instance = &*(ptr as *mut T::Instance);
1006        let imp = instance.imp();
1007
1008        imp.realize()
1009    }
1010}
1011
1012unsafe extern "C" fn widget_root<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1013    unsafe {
1014        let instance = &*(ptr as *mut T::Instance);
1015        let imp = instance.imp();
1016
1017        imp.root()
1018    }
1019}
1020
1021unsafe extern "C" fn widget_set_focus_child<T: WidgetImpl>(
1022    ptr: *mut ffi::GtkWidget,
1023    child_ptr: *mut ffi::GtkWidget,
1024) {
1025    unsafe {
1026        let instance = &*(ptr as *mut T::Instance);
1027        let imp = instance.imp();
1028        let child: Borrowed<Option<Widget>> = from_glib_borrow(child_ptr);
1029
1030        imp.set_focus_child(child.as_ref().as_ref())
1031    }
1032}
1033
1034unsafe extern "C" fn widget_show<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1035    unsafe {
1036        let instance = &*(ptr as *mut T::Instance);
1037        let imp = instance.imp();
1038
1039        imp.show()
1040    }
1041}
1042
1043unsafe extern "C" fn widget_size_allocate<T: WidgetImpl>(
1044    ptr: *mut ffi::GtkWidget,
1045    width: i32,
1046    height: i32,
1047    baseline: i32,
1048) {
1049    unsafe {
1050        let instance = &*(ptr as *mut T::Instance);
1051        let imp = instance.imp();
1052
1053        imp.size_allocate(width, height, baseline)
1054    }
1055}
1056
1057unsafe extern "C" fn widget_snapshot<T: WidgetImpl>(
1058    ptr: *mut ffi::GtkWidget,
1059    snapshot_ptr: *mut ffi::GtkSnapshot,
1060) {
1061    unsafe {
1062        let instance = &*(ptr as *mut T::Instance);
1063        let imp = instance.imp();
1064        let snapshot = from_glib_borrow(snapshot_ptr);
1065
1066        imp.snapshot(&snapshot)
1067    }
1068}
1069
1070unsafe extern "C" fn widget_state_flags_changed<T: WidgetImpl>(
1071    ptr: *mut ffi::GtkWidget,
1072    state_flags_ptr: ffi::GtkStateFlags,
1073) {
1074    unsafe {
1075        let instance = &*(ptr as *mut T::Instance);
1076        let imp = instance.imp();
1077        let state_flags = from_glib(state_flags_ptr);
1078
1079        imp.state_flags_changed(&state_flags)
1080    }
1081}
1082
1083unsafe extern "C" fn widget_system_setting_changed<T: WidgetImpl>(
1084    ptr: *mut ffi::GtkWidget,
1085    settings_ptr: ffi::GtkSystemSetting,
1086) {
1087    unsafe {
1088        let instance = &*(ptr as *mut T::Instance);
1089        let imp = instance.imp();
1090        let settings = from_glib(settings_ptr);
1091
1092        imp.system_setting_changed(&settings)
1093    }
1094}
1095
1096unsafe extern "C" fn widget_unmap<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1097    unsafe {
1098        let instance = &*(ptr as *mut T::Instance);
1099        let imp = instance.imp();
1100
1101        imp.unmap()
1102    }
1103}
1104
1105unsafe extern "C" fn widget_unrealize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1106    unsafe {
1107        let instance = &*(ptr as *mut T::Instance);
1108        let imp = instance.imp();
1109
1110        imp.unrealize()
1111    }
1112}
1113
1114unsafe extern "C" fn widget_unroot<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1115    unsafe {
1116        let instance = &*(ptr as *mut T::Instance);
1117        let imp = instance.imp();
1118
1119        imp.unroot()
1120    }
1121}
1122
1123#[allow(clippy::missing_safety_doc)]
1124pub unsafe trait WidgetClassExt: ClassStruct {
1125    #[doc(alias = "gtk_widget_class_set_template")]
1126    fn set_template_bytes(&mut self, template: &glib::Bytes) {
1127        unsafe {
1128            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1129            ffi::gtk_widget_class_set_template(widget_class, template.to_glib_none().0);
1130        }
1131    }
1132
1133    /// This should be called at class initialization time to specify
1134    /// the [`Builder`][crate::Builder] XML to be used to extend a widget.
1135    ///
1136    /// For convenience, [`set_template_from_resource()`][Self::set_template_from_resource()]
1137    /// is also provided.
1138    ///
1139    /// Note that any class that installs templates must call
1140    /// `Gtk::Widget::init_template()` in the widget’s instance initializer.
1141    /// ## `template_bytes`
1142    /// `GBytes` holding the [`Builder`][crate::Builder] XML
1143    fn set_template(&mut self, template: &[u8]) {
1144        let template_bytes = glib::Bytes::from(template);
1145        self.set_template_bytes(&template_bytes);
1146    }
1147
1148    fn set_template_static(&mut self, template: &'static [u8]) {
1149        let template_bytes = glib::Bytes::from_static(template);
1150        self.set_template_bytes(&template_bytes);
1151    }
1152
1153    /// A convenience function that calls [`set_template()`][Self::set_template()]
1154    /// with the contents of a resource.
1155    ///
1156    /// Note that any class that installs templates must call
1157    /// `Gtk::Widget::init_template()` in the widget’s instance
1158    /// initializer.
1159    /// ## `resource_name`
1160    /// resource path to load the template from
1161    #[doc(alias = "gtk_widget_class_set_template_from_resource")]
1162    fn set_template_from_resource(&mut self, resource_name: &str) {
1163        unsafe {
1164            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1165            ffi::gtk_widget_class_set_template_from_resource(
1166                widget_class,
1167                resource_name.to_glib_none().0,
1168            );
1169        }
1170    }
1171
1172    fn install_action_async<Fut, F>(
1173        &mut self,
1174        action_name: &str,
1175        parameter_type: Option<&glib::VariantTy>,
1176        activate: F,
1177    ) where
1178        F: Fn(
1179                <<Self as ClassStruct>::Type as ObjectSubclass>::Type,
1180                String,
1181                Option<Variant>,
1182            ) -> Fut
1183            + 'static
1184            + Clone,
1185        Fut: Future<Output = ()>,
1186    {
1187        self.install_action(
1188            action_name,
1189            parameter_type,
1190            move |this, action_name, parameter_type| {
1191                let ctx = glib::MainContext::default();
1192                let action_name = action_name.to_owned();
1193                let parameter_type = parameter_type.map(ToOwned::to_owned);
1194                ctx.spawn_local(glib::clone!(
1195                    #[strong]
1196                    this,
1197                    #[strong]
1198                    action_name,
1199                    #[strong]
1200                    parameter_type,
1201                    #[strong]
1202                    activate,
1203                    async move {
1204                        activate(this, action_name, parameter_type).await;
1205                    }
1206                ));
1207            },
1208        );
1209    }
1210
1211    /// Adds an action for all instances of a widget class.
1212    ///
1213    /// This function should be called at class initialization time.
1214    ///
1215    /// Actions installed by this function are stateless. The only state
1216    /// they have is whether they are enabled or not (which can be changed
1217    /// with [`WidgetExt::action_set_enabled()`][crate::prelude::WidgetExt::action_set_enabled()]).
1218    /// ## `action_name`
1219    /// a prefixed action name, such as "clipboard.paste"
1220    /// ## `parameter_type`
1221    /// the parameter type
1222    /// ## `activate`
1223    /// callback to use when the action is activated
1224    #[doc(alias = "gtk_widget_class_install_action")]
1225    fn install_action<F>(
1226        &mut self,
1227        action_name: &str,
1228        parameter_type: Option<&glib::VariantTy>,
1229        activate: F,
1230    ) where
1231        F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
1232            + 'static,
1233    {
1234        unsafe {
1235            // We store the activate callbacks in a HashMap<action_name, activate>
1236            // so that we can retrieve f later on the activate_trampoline call
1237            let mut data = <Self::Type as ObjectSubclassType>::type_data();
1238            let data = data.as_mut();
1239
1240            let f: Box_<F> = Box_::new(activate);
1241
1242            let internal = data
1243                .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1244                .expect("Something bad happened at class_init, the internal class_data is missing");
1245            let callback_ptr = Box_::into_raw(f) as glib::ffi::gpointer;
1246            internal
1247                .actions
1248                .insert(action_name.to_string(), callback_ptr);
1249
1250            unsafe extern "C" fn activate_trampoline<F, S>(
1251                this: *mut ffi::GtkWidget,
1252                action_name: *const libc::c_char,
1253                parameter: *mut glib::ffi::GVariant,
1254            ) where
1255                S: ClassStruct,
1256                <S as ClassStruct>::Type: ObjectSubclass,
1257                F: Fn(&<<S as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
1258                    + 'static,
1259            {
1260                unsafe {
1261                    let action_name = GString::from_glib_borrow(action_name);
1262
1263                    let data = <S::Type as ObjectSubclassType>::type_data();
1264                    let internal = data
1265                        .as_ref()
1266                        .class_data::<Internal>(<S::Type as ObjectSubclassType>::type_())
1267                        .unwrap();
1268                    let activate_callback = *internal
1269                        .actions
1270                        .get(action_name.as_str())
1271                        .unwrap_or_else(|| {
1272                            panic!("Action name '{}' was not found", action_name.as_str());
1273                        });
1274
1275                    let widget = Widget::from_glib_borrow(this);
1276
1277                    let f: &F = &*(activate_callback as *const F);
1278                    f(
1279                        widget.unsafe_cast_ref(),
1280                        &action_name,
1281                        Option::<Variant>::from_glib_borrow(parameter)
1282                            .as_ref()
1283                            .as_ref(),
1284                    )
1285                }
1286            }
1287            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1288            let callback = activate_trampoline::<F, Self>;
1289            ffi::gtk_widget_class_install_action(
1290                widget_class,
1291                action_name.to_glib_none().0,
1292                parameter_type.map(|p| p.as_str()).to_glib_none().0,
1293                Some(callback),
1294            );
1295        }
1296    }
1297
1298    /// Returns details about an action that has been
1299    /// installed for @self.
1300    ///
1301    /// See [`install_action()`][Self::install_action()] for details on
1302    /// how to install actions.
1303    ///
1304    /// Note that this function will also return actions defined
1305    /// by parent classes. You can identify those by looking
1306    /// at @owner.
1307    /// ## `index_`
1308    /// position of the action to query
1309    ///
1310    /// # Returns
1311    ///
1312    /// true if the action was found
1313    ///
1314    /// ## `owner`
1315    /// return location for the type where the action was defined
1316    ///
1317    /// ## `action_name`
1318    /// return location for the action name
1319    ///
1320    /// ## `parameter_type`
1321    /// return location for the parameter type
1322    ///
1323    /// ## `property_name`
1324    /// return location for the property name
1325    #[doc(alias = "gtk_widget_class_query_action")]
1326    fn query_action(&self) -> WidgetActionIter {
1327        let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1328        WidgetActionIter::new(widget_class)
1329    }
1330
1331    /// Overrides the default scope to be used when parsing the class template.
1332    ///
1333    /// This function is intended for language bindings.
1334    ///
1335    /// Note that this must be called from a composite widget classes class
1336    /// initializer after calling [`set_template()`][Self::set_template()].
1337    /// ## `scope`
1338    /// [`BuilderScope`][crate::BuilderScope] to use when loading
1339    ///   the class template
1340    #[doc(alias = "gtk_widget_class_set_template_scope")]
1341    fn set_template_scope<S: IsA<BuilderScope>>(&mut self, scope: &S) {
1342        unsafe {
1343            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1344            ffi::gtk_widget_class_set_template_scope(widget_class, scope.as_ref().to_glib_none().0);
1345        }
1346    }
1347
1348    /// Creates a new shortcut for @self that calls the given @callback
1349    /// with arguments according to @format_string.
1350    ///
1351    /// The arguments and format string must be provided in the same way as
1352    /// with `GLib::Variant::new()`.
1353    ///
1354    /// This function is a convenience wrapper around
1355    /// [`add_shortcut()`][Self::add_shortcut()] and must be called during class
1356    /// initialization. It does not provide for user data, if you need that,
1357    /// you will have to use [`add_shortcut()`][Self::add_shortcut()] with a custom
1358    /// shortcut.
1359    ///
1360    /// Note: Since 4.24, this function takes key aliases into account.
1361    /// See `keyval_get_aliases()` for more information on key aliases.
1362    /// To make a shortcut for an individual key, use
1363    /// [`add_shortcut()`][Self::add_shortcut()].
1364    /// ## `keyval`
1365    /// key value of binding to install
1366    /// ## `mods`
1367    /// key modifier of binding to install
1368    /// ## `callback`
1369    /// the callback to call upon activation
1370    /// ## `format_string`
1371    /// `GVariant` format string for arguments
1372    #[doc(alias = "gtk_widget_class_add_binding")]
1373    fn add_binding<
1374        F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type) -> glib::Propagation + 'static,
1375    >(
1376        &mut self,
1377        keyval: gdk::Key,
1378        mods: gdk::ModifierType,
1379        callback: F,
1380    ) {
1381        let shortcut = crate::Shortcut::new(
1382            Some(crate::KeyvalTrigger::new(keyval, mods)),
1383            Some(crate::CallbackAction::new(
1384                move |widget, _| -> glib::Propagation {
1385                    unsafe { callback(widget.unsafe_cast_ref()) }
1386                },
1387            )),
1388        );
1389        self.add_shortcut(&shortcut);
1390    }
1391
1392    /// Creates a new shortcut for @self that activates the given
1393    /// @action_name with arguments read according to @format_string.
1394    ///
1395    /// The arguments and format string must be provided in the same way as
1396    /// with `GLib::Variant::new()`.
1397    ///
1398    /// This function is a convenience wrapper around
1399    /// [`add_shortcut()`][Self::add_shortcut()] and must be called during class
1400    /// initialization.
1401    ///
1402    /// Note: Since 4.24, this function takes key aliases into account.
1403    /// See `keyval_get_aliases()` for more information on key aliases.
1404    /// To make a shortcut for an individual key, use
1405    /// [`add_shortcut()`][Self::add_shortcut()].
1406    /// ## `keyval`
1407    /// key value of binding to install
1408    /// ## `mods`
1409    /// key modifier of binding to install
1410    /// ## `action_name`
1411    /// the action to activate
1412    /// ## `format_string`
1413    /// `GVariant` format string for arguments
1414    #[doc(alias = "gtk_widget_class_add_binding_action")]
1415    fn add_binding_action(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, action_name: &str) {
1416        let shortcut = crate::Shortcut::new(
1417            Some(crate::KeyvalTrigger::new(keyval, mods)),
1418            Some(crate::NamedAction::new(action_name)),
1419        );
1420        self.add_shortcut(&shortcut);
1421    }
1422
1423    /// Creates a new shortcut for @self that emits the given action
1424    /// @signal with arguments read according to @format_string.
1425    ///
1426    /// The arguments and format string must be provided in the same way as
1427    /// with `GLib::Variant::new()`.
1428    ///
1429    /// This function is a convenience wrapper around
1430    /// [`add_shortcut()`][Self::add_shortcut()] and must be called during class
1431    /// initialization.
1432    ///
1433    /// Note: Since 4.24, this function takes key aliases into account.
1434    /// See `keyval_get_aliases()` for more information on key aliases.
1435    /// To make a shortcut for an individual key, use
1436    /// [`add_shortcut()`][Self::add_shortcut()].
1437    /// ## `keyval`
1438    /// key value of binding to install
1439    /// ## `mods`
1440    /// key modifier of binding to install
1441    /// ## `signal`
1442    /// the signal to execute
1443    /// ## `format_string`
1444    /// `GVariant` format string for arguments
1445    #[doc(alias = "gtk_widget_class_add_binding_signal")]
1446    fn add_binding_signal(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, signal_name: &str) {
1447        let type_ = <Self::Type as ObjectSubclassType>::type_();
1448        assert!(
1449            SignalId::lookup(signal_name, type_).is_some(),
1450            "Signal '{signal_name}' doesn't exists for type '{type_}'",
1451        );
1452
1453        let shortcut = crate::Shortcut::new(
1454            Some(crate::KeyvalTrigger::new(keyval, mods)),
1455            Some(crate::SignalAction::new(signal_name)),
1456        );
1457        self.add_shortcut(&shortcut);
1458    }
1459
1460    /// Installs a shortcut in @self.
1461    ///
1462    /// Every instance created for @self or its subclasses will
1463    /// inherit this shortcut and trigger it.
1464    ///
1465    /// Shortcuts added this way will be triggered in the [enum@Gtk.PropagationPhase.bubble]
1466    /// phase, which means they may also trigger if child widgets have focus.
1467    ///
1468    /// This function must only be used in class initialization functions
1469    /// otherwise it is not guaranteed that the shortcut will be installed.
1470    /// ## `shortcut`
1471    /// the shortcut to add
1472    #[doc(alias = "gtk_widget_class_add_shortcut")]
1473    fn add_shortcut(&mut self, shortcut: &Shortcut) {
1474        unsafe {
1475            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1476            ffi::gtk_widget_class_add_shortcut(widget_class, shortcut.to_glib_none().0);
1477        }
1478    }
1479
1480    /// Installs an action called @action_name on @self and
1481    /// binds its state to the value of the @property_name property.
1482    ///
1483    /// This function will perform a few sanity checks on the property selected
1484    /// via @property_name. Namely, the property must exist, must be readable,
1485    /// writable and must not be construct-only. There are also restrictions
1486    /// on the type of the given property, it must be boolean, int, unsigned int,
1487    /// double or string. If any of these conditions are not met, a critical
1488    /// warning will be printed and no action will be added.
1489    ///
1490    /// The state type of the action matches the property type.
1491    ///
1492    /// If the property is boolean, the action will have no parameter and
1493    /// toggle the property value. Otherwise, the action will have a parameter
1494    /// of the same type as the property.
1495    /// ## `action_name`
1496    /// name of the action
1497    /// ## `property_name`
1498    /// name of a property in instances of @self
1499    ///   or any parent class
1500    #[doc(alias = "gtk_widget_class_install_property_action")]
1501    fn install_property_action(&mut self, action_name: &str, property_name: &str) {
1502        unsafe {
1503            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1504            ffi::gtk_widget_class_install_property_action(
1505                widget_class,
1506                action_name.to_glib_none().0,
1507                property_name.to_glib_none().0,
1508            );
1509        }
1510    }
1511
1512    /// Retrieves the signal id for the activation signal.
1513    ///
1514    /// The activation signal is set using
1515    /// [`set_activate_signal()`][Self::set_activate_signal()].
1516    ///
1517    /// # Returns
1518    ///
1519    /// a signal id, or 0 if the widget class does not
1520    ///   specify an activation signal
1521    #[doc(alias = "gtk_widget_class_get_activate_signal")]
1522    #[doc(alias = "get_activate_signal")]
1523    fn activate_signal(&self) -> Option<SignalId> {
1524        unsafe {
1525            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1526            let signal_id = ffi::gtk_widget_class_get_activate_signal(widget_class);
1527            if signal_id == 0 {
1528                None
1529            } else {
1530                Some(from_glib(signal_id))
1531            }
1532        }
1533    }
1534
1535    /// Sets the activation signal for a widget class.
1536    ///
1537    /// The signal will be emitted when calling [`WidgetExt::activate()`][crate::prelude::WidgetExt::activate()].
1538    ///
1539    /// The @signal_id must have been registered with [function.GObject.signal_new]
1540    /// or `signal_newv()` before calling this function.
1541    /// ## `signal_id`
1542    /// the id for the activate signal
1543    #[doc(alias = "gtk_widget_class_set_activate_signal")]
1544    fn set_activate_signal(&mut self, signal_id: SignalId) {
1545        unsafe {
1546            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1547            ffi::gtk_widget_class_set_activate_signal(widget_class, signal_id.into_glib())
1548        }
1549    }
1550
1551    /// Sets the activation signal for a widget class.
1552    ///
1553    /// The signal id will by looked up by @signal_name.
1554    ///
1555    /// The signal will be emitted when calling [`WidgetExt::activate()`][crate::prelude::WidgetExt::activate()].
1556    ///
1557    /// The @signal_name must have been registered with [function.GObject.signal_new]
1558    /// or `signal_newv()` before calling this function.
1559    /// ## `signal_name`
1560    /// the name of the activate signal of @widget_type
1561    #[doc(alias = "gtk_widget_class_set_activate_signal_from_name")]
1562    fn set_activate_signal_from_name(&mut self, signal_name: &str) {
1563        let type_ = <Self::Type as ObjectSubclassType>::type_();
1564        assert!(
1565            SignalId::lookup(signal_name, type_).is_some(),
1566            "Signal '{signal_name}' doesn't exists for type '{type_}'",
1567        );
1568
1569        unsafe {
1570            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1571            ffi::gtk_widget_class_set_activate_signal_from_name(
1572                widget_class,
1573                signal_name.to_glib_none().0,
1574            );
1575        }
1576    }
1577
1578    /// Sets the type to be used for creating layout managers for
1579    /// widgets of @self.
1580    ///
1581    /// The given @type_ must be a subtype of [`LayoutManager`][crate::LayoutManager].
1582    ///
1583    /// This function should only be called from class init functions
1584    /// of widgets.
1585    /// ## `type_`
1586    /// the object type that implements the [`LayoutManager`][crate::LayoutManager]
1587    ///   for @self
1588    #[doc(alias = "gtk_widget_class_set_layout_manager_type")]
1589    fn set_layout_manager_type<T: IsA<LayoutManager>>(&mut self) {
1590        unsafe {
1591            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1592            ffi::gtk_widget_class_set_layout_manager_type(
1593                widget_class,
1594                T::static_type().into_glib(),
1595            );
1596        }
1597    }
1598
1599    /// Retrieves the type of the [`LayoutManager`][crate::LayoutManager]
1600    /// used by widgets of class @self.
1601    ///
1602    /// See also: [`set_layout_manager_type()`][Self::set_layout_manager_type()].
1603    ///
1604    /// # Returns
1605    ///
1606    /// type of a [`LayoutManager`][crate::LayoutManager] subclass, or `G_TYPE_INVALID`
1607    #[doc(alias = "gtk_widget_class_get_layout_manager_type")]
1608    #[doc(alias = "get_layout_manager_type")]
1609    fn layout_manager_type(&self) -> glib::Type {
1610        unsafe {
1611            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1612            from_glib(ffi::gtk_widget_class_get_layout_manager_type(widget_class))
1613        }
1614    }
1615
1616    /// Sets the name to be used for CSS matching of widgets.
1617    ///
1618    /// If this function is not called for a given class, the name
1619    /// set on the parent class is used. By default, [`Widget`][crate::Widget]
1620    /// uses the name "widget".
1621    /// ## `name`
1622    /// name to use
1623    #[doc(alias = "gtk_widget_class_set_css_name")]
1624    fn set_css_name(&mut self, name: &str) {
1625        unsafe {
1626            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1627            ffi::gtk_widget_class_set_css_name(widget_class, name.to_glib_none().0);
1628        }
1629    }
1630
1631    /// Gets the name used by this class for matching in CSS code.
1632    ///
1633    /// See [`set_css_name()`][Self::set_css_name()] for details.
1634    ///
1635    /// # Returns
1636    ///
1637    /// the CSS name of the given class
1638    #[doc(alias = "gtk_widget_class_get_css_name")]
1639    #[doc(alias = "get_css_name")]
1640    fn css_name(&self) -> glib::GString {
1641        unsafe {
1642            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1643            from_glib_none(ffi::gtk_widget_class_get_css_name(widget_class))
1644        }
1645    }
1646
1647    /// Sets the accessible role used by the given widget class.
1648    ///
1649    /// Different accessible roles have different states, and are
1650    /// rendered differently by assistive technologies.
1651    /// ## `accessible_role`
1652    /// the accessible role to use
1653    #[doc(alias = "gtk_widget_class_set_accessible_role")]
1654    fn set_accessible_role(&mut self, role: AccessibleRole) {
1655        unsafe {
1656            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1657            ffi::gtk_widget_class_set_accessible_role(widget_class, role.into_glib());
1658        }
1659    }
1660
1661    /// Retrieves the accessible role used by the given widget class.
1662    ///
1663    /// Different accessible roles have different states, and are rendered
1664    /// differently by assistive technologies.
1665    ///
1666    /// See also: [`AccessibleExt::accessible_role()`][crate::prelude::AccessibleExt::accessible_role()].
1667    ///
1668    /// # Returns
1669    ///
1670    /// the accessible role for the widget class
1671    #[doc(alias = "gtk_widget_class_get_accessible_role")]
1672    #[doc(alias = "get_accessible_role")]
1673    fn accessible_role(&self) -> AccessibleRole {
1674        unsafe {
1675            let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1676            from_glib(ffi::gtk_widget_class_get_accessible_role(widget_class))
1677        }
1678    }
1679
1680    #[allow(clippy::missing_safety_doc)]
1681    #[doc(alias = "gtk_widget_class_bind_template_child_full")]
1682    unsafe fn bind_template_child_with_offset<T>(
1683        &mut self,
1684        name: &str,
1685        internal: bool,
1686        offset: field_offset::FieldOffset<Self::Type, TemplateChild<T>>,
1687    ) where
1688        T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1689    {
1690        unsafe {
1691            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1692            let private_offset = <Self::Type as ObjectSubclassType>::type_data()
1693                .as_ref()
1694                .impl_offset();
1695            ffi::gtk_widget_class_bind_template_child_full(
1696                widget_class,
1697                name.to_glib_none().0,
1698                internal.into_glib(),
1699                private_offset + (offset.get_byte_offset() as isize),
1700            )
1701        }
1702    }
1703
1704    fn rust_template_scope(&mut self) -> BuilderRustScope {
1705        assert_initialized_main_thread!();
1706        unsafe {
1707            let mut data = <Self::Type as ObjectSubclassType>::type_data();
1708            let internal = data
1709                .as_mut()
1710                .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1711                .expect("Something bad happened at class_init, the internal class_data is missing");
1712            let scope = internal.scope.get_or_insert_with(|| {
1713                let scope = BuilderRustScope::new();
1714                self.set_template_scope(&scope);
1715                scope.into_glib_ptr()
1716            });
1717            from_glib_none(*scope)
1718        }
1719    }
1720}
1721
1722unsafe impl<T: ClassStruct> WidgetClassExt for T where T::Type: WidgetImpl {}
1723
1724#[derive(Debug, PartialEq, Eq)]
1725#[repr(transparent)]
1726pub struct TemplateChild<T>
1727where
1728    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1729{
1730    ptr: *mut <T as ObjectType>::GlibType,
1731}
1732
1733impl<T: Property> Property for TemplateChild<T>
1734where
1735    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1736{
1737    type Value = T::Value;
1738}
1739
1740impl<T> Default for TemplateChild<T>
1741where
1742    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1743{
1744    fn default() -> Self {
1745        T::static_type();
1746
1747        Self {
1748            ptr: std::ptr::null_mut(),
1749        }
1750    }
1751}
1752
1753impl<T> PropertyGet for TemplateChild<T>
1754where
1755    T: Property + ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1756{
1757    type Value = T;
1758
1759    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
1760        f(&self.get())
1761    }
1762}
1763
1764impl<T> std::ops::Deref for TemplateChild<T>
1765where
1766    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1767{
1768    type Target = T;
1769
1770    #[inline]
1771    fn deref(&self) -> &Self::Target {
1772        unsafe {
1773            if !self.is_bound() {
1774                let name = Self::name();
1775                panic!(
1776                    "Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute."
1777                );
1778            }
1779            &*(&self.ptr as *const _ as *const T)
1780        }
1781    }
1782}
1783
1784impl<T> Downgrade for TemplateChild<T>
1785where
1786    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType> + Downgrade,
1787{
1788    type Weak = T::Weak;
1789
1790    fn downgrade(&self) -> Self::Weak {
1791        T::downgrade(&self.get())
1792    }
1793}
1794
1795impl<T> TemplateChild<T>
1796where
1797    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1798{
1799    pub(crate) fn name<'a>() -> &'a str {
1800        T::static_type().name()
1801    }
1802
1803    #[track_caller]
1804    pub fn get(&self) -> T {
1805        self.try_get()
1806            .unwrap_or_else(|| {
1807                let name = Self::name();
1808                panic!("Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute.");
1809            })
1810    }
1811
1812    // rustdoc-stripper-ignore-next
1813    /// Determines if the child has been bound. This is primarily
1814    /// useful for implementing the [`Buildable`][`crate::Buildable`] interface.
1815    pub fn is_bound(&self) -> bool {
1816        !self.ptr.is_null()
1817    }
1818
1819    // rustdoc-stripper-ignore-next
1820    /// Returns Some(child) if the widget has been bound.
1821    pub fn try_get(&self) -> Option<T> {
1822        unsafe { Option::<T>::from_glib_none(self.ptr) }
1823    }
1824}
1825
1826// rustdoc-stripper-ignore-next
1827/// A trait for setting up template children inside
1828/// [`class_init`](glib::subclass::types::ObjectSubclass::class_init). This
1829/// trait is implemented automatically by the
1830/// [`CompositeTemplate`](crate::CompositeTemplate) macro.
1831pub trait CompositeTemplate: WidgetImpl {
1832    fn bind_template(klass: &mut Self::Class);
1833    fn check_template_children(widget: &<Self as ObjectSubclass>::Type);
1834}
1835
1836// rustdoc-stripper-ignore-next
1837/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1838/// types to allow binding a composite template directly on `self`. This is a
1839/// convenience wrapper around the [`CompositeTemplate`] trait.
1840pub trait CompositeTemplateClass {
1841    // rustdoc-stripper-ignore-next
1842    /// Binds the template callbacks from this type into the default template
1843    /// scope for `self`.
1844    fn bind_template(&mut self);
1845}
1846
1847impl<T, U> CompositeTemplateClass for T
1848where
1849    T: ClassStruct<Type = U>,
1850    U: ObjectSubclass<Class = T> + CompositeTemplate,
1851{
1852    fn bind_template(&mut self) {
1853        <U as CompositeTemplate>::bind_template(self);
1854    }
1855}
1856
1857pub type TemplateCallback = (&'static str, fn(&[glib::Value]) -> Option<glib::Value>);
1858
1859// rustdoc-stripper-ignore-next
1860/// A trait for setting up template callbacks inside
1861/// [`class_init`](glib::subclass::types::ObjectSubclass::class_init). This
1862/// trait is implemented automatically by the
1863/// [`template_callbacks`](crate::template_callbacks) macro.
1864pub trait CompositeTemplateCallbacks {
1865    const CALLBACKS: &'static [TemplateCallback];
1866
1867    // rustdoc-stripper-ignore-next
1868    /// Binds the template callbacks from this type into the default template
1869    /// scope for `klass`.
1870    fn bind_template_callbacks<T: WidgetClassExt>(klass: &mut T) {
1871        Self::add_callbacks_to_scope(&klass.rust_template_scope());
1872    }
1873    // rustdoc-stripper-ignore-next
1874    /// Binds the template callbacks from this type into the default template
1875    /// scope for `klass`, prepending `prefix` to each callback name.
1876    fn bind_template_callbacks_prefixed<T: WidgetClassExt>(klass: &mut T, prefix: &str) {
1877        Self::add_callbacks_to_scope_prefixed(&klass.rust_template_scope(), prefix);
1878    }
1879    // rustdoc-stripper-ignore-next
1880    /// Binds the template callbacks from this type into `scope`.
1881    fn add_callbacks_to_scope(scope: &BuilderRustScope) {
1882        for (name, func) in Self::CALLBACKS {
1883            scope.add_callback(*name, func);
1884        }
1885    }
1886    // rustdoc-stripper-ignore-next
1887    /// Binds the template callbacks from this type into `scope`, prepending
1888    /// `prefix` to each callback name.
1889    fn add_callbacks_to_scope_prefixed(scope: &BuilderRustScope, prefix: &str) {
1890        for (name, func) in Self::CALLBACKS {
1891            scope.add_callback(format!("{prefix}{name}"), func);
1892        }
1893    }
1894}
1895
1896// rustdoc-stripper-ignore-next
1897/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1898/// types to allow binding private template callbacks directly on `self`. This
1899/// is a convenience wrapper around the [`CompositeTemplateCallbacks`] trait.
1900pub trait CompositeTemplateCallbacksClass {
1901    // rustdoc-stripper-ignore-next
1902    /// Binds the template callbacks from the subclass type into the default
1903    /// template scope for `self`.
1904    fn bind_template_callbacks(&mut self);
1905}
1906
1907impl<T, U> CompositeTemplateCallbacksClass for T
1908where
1909    T: ClassStruct<Type = U> + WidgetClassExt,
1910    U: ObjectSubclass<Class = T> + CompositeTemplateCallbacks,
1911{
1912    fn bind_template_callbacks(&mut self) {
1913        <U as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1914    }
1915}
1916
1917// rustdoc-stripper-ignore-next
1918/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1919/// types to allow binding the instance template callbacks directly on `self`.
1920/// This is a convenience wrapper around the [`CompositeTemplateCallbacks`]
1921/// trait.
1922pub trait CompositeTemplateInstanceCallbacksClass {
1923    // rustdoc-stripper-ignore-next
1924    /// Binds the template callbacks from the instance type into the default
1925    /// template scope for `self`.
1926    fn bind_template_instance_callbacks(&mut self);
1927}
1928
1929impl<T, U, V> CompositeTemplateInstanceCallbacksClass for T
1930where
1931    T: ClassStruct<Type = U> + WidgetClassExt,
1932    U: ObjectSubclass<Class = T, Type = V>,
1933    V: CompositeTemplateCallbacks,
1934{
1935    fn bind_template_instance_callbacks(&mut self) {
1936        <V as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1937    }
1938}
1939
1940pub trait CompositeTemplateInitializingExt {
1941    fn init_template(&self);
1942}
1943
1944impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateInitializingExt
1945    for glib::subclass::InitializingObject<T>
1946{
1947    fn init_template(&self) {
1948        unsafe {
1949            let widget = self
1950                .as_ref()
1951                .unsafe_cast_ref::<<T as ObjectSubclass>::Type>();
1952            ffi::gtk_widget_init_template(AsRef::<Widget>::as_ref(widget).to_glib_none().0);
1953
1954            <T as CompositeTemplate>::check_template_children(widget);
1955        }
1956    }
1957}
1958
1959pub trait CompositeTemplateDisposeExt {
1960    #[cfg(feature = "v4_8")]
1961    #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1962    fn dispose_template(&self);
1963}
1964
1965impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateDisposeExt for T {
1966    #[cfg(feature = "v4_8")]
1967    #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1968    fn dispose_template(&self) {
1969        unsafe {
1970            ffi::gtk_widget_dispose_template(
1971                self.obj().upcast_ref::<Widget>().to_glib_none().0,
1972                <T as ObjectSubclass>::Type::static_type().into_glib(),
1973            );
1974        }
1975    }
1976}
1977
1978#[cfg(test)]
1979mod tests {
1980    use super::*;
1981    use crate::{self as gtk4};
1982
1983    // Regression test for https://github.com/gtk-rs/gtk4-rs/issues/2345:
1984    // widget class methods must stay callable on a custom `ClassStruct`, not
1985    // only on `glib::Class<T>`.
1986    mod imp {
1987        use super::*;
1988
1989        #[derive(Default)]
1990        pub struct CustomClassWidget;
1991
1992        #[glib::object_subclass]
1993        impl ObjectSubclass for CustomClassWidget {
1994            const NAME: &'static str = "GtkRsTestCustomClassWidget";
1995            type Type = super::CustomClassWidget;
1996            type ParentType = Widget;
1997            type Class = super::CustomClassWidgetClass;
1998
1999            fn class_init(klass: &mut Self::Class) {
2000                klass.set_css_name("gtkrstestcustomclasswidget");
2001                klass.set_accessible_role(AccessibleRole::Group);
2002                klass.set_layout_manager_type::<crate::BinLayout>();
2003
2004                klass.install_property_action("test.visible", "visible");
2005                klass.add_binding_action(
2006                    gdk::Key::a,
2007                    gdk::ModifierType::CONTROL_MASK,
2008                    "test.visible",
2009                );
2010                klass.add_shortcut(&crate::Shortcut::new(
2011                    Some(crate::KeyvalTrigger::new(
2012                        gdk::Key::b,
2013                        gdk::ModifierType::CONTROL_MASK,
2014                    )),
2015                    Some(crate::NamedAction::new("test.visible")),
2016                ));
2017
2018                // The `&self` getters must be callable on a custom class struct
2019                // too. Deliberately no assertions here: a panic inside
2020                // `class_init()` unwinds across an `extern "C"` boundary and
2021                // aborts the whole test binary instead of reporting a single
2022                // failed test. Every value below is read back and asserted on
2023                // in the test body, where a failure is reported normally.
2024                let _ = klass.css_name();
2025                let _ = klass.accessible_role();
2026                let _ = klass.layout_manager_type();
2027                let _ = klass.activate_signal();
2028                let _ = klass.query_action();
2029            }
2030        }
2031
2032        impl ObjectImpl for CustomClassWidget {}
2033        impl WidgetImpl for CustomClassWidget {}
2034    }
2035
2036    #[cfg(feature = "v4_10")]
2037    glib::wrapper! {
2038        pub struct CustomClassWidget(ObjectSubclass<imp::CustomClassWidget>)
2039            @extends gtk4::Widget,
2040            @implements gtk4::Accessible, gtk4::Buildable, gtk4::ConstraintTarget;
2041    }
2042
2043    #[cfg(not(feature = "v4_10"))]
2044    glib::wrapper! {
2045        pub struct CustomClassWidget(ObjectSubclass<imp::CustomClassWidget>)
2046            @extends gtk4::Widget,
2047            @implements gtk4::Buildable, gtk4::ConstraintTarget;
2048    }
2049
2050    // A user-defined class struct, i.e. *not* `glib::Class<Self>`. It
2051    // deliberately has no `Deref` impl, so nothing can be reached through
2052    // auto-deref.
2053    #[repr(C)]
2054    pub struct CustomClassWidgetClass {
2055        pub parent_class: ffi::GtkWidgetClass,
2056    }
2057
2058    unsafe impl ClassStruct for CustomClassWidgetClass {
2059        type Type = imp::CustomClassWidget;
2060    }
2061
2062    #[crate::test]
2063    fn class_methods_on_custom_class_struct() {
2064        // Instantiating runs `class_init()`, which is where the class methods
2065        // are called on the custom class struct.
2066        let widget = glib::Object::new::<CustomClassWidget>();
2067
2068        // Read the results back through `glib::Class<T>`, which is what
2069        // https://github.com/gtk-rs/gtk4-rs/pull/2319 added. This checks both
2070        // trait impls against the same `GtkWidgetClass`.
2071        let class = widget.class();
2072        assert_eq!(class.css_name(), "gtkrstestcustomclasswidget");
2073        assert_eq!(class.accessible_role(), AccessibleRole::Group);
2074        assert_eq!(class.layout_manager_type(), crate::BinLayout::static_type());
2075        assert!(class.activate_signal().is_none());
2076
2077        // `query_action()` also enumerates actions inherited from parent
2078        // classes, so only assert that the action we installed is present --
2079        // a future GTK may well add class actions to `GtkWidget` itself.
2080        let actions: Vec<_> = class.query_action().map(|a| a.name().to_owned()).collect();
2081        assert!(
2082            actions.iter().any(|name| name == "test.visible"),
2083            "installed action missing from {actions:?}"
2084        );
2085
2086        // ... and on a class looked up by type rather than via an instance.
2087        // Deliberately our own test type: `from_type()` hands out the
2088        // process-global class, so binding a shortcut on e.g. `GtkTextView`
2089        // here would leak into every other test in this binary.
2090        let class = glib::Class::<CustomClassWidget>::from_type(CustomClassWidget::static_type())
2091            .expect("CustomClassWidget class");
2092        class.add_binding_action(gdk::Key::c, gdk::ModifierType::CONTROL_MASK, "test.visible");
2093        assert!(class.query_action().any(|a| a.name() == "test.visible"));
2094    }
2095}