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, 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 @widget's content area.
148    /// ## `x`
149    /// X coordinate to test, relative to @widget's origin
150    /// ## `y`
151    /// Y coordinate to test, relative to @widget's origin
152    ///
153    /// # Returns
154    ///
155    /// true if @widget 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 @widget.
182    #[doc(alias = "get_request_mode")]
183    fn request_mode(&self) -> SizeRequestMode {
184        self.parent_request_mode()
185    }
186
187    /// Causes @widget to have the keyboard focus for the window
188    /// that it belongs to.
189    ///
190    /// If @widget is not focusable, or its [`WidgetImpl::grab_focus()`][crate::subclass::prelude::WidgetImpl::grab_focus()]
191    /// implementation cannot transfer the focus to a descendant of @widget
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 @widget
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    /// s toplevel.
218    ///
219    /// The default [`keynav-failed`][struct@crate::Widget#keynav-failed] handler returns
220    /// false for [enum@Gtk.DirectionType.tab-forward] and
221    /// [enum@Gtk.DirectionType.tab-backward]. For the other values
222    /// of [`DirectionType`][crate::DirectionType] it returns true.
223    ///
224    /// Whenever the default handler returns true, it also calls
225    /// [`WidgetExt::error_bell()`][crate::prelude::WidgetExt::error_bell()] to notify the user of the
226    /// failed keyboard navigation.
227    ///
228    /// A use case for providing an own implementation of `::keynav-failed`
229    /// (either by connecting to it or by overriding it) would be a row of
230    /// [`Entry`][crate::Entry] widgets where the user should be able to navigate
231    /// the entire row with the cursor keys, as e.g. known from user
232    /// interfaces that require entering license keys.
233    /// ## `direction`
234    /// direction of focus movement
235    ///
236    /// # Returns
237    ///
238    /// true if stopping keyboard navigation is fine, false
239    ///   if the emitting widget should try to handle the keyboard
240    ///   navigation attempt in its parent widget
241    fn keynav_failed(&self, direction_type: DirectionType) -> bool {
242        self.parent_keynav_failed(direction_type)
243    }
244
245    /// t already.
246    ///
247    /// This function is only for use in widget implementations.
248    fn map(&self) {
249        self.parent_map()
250    }
251
252    /// s geometry management section](class.Widget.html#height-for-width-geometry-management) for
253    /// a more details on implementing `GtkWidgetClass.measure()`.
254    /// ## `orientation`
255    /// the orientation to measure
256    /// ## `for_size`
257    /// Size for the opposite of @orientation, i.e.
258    ///   if @orientation is [`Orientation::Horizontal`][crate::Orientation::Horizontal], this is
259    ///   the height the widget should be measured with. The [`Orientation::Vertical`][crate::Orientation::Vertical]
260    ///   case is analogous. This way, both height-for-width and width-for-height
261    ///   requests can be implemented. If no size is known, -1 can be passed.
262    ///
263    /// # Returns
264    ///
265    ///
266    /// ## `minimum`
267    /// location to store the minimum size
268    ///
269    /// ## `natural`
270    /// location to store the natural size
271    ///
272    /// ## `minimum_baseline`
273    /// location to store the baseline
274    ///   position for the minimum size, or -1 to report no baseline
275    ///
276    /// ## `natural_baseline`
277    /// location to store the baseline
278    ///   position for the natural size, or -1 to report no baseline
279    fn measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
280        self.parent_measure(orientation, for_size)
281    }
282
283    /// Emits the [`mnemonic-activate`][struct@crate::Widget#mnemonic-activate] signal.
284    /// ## `group_cycling`
285    /// true if there are other widgets with the same mnemonic
286    ///
287    /// # Returns
288    ///
289    /// true if the signal has been handled
290    fn mnemonic_activate(&self, group_cycling: bool) -> bool {
291        self.parent_mnemonic_activate(group_cycling)
292    }
293
294    /// Signal emitted when a change of focus is requested
295    fn move_focus(&self, direction_type: DirectionType) {
296        self.parent_move_focus(direction_type)
297    }
298
299    ///
300    ///   widget; or emitted when widget got focus in keyboard mode.
301    fn query_tooltip(&self, x: i32, y: i32, keyboard_tooltip: bool, tooltip: &Tooltip) -> bool {
302        self.parent_query_tooltip(x, y, keyboard_tooltip, tooltip)
303    }
304
305    /// t very useful otherwise. Many times when you think you might
306    /// need it, a better approach is to connect to a signal that will be
307    /// called after the widget is realized automatically, such as
308    /// [`realize`][struct@crate::Widget#realize].
309    fn realize(&self) {
310        self.parent_realize()
311    }
312
313    /// Called when the widget gets added to a [`Root`][crate::Root] widget. Must
314    ///   chain up
315    fn root(&self) {
316        self.parent_root()
317    }
318
319    /// Set the focus child of the widget.
320    ///
321    /// This function is only suitable for widget implementations.
322    /// If you want a certain widget to get the input focus, call
323    /// [`WidgetExt::grab_focus()`][crate::prelude::WidgetExt::grab_focus()] on it.
324    /// ## `child`
325    /// a direct child widget of @widget
326    ///   or `NULL` to unset the focus child
327    fn set_focus_child(&self, child: Option<&Widget>) {
328        self.parent_set_focus_child(child)
329    }
330
331    /// t shown will not appear on the screen.
332    ///
333    /// Remember that you have to show the containers containing a widget,
334    /// in addition to the widget itself, before it will appear onscreen.
335    ///
336    /// When a toplevel widget is shown, it is immediately realized and
337    /// mapped; other shown widgets are realized and mapped when their
338    /// toplevel widget is realized and mapped.
339    ///
340    /// # Deprecated since 4.10
341    ///
342    /// Use [`WidgetExt::set_visible()`][crate::prelude::WidgetExt::set_visible()] instead
343    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
344    #[allow(deprecated)]
345    fn show(&self) {
346        self.parent_show()
347    }
348
349    /// Called to set the allocation, if the widget does
350    ///   not have a layout manager.
351    fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
352        self.parent_size_allocate(width, height, baseline)
353    }
354
355    /// Vfunc called when a new snapshot of the widget has to be taken.
356    fn snapshot(&self, snapshot: &Snapshot) {
357        self.parent_snapshot(snapshot)
358    }
359
360    /// Signal emitted when the widget state changes,
361    ///   see gtk_widget_get_state_flags().
362    fn state_flags_changed(&self, state_flags: &StateFlags) {
363        self.parent_state_flags_changed(state_flags)
364    }
365
366    /// Emitted when a system setting was changed. Must chain up.
367    fn system_setting_changed(&self, settings: &SystemSetting) {
368        self.parent_system_setting_changed(settings)
369    }
370
371    /// s currently mapped.
372    ///
373    /// This function is only for use in widget implementations.
374    fn unmap(&self) {
375        self.parent_unmap()
376    }
377
378    /// Causes a widget to be unrealized.
379    ///
380    /// This frees all GDK resources associated with the widget.
381    ///
382    /// This function is only useful in widget implementations.
383    fn unrealize(&self) {
384        self.parent_unrealize()
385    }
386
387    /// Called when the widget is about to be removed from its
388    ///   [`Root`][crate::Root] widget. Must chain up
389    fn unroot(&self) {
390        self.parent_unroot()
391    }
392}
393
394pub trait WidgetImplExt: WidgetImpl {
395    fn parent_compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
396        unsafe {
397            let data = Self::type_data();
398            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
399            if let Some(f) = (*parent_class).compute_expand {
400                let mut hexpand_glib = hexpand.into_glib();
401                let mut vexpand_glib = vexpand.into_glib();
402                f(
403                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
404                    &mut hexpand_glib,
405                    &mut vexpand_glib,
406                );
407                *hexpand = from_glib(hexpand_glib);
408                *vexpand = from_glib(vexpand_glib);
409            }
410        }
411    }
412
413    // true if the widget contains (x, y)
414    fn parent_contains(&self, x: f64, y: f64) -> bool {
415        unsafe {
416            let data = Self::type_data();
417            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
418            if let Some(f) = (*parent_class).contains {
419                from_glib(f(
420                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
421                    x,
422                    y,
423                ))
424            } else {
425                false
426            }
427        }
428    }
429
430    fn parent_direction_changed(&self, previous_direction: TextDirection) {
431        unsafe {
432            let data = Self::type_data();
433            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
434            if let Some(f) = (*parent_class).direction_changed {
435                f(
436                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
437                    previous_direction.into_glib(),
438                )
439            }
440        }
441    }
442
443    // Returns true if focus ended up inside widget
444    fn parent_focus(&self, direction_type: DirectionType) -> bool {
445        unsafe {
446            let data = Self::type_data();
447            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
448            if let Some(f) = (*parent_class).focus {
449                from_glib(f(
450                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
451                    direction_type.into_glib(),
452                ))
453            } else {
454                false
455            }
456        }
457    }
458
459    fn parent_request_mode(&self) -> SizeRequestMode {
460        unsafe {
461            let data = Self::type_data();
462            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
463            let f = (*parent_class)
464                .get_request_mode
465                .expect("No parent class impl for \"get_request_mode\"");
466            from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
467        }
468    }
469
470    // Returns true if focus ended up inside widget
471    fn parent_grab_focus(&self) -> bool {
472        unsafe {
473            let data = Self::type_data();
474            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
475            if let Some(f) = (*parent_class).grab_focus {
476                from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
477            } else {
478                false
479            }
480        }
481    }
482
483    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
484    #[allow(deprecated)]
485    fn parent_hide(&self) {
486        unsafe {
487            let data = Self::type_data();
488            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
489            if let Some(f) = (*parent_class).hide {
490                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
491            }
492        }
493    }
494
495    // TRUE if stopping keyboard navigation is fine,
496    // FALSE if the emitting widget should try to handle the keyboard navigation
497    // attempt in its parent container(s).
498    fn parent_keynav_failed(&self, direction_type: DirectionType) -> bool {
499        unsafe {
500            let data = Self::type_data();
501            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
502            if let Some(f) = (*parent_class).keynav_failed {
503                from_glib(f(
504                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
505                    direction_type.into_glib(),
506                ))
507            } else {
508                false
509            }
510        }
511    }
512
513    fn parent_map(&self) {
514        unsafe {
515            let data = Self::type_data();
516            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
517            if let Some(f) = (*parent_class).map {
518                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
519            }
520        }
521    }
522
523    fn parent_measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
524        unsafe {
525            let data = Self::type_data();
526            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
527
528            let f = (*parent_class)
529                .measure
530                .expect("No parent class impl for \"measure\"");
531
532            let mut min = 0;
533            let mut nat = 0;
534            let mut min_base = -1;
535            let mut nat_base = -1;
536            f(
537                self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
538                orientation.into_glib(),
539                for_size,
540                &mut min,
541                &mut nat,
542                &mut min_base,
543                &mut nat_base,
544            );
545            (min, nat, min_base, nat_base)
546        }
547    }
548
549    // True if the signal has been handled
550    fn parent_mnemonic_activate(&self, group_cycling: bool) -> bool {
551        unsafe {
552            let data = Self::type_data();
553            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
554            if let Some(f) = (*parent_class).mnemonic_activate {
555                from_glib(f(
556                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
557                    group_cycling.into_glib(),
558                ))
559            } else {
560                false
561            }
562        }
563    }
564
565    fn parent_move_focus(&self, direction_type: DirectionType) {
566        unsafe {
567            let data = Self::type_data();
568            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
569            if let Some(f) = (*parent_class).move_focus {
570                f(
571                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
572                    direction_type.into_glib(),
573                )
574            }
575        }
576    }
577
578    fn parent_query_tooltip(
579        &self,
580        x: i32,
581        y: i32,
582        keyboard_tooltip: bool,
583        tooltip: &Tooltip,
584    ) -> bool {
585        unsafe {
586            let data = Self::type_data();
587            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
588            if let Some(f) = (*parent_class).query_tooltip {
589                from_glib(f(
590                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
591                    x,
592                    y,
593                    keyboard_tooltip.into_glib(),
594                    tooltip.to_glib_none().0,
595                ))
596            } else {
597                false
598            }
599        }
600    }
601
602    fn parent_realize(&self) {
603        unsafe {
604            let data = Self::type_data();
605            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
606            if let Some(f) = (*parent_class).realize {
607                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
608            }
609        }
610    }
611
612    fn parent_root(&self) {
613        unsafe {
614            let data = Self::type_data();
615            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
616            if let Some(f) = (*parent_class).root {
617                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
618            }
619        }
620    }
621
622    fn parent_set_focus_child(&self, child: Option<&Widget>) {
623        unsafe {
624            let data = Self::type_data();
625            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
626            if let Some(f) = (*parent_class).set_focus_child {
627                f(
628                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
629                    child.to_glib_none().0,
630                )
631            }
632        }
633    }
634
635    #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
636    #[allow(deprecated)]
637    fn parent_show(&self) {
638        unsafe {
639            let data = Self::type_data();
640            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
641            if let Some(f) = (*parent_class).show {
642                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
643            }
644        }
645    }
646
647    fn parent_size_allocate(&self, width: i32, height: i32, baseline: i32) {
648        unsafe {
649            let data = Self::type_data();
650            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
651            if let Some(f) = (*parent_class).size_allocate {
652                f(
653                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
654                    width,
655                    height,
656                    baseline,
657                )
658            }
659        }
660    }
661
662    fn parent_snapshot(&self, snapshot: &Snapshot) {
663        unsafe {
664            let data = Self::type_data();
665            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
666            if let Some(f) = (*parent_class).snapshot {
667                f(
668                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
669                    snapshot.to_glib_none().0,
670                )
671            }
672        }
673    }
674
675    fn parent_state_flags_changed(&self, state_flags: &StateFlags) {
676        unsafe {
677            let data = Self::type_data();
678            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
679            if let Some(f) = (*parent_class).state_flags_changed {
680                f(
681                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
682                    state_flags.into_glib(),
683                )
684            }
685        }
686    }
687
688    fn parent_system_setting_changed(&self, settings: &SystemSetting) {
689        unsafe {
690            let data = Self::type_data();
691            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
692            if let Some(f) = (*parent_class).system_setting_changed {
693                f(
694                    self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
695                    settings.into_glib(),
696                )
697            }
698        }
699    }
700
701    fn parent_unmap(&self) {
702        unsafe {
703            let data = Self::type_data();
704            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
705            if let Some(f) = (*parent_class).unmap {
706                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
707            }
708        }
709    }
710
711    fn parent_unrealize(&self) {
712        unsafe {
713            let data = Self::type_data();
714            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
715            if let Some(f) = (*parent_class).unrealize {
716                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
717            }
718        }
719    }
720
721    fn parent_unroot(&self) {
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).unroot {
726                f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
727            }
728        }
729    }
730}
731
732impl<T: WidgetImpl> WidgetImplExt for T {}
733
734unsafe impl<T: WidgetImpl> IsSubclassable<T> for Widget {
735    fn class_init(class: &mut ::glib::Class<Self>) {
736        Self::parent_class_init::<T>(class);
737
738        assert_initialized_main_thread!();
739
740        let klass = class.as_mut();
741        unsafe {
742            let mut data = T::type_data();
743            let data = data.as_mut();
744            // Used to store actions for `install_action` and `rust_builder_scope`
745            data.set_class_data(<T as ObjectSubclassType>::type_(), Internal::default());
746        }
747
748        klass.compute_expand = Some(widget_compute_expand::<T>);
749        klass.contains = Some(widget_contains::<T>);
750        klass.direction_changed = Some(widget_direction_changed::<T>);
751        klass.focus = Some(widget_focus::<T>);
752        klass.get_request_mode = Some(widget_get_request_mode::<T>);
753        klass.grab_focus = Some(widget_grab_focus::<T>);
754        klass.hide = Some(widget_hide::<T>);
755        klass.keynav_failed = Some(widget_keynav_failed::<T>);
756        klass.map = Some(widget_map::<T>);
757        klass.measure = Some(widget_measure::<T>);
758        klass.mnemonic_activate = Some(widget_mnemonic_activate::<T>);
759        klass.move_focus = Some(widget_move_focus::<T>);
760        klass.query_tooltip = Some(widget_query_tooltip::<T>);
761        klass.realize = Some(widget_realize::<T>);
762        klass.root = Some(widget_root::<T>);
763        klass.set_focus_child = Some(widget_set_focus_child::<T>);
764        klass.show = Some(widget_show::<T>);
765        klass.size_allocate = Some(widget_size_allocate::<T>);
766        klass.snapshot = Some(widget_snapshot::<T>);
767        klass.state_flags_changed = Some(widget_state_flags_changed::<T>);
768        klass.system_setting_changed = Some(widget_system_setting_changed::<T>);
769        klass.unmap = Some(widget_unmap::<T>);
770        klass.unrealize = Some(widget_unrealize::<T>);
771        klass.unroot = Some(widget_unroot::<T>);
772    }
773}
774
775unsafe extern "C" fn widget_compute_expand<T: WidgetImpl>(
776    ptr: *mut ffi::GtkWidget,
777    hexpand_ptr: *mut glib::ffi::gboolean,
778    vexpand_ptr: *mut glib::ffi::gboolean,
779) {
780    unsafe {
781        let instance = &*(ptr as *mut T::Instance);
782        let imp = instance.imp();
783
784        let widget = imp.obj();
785        let widget = widget.unsafe_cast_ref::<Widget>();
786        let mut hexpand: bool = if widget.is_hexpand_set() {
787            widget.hexpands()
788        } else {
789            from_glib(*hexpand_ptr)
790        };
791        let mut vexpand: bool = if widget.is_vexpand_set() {
792            widget.vexpands()
793        } else {
794            from_glib(*vexpand_ptr)
795        };
796
797        imp.compute_expand(&mut hexpand, &mut vexpand);
798
799        *hexpand_ptr = hexpand.into_glib();
800        *vexpand_ptr = vexpand.into_glib();
801    }
802}
803
804unsafe extern "C" fn widget_contains<T: WidgetImpl>(
805    ptr: *mut ffi::GtkWidget,
806    x: f64,
807    y: f64,
808) -> glib::ffi::gboolean {
809    unsafe {
810        let instance = &*(ptr as *mut T::Instance);
811        let imp = instance.imp();
812
813        imp.contains(x, y).into_glib()
814    }
815}
816
817unsafe extern "C" fn widget_direction_changed<T: WidgetImpl>(
818    ptr: *mut ffi::GtkWidget,
819    direction_ptr: ffi::GtkTextDirection,
820) {
821    unsafe {
822        let instance = &*(ptr as *mut T::Instance);
823        let imp = instance.imp();
824        let direction_wrap = from_glib(direction_ptr);
825
826        imp.direction_changed(direction_wrap)
827    }
828}
829
830unsafe extern "C" fn widget_focus<T: WidgetImpl>(
831    ptr: *mut ffi::GtkWidget,
832    direction_type_ptr: ffi::GtkDirectionType,
833) -> glib::ffi::gboolean {
834    unsafe {
835        let instance = &*(ptr as *mut T::Instance);
836        let imp = instance.imp();
837        let direction_type = from_glib(direction_type_ptr);
838
839        imp.focus(direction_type).into_glib()
840    }
841}
842
843unsafe extern "C" fn widget_get_request_mode<T: WidgetImpl>(
844    ptr: *mut ffi::GtkWidget,
845) -> ffi::GtkSizeRequestMode {
846    unsafe {
847        let instance = &*(ptr as *mut T::Instance);
848        let imp = instance.imp();
849
850        imp.request_mode().into_glib()
851    }
852}
853
854unsafe extern "C" fn widget_grab_focus<T: WidgetImpl>(
855    ptr: *mut ffi::GtkWidget,
856) -> glib::ffi::gboolean {
857    unsafe {
858        let instance = &*(ptr as *mut T::Instance);
859        let imp = instance.imp();
860
861        imp.grab_focus().into_glib()
862    }
863}
864
865unsafe extern "C" fn widget_hide<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
866    unsafe {
867        let instance = &*(ptr as *mut T::Instance);
868        let imp = instance.imp();
869
870        imp.hide()
871    }
872}
873
874unsafe extern "C" fn widget_keynav_failed<T: WidgetImpl>(
875    ptr: *mut ffi::GtkWidget,
876    direction_type_ptr: ffi::GtkDirectionType,
877) -> glib::ffi::gboolean {
878    unsafe {
879        let instance = &*(ptr as *mut T::Instance);
880        let imp = instance.imp();
881        let direction_type = from_glib(direction_type_ptr);
882
883        imp.keynav_failed(direction_type).into_glib()
884    }
885}
886
887unsafe extern "C" fn widget_map<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
888    unsafe {
889        let instance = &*(ptr as *mut T::Instance);
890        let imp = instance.imp();
891
892        imp.map()
893    }
894}
895
896unsafe extern "C" fn widget_measure<T: WidgetImpl>(
897    ptr: *mut ffi::GtkWidget,
898    orientation_ptr: ffi::GtkOrientation,
899    for_size: i32,
900    min_ptr: *mut libc::c_int,
901    nat_ptr: *mut libc::c_int,
902    min_base_ptr: *mut libc::c_int,
903    nat_base_ptr: *mut libc::c_int,
904) {
905    unsafe {
906        let instance = &*(ptr as *mut T::Instance);
907        let imp = instance.imp();
908        let orientation = from_glib(orientation_ptr);
909        let (min, nat, min_base, nat_base) = imp.measure(orientation, for_size);
910        if !min_ptr.is_null() {
911            *min_ptr = min;
912        }
913        if !nat_ptr.is_null() {
914            *nat_ptr = nat;
915        }
916        if !min_base_ptr.is_null() {
917            *min_base_ptr = min_base;
918        }
919        if !nat_base_ptr.is_null() {
920            *nat_base_ptr = nat_base;
921        }
922    }
923}
924
925unsafe extern "C" fn widget_mnemonic_activate<T: WidgetImpl>(
926    ptr: *mut ffi::GtkWidget,
927    group_cycling_ptr: glib::ffi::gboolean,
928) -> glib::ffi::gboolean {
929    unsafe {
930        let instance = &*(ptr as *mut T::Instance);
931        let imp = instance.imp();
932        let group_cycling: bool = from_glib(group_cycling_ptr);
933
934        imp.mnemonic_activate(group_cycling).into_glib()
935    }
936}
937
938unsafe extern "C" fn widget_move_focus<T: WidgetImpl>(
939    ptr: *mut ffi::GtkWidget,
940    direction_type_ptr: ffi::GtkDirectionType,
941) {
942    unsafe {
943        let instance = &*(ptr as *mut T::Instance);
944        let imp = instance.imp();
945        let direction_type = from_glib(direction_type_ptr);
946
947        imp.move_focus(direction_type)
948    }
949}
950
951unsafe extern "C" fn widget_query_tooltip<T: WidgetImpl>(
952    ptr: *mut ffi::GtkWidget,
953    x: i32,
954    y: i32,
955    keyboard_tooltip_ptr: glib::ffi::gboolean,
956    tooltip_ptr: *mut ffi::GtkTooltip,
957) -> glib::ffi::gboolean {
958    unsafe {
959        let instance = &*(ptr as *mut T::Instance);
960        let imp = instance.imp();
961
962        let keyboard_tooltip: bool = from_glib(keyboard_tooltip_ptr);
963        let tooltip = from_glib_borrow(tooltip_ptr);
964
965        imp.query_tooltip(x, y, keyboard_tooltip, &tooltip)
966            .into_glib()
967    }
968}
969
970unsafe extern "C" fn widget_realize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
971    unsafe {
972        let instance = &*(ptr as *mut T::Instance);
973        let imp = instance.imp();
974
975        imp.realize()
976    }
977}
978
979unsafe extern "C" fn widget_root<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
980    unsafe {
981        let instance = &*(ptr as *mut T::Instance);
982        let imp = instance.imp();
983
984        imp.root()
985    }
986}
987
988unsafe extern "C" fn widget_set_focus_child<T: WidgetImpl>(
989    ptr: *mut ffi::GtkWidget,
990    child_ptr: *mut ffi::GtkWidget,
991) {
992    unsafe {
993        let instance = &*(ptr as *mut T::Instance);
994        let imp = instance.imp();
995        let child: Borrowed<Option<Widget>> = from_glib_borrow(child_ptr);
996
997        imp.set_focus_child(child.as_ref().as_ref())
998    }
999}
1000
1001unsafe extern "C" fn widget_show<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1002    unsafe {
1003        let instance = &*(ptr as *mut T::Instance);
1004        let imp = instance.imp();
1005
1006        imp.show()
1007    }
1008}
1009
1010unsafe extern "C" fn widget_size_allocate<T: WidgetImpl>(
1011    ptr: *mut ffi::GtkWidget,
1012    width: i32,
1013    height: i32,
1014    baseline: i32,
1015) {
1016    unsafe {
1017        let instance = &*(ptr as *mut T::Instance);
1018        let imp = instance.imp();
1019
1020        imp.size_allocate(width, height, baseline)
1021    }
1022}
1023
1024unsafe extern "C" fn widget_snapshot<T: WidgetImpl>(
1025    ptr: *mut ffi::GtkWidget,
1026    snapshot_ptr: *mut ffi::GtkSnapshot,
1027) {
1028    unsafe {
1029        let instance = &*(ptr as *mut T::Instance);
1030        let imp = instance.imp();
1031        let snapshot = from_glib_borrow(snapshot_ptr);
1032
1033        imp.snapshot(&snapshot)
1034    }
1035}
1036
1037unsafe extern "C" fn widget_state_flags_changed<T: WidgetImpl>(
1038    ptr: *mut ffi::GtkWidget,
1039    state_flags_ptr: ffi::GtkStateFlags,
1040) {
1041    unsafe {
1042        let instance = &*(ptr as *mut T::Instance);
1043        let imp = instance.imp();
1044        let state_flags = from_glib(state_flags_ptr);
1045
1046        imp.state_flags_changed(&state_flags)
1047    }
1048}
1049
1050unsafe extern "C" fn widget_system_setting_changed<T: WidgetImpl>(
1051    ptr: *mut ffi::GtkWidget,
1052    settings_ptr: ffi::GtkSystemSetting,
1053) {
1054    unsafe {
1055        let instance = &*(ptr as *mut T::Instance);
1056        let imp = instance.imp();
1057        let settings = from_glib(settings_ptr);
1058
1059        imp.system_setting_changed(&settings)
1060    }
1061}
1062
1063unsafe extern "C" fn widget_unmap<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1064    unsafe {
1065        let instance = &*(ptr as *mut T::Instance);
1066        let imp = instance.imp();
1067
1068        imp.unmap()
1069    }
1070}
1071
1072unsafe extern "C" fn widget_unrealize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1073    unsafe {
1074        let instance = &*(ptr as *mut T::Instance);
1075        let imp = instance.imp();
1076
1077        imp.unrealize()
1078    }
1079}
1080
1081unsafe extern "C" fn widget_unroot<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1082    unsafe {
1083        let instance = &*(ptr as *mut T::Instance);
1084        let imp = instance.imp();
1085
1086        imp.unroot()
1087    }
1088}
1089
1090#[allow(clippy::missing_safety_doc)]
1091pub unsafe trait WidgetClassExt: ClassStruct {
1092    #[doc(alias = "gtk_widget_class_set_template")]
1093    fn set_template_bytes(&mut self, template: &glib::Bytes) {
1094        unsafe {
1095            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1096            ffi::gtk_widget_class_set_template(widget_class, template.to_glib_none().0);
1097        }
1098    }
1099
1100    /// s instance initializer.
1101    /// ## `template_bytes`
1102    /// `GBytes` holding the [`Builder`][crate::Builder] XML
1103    fn set_template(&mut self, template: &[u8]) {
1104        let template_bytes = glib::Bytes::from(template);
1105        self.set_template_bytes(&template_bytes);
1106    }
1107
1108    fn set_template_static(&mut self, template: &'static [u8]) {
1109        let template_bytes = glib::Bytes::from_static(template);
1110        self.set_template_bytes(&template_bytes);
1111    }
1112
1113    /// s instance
1114    /// initializer.
1115    /// ## `resource_name`
1116    /// resource path to load the template from
1117    #[doc(alias = "gtk_widget_class_set_template_from_resource")]
1118    fn set_template_from_resource(&mut self, resource_name: &str) {
1119        unsafe {
1120            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1121            ffi::gtk_widget_class_set_template_from_resource(
1122                widget_class,
1123                resource_name.to_glib_none().0,
1124            );
1125        }
1126    }
1127
1128    fn install_action_async<Fut, F>(
1129        &mut self,
1130        action_name: &str,
1131        parameter_type: Option<&glib::VariantTy>,
1132        activate: F,
1133    ) where
1134        F: Fn(
1135                <<Self as ClassStruct>::Type as ObjectSubclass>::Type,
1136                String,
1137                Option<Variant>,
1138            ) -> Fut
1139            + 'static
1140            + Clone,
1141        Fut: Future<Output = ()>,
1142    {
1143        self.install_action(
1144            action_name,
1145            parameter_type,
1146            move |this, action_name, parameter_type| {
1147                let ctx = glib::MainContext::default();
1148                let action_name = action_name.to_owned();
1149                let parameter_type = parameter_type.map(ToOwned::to_owned);
1150                ctx.spawn_local(glib::clone!(
1151                    #[strong]
1152                    this,
1153                    #[strong]
1154                    action_name,
1155                    #[strong]
1156                    parameter_type,
1157                    #[strong]
1158                    activate,
1159                    async move {
1160                        activate(this, action_name, parameter_type).await;
1161                    }
1162                ));
1163            },
1164        );
1165    }
1166
1167    /// Adds an action for all instances of a widget class.
1168    ///
1169    /// This function should be called at class initialization time.
1170    ///
1171    /// Actions installed by this function are stateless. The only state
1172    /// they have is whether they are enabled or not (which can be changed
1173    /// with [`WidgetExt::action_set_enabled()`][crate::prelude::WidgetExt::action_set_enabled()]).
1174    /// ## `action_name`
1175    /// a prefixed action name, such as "clipboard.paste"
1176    /// ## `parameter_type`
1177    /// the parameter type
1178    /// ## `activate`
1179    /// callback to use when the action is activated
1180    #[doc(alias = "gtk_widget_class_install_action")]
1181    fn install_action<F>(
1182        &mut self,
1183        action_name: &str,
1184        parameter_type: Option<&glib::VariantTy>,
1185        activate: F,
1186    ) where
1187        F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
1188            + 'static,
1189    {
1190        unsafe {
1191            // We store the activate callbacks in a HashMap<action_name, activate>
1192            // so that we can retrieve f later on the activate_trampoline call
1193            let mut data = <Self::Type as ObjectSubclassType>::type_data();
1194            let data = data.as_mut();
1195
1196            let f: Box_<F> = Box_::new(activate);
1197
1198            let internal = data
1199                .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1200                .expect("Something bad happened at class_init, the internal class_data is missing");
1201            let callback_ptr = Box_::into_raw(f) as glib::ffi::gpointer;
1202            internal
1203                .actions
1204                .insert(action_name.to_string(), callback_ptr);
1205
1206            unsafe extern "C" fn activate_trampoline<F, S>(
1207                this: *mut ffi::GtkWidget,
1208                action_name: *const libc::c_char,
1209                parameter: *mut glib::ffi::GVariant,
1210            ) where
1211                S: ClassStruct,
1212                <S as ClassStruct>::Type: ObjectSubclass,
1213                F: Fn(&<<S as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
1214                    + 'static,
1215            {
1216                unsafe {
1217                    let action_name = GString::from_glib_borrow(action_name);
1218
1219                    let data = <S::Type as ObjectSubclassType>::type_data();
1220                    let internal = data
1221                        .as_ref()
1222                        .class_data::<Internal>(<S::Type as ObjectSubclassType>::type_())
1223                        .unwrap();
1224                    let activate_callback = *internal
1225                        .actions
1226                        .get(&action_name.to_string())
1227                        .unwrap_or_else(|| {
1228                            panic!("Action name '{}' was not found", action_name.as_str());
1229                        });
1230
1231                    let widget = Widget::from_glib_borrow(this);
1232
1233                    let f: &F = &*(activate_callback as *const F);
1234                    f(
1235                        widget.unsafe_cast_ref(),
1236                        &action_name,
1237                        Option::<Variant>::from_glib_borrow(parameter)
1238                            .as_ref()
1239                            .as_ref(),
1240                    )
1241                }
1242            }
1243            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1244            let callback = activate_trampoline::<F, Self>;
1245            ffi::gtk_widget_class_install_action(
1246                widget_class,
1247                action_name.to_glib_none().0,
1248                parameter_type.map(|p| p.as_str()).to_glib_none().0,
1249                Some(callback),
1250            );
1251        }
1252    }
1253
1254    /// Overrides the default scope to be used when parsing the class template.
1255    ///
1256    /// This function is intended for language bindings.
1257    ///
1258    /// Note that this must be called from a composite widget classes class
1259    /// initializer after calling [`set_template()`][Self::set_template()].
1260    /// ## `scope`
1261    /// [`BuilderScope`][crate::BuilderScope] to use when loading
1262    ///   the class template
1263    #[doc(alias = "gtk_widget_class_set_template_scope")]
1264    fn set_template_scope<S: IsA<BuilderScope>>(&mut self, scope: &S) {
1265        unsafe {
1266            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1267            ffi::gtk_widget_class_set_template_scope(widget_class, scope.as_ref().to_glib_none().0);
1268        }
1269    }
1270
1271    /// Creates a new shortcut for @self that calls the given @callback
1272    /// with arguments according to @format_string.
1273    ///
1274    /// The arguments and format string must be provided in the same way as
1275    /// with `GLib::Variant::new()`.
1276    ///
1277    /// This function is a convenience wrapper around
1278    /// [`add_shortcut()`][Self::add_shortcut()] and must be called during class
1279    /// initialization. It does not provide for user data, if you need that,
1280    /// you will have to use [`add_shortcut()`][Self::add_shortcut()] with a custom
1281    /// shortcut.
1282    ///
1283    /// Note: Since 4.24, this function takes key aliases into account.
1284    /// See `keyval_get_aliases()` for more information on key aliases.
1285    /// To make a shortcut for an individual key, use
1286    /// [`add_shortcut()`][Self::add_shortcut()].
1287    /// ## `keyval`
1288    /// key value of binding to install
1289    /// ## `mods`
1290    /// key modifier of binding to install
1291    /// ## `callback`
1292    /// the callback to call upon activation
1293    /// ## `format_string`
1294    /// `GVariant` format string for arguments
1295    #[doc(alias = "gtk_widget_class_add_binding")]
1296    fn add_binding<
1297        F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type) -> glib::Propagation + 'static,
1298    >(
1299        &mut self,
1300        keyval: gdk::Key,
1301        mods: gdk::ModifierType,
1302        callback: F,
1303    ) {
1304        let shortcut = crate::Shortcut::new(
1305            Some(crate::KeyvalTrigger::new(keyval, mods)),
1306            Some(crate::CallbackAction::new(
1307                move |widget, _| -> glib::Propagation {
1308                    unsafe { callback(widget.unsafe_cast_ref()) }
1309                },
1310            )),
1311        );
1312        unsafe {
1313            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1314            ffi::gtk_widget_class_add_shortcut(widget_class, shortcut.to_glib_none().0);
1315        }
1316    }
1317
1318    /// Creates a new shortcut for @self that emits the given action
1319    /// @signal with arguments read according to @format_string.
1320    ///
1321    /// The arguments and format string must be provided in the same way as
1322    /// with `GLib::Variant::new()`.
1323    ///
1324    /// This function is a convenience wrapper around
1325    /// [`add_shortcut()`][Self::add_shortcut()] and must be called during class
1326    /// initialization.
1327    ///
1328    /// Note: Since 4.24, this function takes key aliases into account.
1329    /// See `keyval_get_aliases()` for more information on key aliases.
1330    /// To make a shortcut for an individual key, use
1331    /// [`add_shortcut()`][Self::add_shortcut()].
1332    /// ## `keyval`
1333    /// key value of binding to install
1334    /// ## `mods`
1335    /// key modifier of binding to install
1336    /// ## `signal`
1337    /// the signal to execute
1338    /// ## `format_string`
1339    /// `GVariant` format string for arguments
1340    #[doc(alias = "gtk_widget_class_add_binding_signal")]
1341    fn add_binding_signal(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, signal_name: &str) {
1342        let type_ = <Self::Type as ObjectSubclassType>::type_();
1343        assert!(
1344            SignalId::lookup(signal_name, type_).is_some(),
1345            "Signal '{signal_name}' doesn't exists for type '{type_}'",
1346        );
1347
1348        let shortcut = crate::Shortcut::new(
1349            Some(crate::KeyvalTrigger::new(keyval, mods)),
1350            Some(crate::SignalAction::new(signal_name)),
1351        );
1352        unsafe {
1353            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1354            ffi::gtk_widget_class_add_shortcut(widget_class, shortcut.to_glib_none().0);
1355        }
1356    }
1357
1358    /// Sets the activation signal for a widget class.
1359    ///
1360    /// The signal will be emitted when calling [`WidgetExt::activate()`][crate::prelude::WidgetExt::activate()].
1361    ///
1362    /// The @signal_id must have been registered with [function.GObject.signal_new]
1363    /// or `signal_newv()` before calling this function.
1364    /// ## `signal_id`
1365    /// the id for the activate signal
1366    #[doc(alias = "gtk_widget_class_set_activate_signal")]
1367    fn set_activate_signal(&mut self, signal_id: SignalId) {
1368        unsafe {
1369            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1370            ffi::gtk_widget_class_set_activate_signal(widget_class, signal_id.into_glib())
1371        }
1372    }
1373
1374    /// Sets the activation signal for a widget class.
1375    ///
1376    /// The signal id will by looked up by @signal_name.
1377    ///
1378    /// The signal will be emitted when calling [`WidgetExt::activate()`][crate::prelude::WidgetExt::activate()].
1379    ///
1380    /// The @signal_name must have been registered with [function.GObject.signal_new]
1381    /// or `signal_newv()` before calling this function.
1382    /// ## `signal_name`
1383    /// the name of the activate signal of @widget_type
1384    #[doc(alias = "gtk_widget_class_set_activate_signal_from_name")]
1385    fn set_activate_signal_from_name(&mut self, signal_name: &str) {
1386        let type_ = <Self::Type as ObjectSubclassType>::type_();
1387        assert!(
1388            SignalId::lookup(signal_name, type_).is_some(),
1389            "Signal '{signal_name}' doesn't exists for type '{type_}'",
1390        );
1391
1392        unsafe {
1393            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1394            ffi::gtk_widget_class_set_activate_signal_from_name(
1395                widget_class,
1396                signal_name.to_glib_none().0,
1397            );
1398        }
1399    }
1400
1401    /// Sets the type to be used for creating layout managers for
1402    /// widgets of @self.
1403    ///
1404    /// The given @type_ must be a subtype of [`LayoutManager`][crate::LayoutManager].
1405    ///
1406    /// This function should only be called from class init functions
1407    /// of widgets.
1408    /// ## `type_`
1409    /// the object type that implements the [`LayoutManager`][crate::LayoutManager]
1410    ///   for @self
1411    #[doc(alias = "gtk_widget_class_set_layout_manager_type")]
1412    fn set_layout_manager_type<T: IsA<LayoutManager>>(&mut self) {
1413        unsafe {
1414            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1415            ffi::gtk_widget_class_set_layout_manager_type(
1416                widget_class,
1417                T::static_type().into_glib(),
1418            );
1419        }
1420    }
1421
1422    /// Sets the name to be used for CSS matching of widgets.
1423    ///
1424    /// If this function is not called for a given class, the name
1425    /// set on the parent class is used. By default, [`Widget`][crate::Widget]
1426    /// uses the name "widget".
1427    /// ## `name`
1428    /// name to use
1429    #[doc(alias = "gtk_widget_class_set_css_name")]
1430    fn set_css_name(&mut self, name: &str) {
1431        unsafe {
1432            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1433            ffi::gtk_widget_class_set_css_name(widget_class, name.to_glib_none().0);
1434        }
1435    }
1436
1437    /// Sets the accessible role used by the given widget class.
1438    ///
1439    /// Different accessible roles have different states, and are
1440    /// rendered differently by assistive technologies.
1441    /// ## `accessible_role`
1442    /// the accessible role to use
1443    #[doc(alias = "gtk_widget_class_set_accessible_role")]
1444    fn set_accessible_role(&mut self, role: AccessibleRole) {
1445        unsafe {
1446            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1447            ffi::gtk_widget_class_set_accessible_role(widget_class, role.into_glib());
1448        }
1449    }
1450
1451    #[allow(clippy::missing_safety_doc)]
1452    #[doc(alias = "gtk_widget_class_bind_template_child_full")]
1453    unsafe fn bind_template_child_with_offset<T>(
1454        &mut self,
1455        name: &str,
1456        internal: bool,
1457        offset: field_offset::FieldOffset<Self::Type, TemplateChild<T>>,
1458    ) where
1459        T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1460    {
1461        unsafe {
1462            let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1463            let private_offset = <Self::Type as ObjectSubclassType>::type_data()
1464                .as_ref()
1465                .impl_offset();
1466            ffi::gtk_widget_class_bind_template_child_full(
1467                widget_class,
1468                name.to_glib_none().0,
1469                internal.into_glib(),
1470                private_offset + (offset.get_byte_offset() as isize),
1471            )
1472        }
1473    }
1474
1475    fn rust_template_scope(&mut self) -> BuilderRustScope {
1476        assert_initialized_main_thread!();
1477        unsafe {
1478            let mut data = <Self::Type as ObjectSubclassType>::type_data();
1479            let internal = data
1480                .as_mut()
1481                .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1482                .expect("Something bad happened at class_init, the internal class_data is missing");
1483            let scope = internal.scope.get_or_insert_with(|| {
1484                let scope = BuilderRustScope::new();
1485                self.set_template_scope(&scope);
1486                scope.into_glib_ptr()
1487            });
1488            from_glib_none(*scope)
1489        }
1490    }
1491}
1492
1493unsafe impl<T: ClassStruct> WidgetClassExt for T where T::Type: WidgetImpl {}
1494
1495#[derive(Debug, PartialEq, Eq)]
1496#[repr(transparent)]
1497pub struct TemplateChild<T>
1498where
1499    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1500{
1501    ptr: *mut <T as ObjectType>::GlibType,
1502}
1503
1504impl<T: Property> Property for TemplateChild<T>
1505where
1506    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1507{
1508    type Value = T::Value;
1509}
1510
1511impl<T> Default for TemplateChild<T>
1512where
1513    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1514{
1515    fn default() -> Self {
1516        T::static_type();
1517
1518        Self {
1519            ptr: std::ptr::null_mut(),
1520        }
1521    }
1522}
1523
1524impl<T> PropertyGet for TemplateChild<T>
1525where
1526    T: Property + ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1527{
1528    type Value = T;
1529
1530    fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
1531        f(&self.get())
1532    }
1533}
1534
1535impl<T> std::ops::Deref for TemplateChild<T>
1536where
1537    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1538{
1539    type Target = T;
1540
1541    #[inline]
1542    fn deref(&self) -> &Self::Target {
1543        unsafe {
1544            if !self.is_bound() {
1545                let name = Self::name();
1546                panic!(
1547                    "Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute."
1548                );
1549            }
1550            &*(&self.ptr as *const _ as *const T)
1551        }
1552    }
1553}
1554
1555impl<T> Downgrade for TemplateChild<T>
1556where
1557    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType> + Downgrade,
1558{
1559    type Weak = T::Weak;
1560
1561    fn downgrade(&self) -> Self::Weak {
1562        T::downgrade(&self.get())
1563    }
1564}
1565
1566impl<T> TemplateChild<T>
1567where
1568    T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1569{
1570    pub(crate) fn name<'a>() -> &'a str {
1571        T::static_type().name()
1572    }
1573
1574    #[track_caller]
1575    pub fn get(&self) -> T {
1576        self.try_get()
1577            .unwrap_or_else(|| {
1578                let name = Self::name();
1579                panic!("Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute.");
1580            })
1581    }
1582
1583    // rustdoc-stripper-ignore-next
1584    /// Determines if the child has been bound. This is primarily
1585    /// useful for implementing the [`Buildable`][`crate::Buildable`] interface.
1586    pub fn is_bound(&self) -> bool {
1587        !self.ptr.is_null()
1588    }
1589
1590    // rustdoc-stripper-ignore-next
1591    /// Returns Some(child) if the widget has been bound.
1592    pub fn try_get(&self) -> Option<T> {
1593        unsafe { Option::<T>::from_glib_none(self.ptr) }
1594    }
1595}
1596
1597// rustdoc-stripper-ignore-next
1598/// A trait for setting up template children inside
1599/// [`class_init`](glib::subclass::types::ObjectSubclass::class_init). This
1600/// trait is implemented automatically by the
1601/// [`CompositeTemplate`](crate::CompositeTemplate) macro.
1602pub trait CompositeTemplate: WidgetImpl {
1603    fn bind_template(klass: &mut Self::Class);
1604    fn check_template_children(widget: &<Self as ObjectSubclass>::Type);
1605}
1606
1607// rustdoc-stripper-ignore-next
1608/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1609/// types to allow binding a composite template directly on `self`. This is a
1610/// convenience wrapper around the [`CompositeTemplate`] trait.
1611pub trait CompositeTemplateClass {
1612    // rustdoc-stripper-ignore-next
1613    /// Binds the template callbacks from this type into the default template
1614    /// scope for `self`.
1615    fn bind_template(&mut self);
1616}
1617
1618impl<T, U> CompositeTemplateClass for T
1619where
1620    T: ClassStruct<Type = U>,
1621    U: ObjectSubclass<Class = T> + CompositeTemplate,
1622{
1623    fn bind_template(&mut self) {
1624        <U as CompositeTemplate>::bind_template(self);
1625    }
1626}
1627
1628pub type TemplateCallback = (&'static str, fn(&[glib::Value]) -> Option<glib::Value>);
1629
1630// rustdoc-stripper-ignore-next
1631/// A trait for setting up template callbacks inside
1632/// [`class_init`](glib::subclass::types::ObjectSubclass::class_init). This
1633/// trait is implemented automatically by the
1634/// [`template_callbacks`](crate::template_callbacks) macro.
1635pub trait CompositeTemplateCallbacks {
1636    const CALLBACKS: &'static [TemplateCallback];
1637
1638    // rustdoc-stripper-ignore-next
1639    /// Binds the template callbacks from this type into the default template
1640    /// scope for `klass`.
1641    fn bind_template_callbacks<T: WidgetClassExt>(klass: &mut T) {
1642        Self::add_callbacks_to_scope(&klass.rust_template_scope());
1643    }
1644    // rustdoc-stripper-ignore-next
1645    /// Binds the template callbacks from this type into the default template
1646    /// scope for `klass`, prepending `prefix` to each callback name.
1647    fn bind_template_callbacks_prefixed<T: WidgetClassExt>(klass: &mut T, prefix: &str) {
1648        Self::add_callbacks_to_scope_prefixed(&klass.rust_template_scope(), prefix);
1649    }
1650    // rustdoc-stripper-ignore-next
1651    /// Binds the template callbacks from this type into `scope`.
1652    fn add_callbacks_to_scope(scope: &BuilderRustScope) {
1653        for (name, func) in Self::CALLBACKS {
1654            scope.add_callback(*name, func);
1655        }
1656    }
1657    // rustdoc-stripper-ignore-next
1658    /// Binds the template callbacks from this type into `scope`, prepending
1659    /// `prefix` to each callback name.
1660    fn add_callbacks_to_scope_prefixed(scope: &BuilderRustScope, prefix: &str) {
1661        for (name, func) in Self::CALLBACKS {
1662            scope.add_callback(format!("{prefix}{name}"), func);
1663        }
1664    }
1665}
1666
1667// rustdoc-stripper-ignore-next
1668/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1669/// types to allow binding private template callbacks directly on `self`. This
1670/// is a convenience wrapper around the [`CompositeTemplateCallbacks`] trait.
1671pub trait CompositeTemplateCallbacksClass {
1672    // rustdoc-stripper-ignore-next
1673    /// Binds the template callbacks from the subclass type into the default
1674    /// template scope for `self`.
1675    fn bind_template_callbacks(&mut self);
1676}
1677
1678impl<T, U> CompositeTemplateCallbacksClass for T
1679where
1680    T: ClassStruct<Type = U> + WidgetClassExt,
1681    U: ObjectSubclass<Class = T> + CompositeTemplateCallbacks,
1682{
1683    fn bind_template_callbacks(&mut self) {
1684        <U as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1685    }
1686}
1687
1688// rustdoc-stripper-ignore-next
1689/// An extension trait for [`ClassStruct`](glib::subclass::types::ClassStruct)
1690/// types to allow binding the instance template callbacks directly on `self`.
1691/// This is a convenience wrapper around the [`CompositeTemplateCallbacks`]
1692/// trait.
1693pub trait CompositeTemplateInstanceCallbacksClass {
1694    // rustdoc-stripper-ignore-next
1695    /// Binds the template callbacks from the instance type into the default
1696    /// template scope for `self`.
1697    fn bind_template_instance_callbacks(&mut self);
1698}
1699
1700impl<T, U, V> CompositeTemplateInstanceCallbacksClass for T
1701where
1702    T: ClassStruct<Type = U> + WidgetClassExt,
1703    U: ObjectSubclass<Class = T, Type = V>,
1704    V: CompositeTemplateCallbacks,
1705{
1706    fn bind_template_instance_callbacks(&mut self) {
1707        <V as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1708    }
1709}
1710
1711pub trait CompositeTemplateInitializingExt {
1712    fn init_template(&self);
1713}
1714
1715impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateInitializingExt
1716    for glib::subclass::InitializingObject<T>
1717{
1718    fn init_template(&self) {
1719        unsafe {
1720            let widget = self
1721                .as_ref()
1722                .unsafe_cast_ref::<<T as ObjectSubclass>::Type>();
1723            ffi::gtk_widget_init_template(AsRef::<Widget>::as_ref(widget).to_glib_none().0);
1724
1725            <T as CompositeTemplate>::check_template_children(widget);
1726        }
1727    }
1728}
1729
1730pub trait CompositeTemplateDisposeExt {
1731    #[cfg(feature = "v4_8")]
1732    #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1733    fn dispose_template(&self);
1734}
1735
1736impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateDisposeExt for T {
1737    #[cfg(feature = "v4_8")]
1738    #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1739    fn dispose_template(&self) {
1740        unsafe {
1741            ffi::gtk_widget_dispose_template(
1742                self.obj().upcast_ref::<Widget>().to_glib_none().0,
1743                <T as ObjectSubclass>::Type::static_type().into_glib(),
1744            );
1745        }
1746    }
1747}