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