gtk4/subclass/
widget.rs

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