1use std::{boxed::Box as Box_, collections::HashMap, fmt, future::Future};
7
8use glib::{
9 GString, Variant,
10 clone::Downgrade,
11 property::{Property, PropertyGet},
12 subclass::SignalId,
13 translate::*,
14};
15
16use crate::{
17 AccessibleRole, Buildable, BuilderRustScope, BuilderScope, ConstraintTarget, DirectionType,
18 LayoutManager, Orientation, Shortcut, SizeRequestMode, Snapshot, StateFlags, SystemSetting,
19 TextDirection, Tooltip, Widget, ffi, prelude::*, subclass::prelude::*,
20};
21
22#[derive(Debug, Default)]
23struct Internal {
24 pub(crate) actions: HashMap<String, glib::ffi::gpointer>,
25 pub(crate) scope: Option<*mut <<BuilderRustScope as glib::object::ObjectSubclassIs>::Subclass as ObjectSubclass>::Instance>,
26}
27unsafe impl Sync for Internal {}
28unsafe impl Send for Internal {}
29
30pub struct WidgetActionIter(*mut ffi::GtkWidgetClass, u32);
31
32impl WidgetActionIter {
33 pub(crate) fn new(widget_class: *mut ffi::GtkWidgetClass) -> Self {
34 Self(widget_class, 0)
35 }
36}
37
38pub struct WidgetAction(
39 glib::Type,
40 GString,
41 Option<glib::VariantType>,
42 Option<GString>,
43);
44
45impl WidgetAction {
46 pub fn owner(&self) -> glib::Type {
49 self.0
50 }
51
52 pub fn name(&self) -> &str {
55 self.1.as_ref()
56 }
57
58 pub fn parameter_type(&self) -> Option<&glib::VariantType> {
61 self.2.as_ref()
62 }
63
64 pub fn property_name(&self) -> Option<&str> {
67 self.3.as_ref().map(|s| s.as_ref())
68 }
69}
70
71impl fmt::Debug for WidgetAction {
72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73 f.debug_struct("WidgetAction")
74 .field("owner", &self.owner())
75 .field("name", &self.name())
76 .field("parameter_type", &self.parameter_type())
77 .field("property_name", &self.property_name())
78 .finish()
79 }
80}
81
82impl Iterator for WidgetActionIter {
83 type Item = WidgetAction;
84
85 fn next(&mut self) -> Option<Self::Item> {
86 unsafe {
87 let mut owner = std::mem::MaybeUninit::uninit();
88 let mut action_name_ptr = std::ptr::null();
89 let mut parameter_type = std::ptr::null();
90 let mut property_name_ptr = std::ptr::null();
91 let found: bool = from_glib(ffi::gtk_widget_class_query_action(
92 self.0,
93 self.1,
94 owner.as_mut_ptr(),
95 &mut action_name_ptr,
96 &mut parameter_type,
97 &mut property_name_ptr,
98 ));
99 if found {
100 self.1 += 1;
101 let property_name: Option<GString> = from_glib_none(property_name_ptr);
102 let action_name: GString = from_glib_none(action_name_ptr);
103
104 Some(WidgetAction(
105 from_glib(owner.assume_init()),
106 action_name,
107 from_glib_none(parameter_type),
108 property_name,
109 ))
110 } else {
111 None
112 }
113 }
114 }
115}
116
117impl std::iter::FusedIterator for WidgetActionIter {}
118
119#[cfg(feature = "v4_10")]
120#[doc(hidden)]
121pub trait WidgetImplBounds:
122 IsA<Widget> + IsA<crate::Accessible> + IsA<Buildable> + IsA<ConstraintTarget>
123{
124}
125#[cfg(feature = "v4_10")]
126impl<T: IsA<Widget> + IsA<crate::Accessible> + IsA<Buildable> + IsA<ConstraintTarget>>
127 WidgetImplBounds for T
128{
129}
130
131#[cfg(not(feature = "v4_10"))]
132#[doc(hidden)]
133pub trait WidgetImplBounds: IsA<Widget> + IsA<Buildable> + IsA<ConstraintTarget> {}
134#[cfg(not(feature = "v4_10"))]
135impl<T: IsA<Widget> + IsA<Buildable> + IsA<ConstraintTarget>> WidgetImplBounds for T {}
136
137pub trait WidgetImpl: ObjectImpl + ObjectSubclass<Type: WidgetImplBounds> {
138 fn compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
141 self.parent_compute_expand(hexpand, vexpand)
142 }
143
144 fn contains(&self, x: f64, y: f64) -> bool {
157 self.parent_contains(x, y)
158 }
159
160 fn direction_changed(&self, previous_direction: TextDirection) {
163 self.parent_direction_changed(previous_direction)
164 }
165
166 fn focus(&self, direction_type: DirectionType) -> bool {
168 self.parent_focus(direction_type)
169 }
170
171 #[doc(alias = "get_request_mode")]
183 fn request_mode(&self) -> SizeRequestMode {
184 self.parent_request_mode()
185 }
186
187 fn grab_focus(&self) -> bool {
201 self.parent_grab_focus()
202 }
203
204 #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
212 #[allow(deprecated)]
213 fn hide(&self) {
214 self.parent_hide()
215 }
216
217 fn keynav_failed(&self, direction_type: DirectionType) -> bool {
254 self.parent_keynav_failed(direction_type)
255 }
256
257 fn map(&self) {
261 self.parent_map()
262 }
263
264 fn measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
298 self.parent_measure(orientation, for_size)
299 }
300
301 fn mnemonic_activate(&self, group_cycling: bool) -> bool {
309 self.parent_mnemonic_activate(group_cycling)
310 }
311
312 fn move_focus(&self, direction_type: DirectionType) {
314 self.parent_move_focus(direction_type)
315 }
316
317 fn query_tooltip(&self, x: i32, y: i32, keyboard_tooltip: bool, tooltip: &Tooltip) -> bool {
321 self.parent_query_tooltip(x, y, keyboard_tooltip, tooltip)
322 }
323
324 fn realize(&self) {
341 self.parent_realize()
342 }
343
344 fn root(&self) {
347 self.parent_root()
348 }
349
350 fn set_focus_child(&self, child: Option<&Widget>) {
359 self.parent_set_focus_child(child)
360 }
361
362 #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
377 #[allow(deprecated)]
378 fn show(&self) {
379 self.parent_show()
380 }
381
382 fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
385 self.parent_size_allocate(width, height, baseline)
386 }
387
388 fn snapshot(&self, snapshot: &Snapshot) {
390 self.parent_snapshot(snapshot)
391 }
392
393 fn state_flags_changed(&self, state_flags: &StateFlags) {
396 self.parent_state_flags_changed(state_flags)
397 }
398
399 fn system_setting_changed(&self, settings: &SystemSetting) {
401 self.parent_system_setting_changed(settings)
402 }
403
404 fn unmap(&self) {
408 self.parent_unmap()
409 }
410
411 fn unrealize(&self) {
417 self.parent_unrealize()
418 }
419
420 fn unroot(&self) {
423 self.parent_unroot()
424 }
425}
426
427pub trait WidgetImplExt: WidgetImpl {
428 fn parent_compute_expand(&self, hexpand: &mut bool, vexpand: &mut bool) {
429 unsafe {
430 let data = Self::type_data();
431 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
432 if let Some(f) = (*parent_class).compute_expand {
433 let mut hexpand_glib = hexpand.into_glib();
434 let mut vexpand_glib = vexpand.into_glib();
435 f(
436 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
437 &mut hexpand_glib,
438 &mut vexpand_glib,
439 );
440 *hexpand = from_glib(hexpand_glib);
441 *vexpand = from_glib(vexpand_glib);
442 }
443 }
444 }
445
446 fn parent_contains(&self, x: f64, y: f64) -> bool {
448 unsafe {
449 let data = Self::type_data();
450 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
451 if let Some(f) = (*parent_class).contains {
452 from_glib(f(
453 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
454 x,
455 y,
456 ))
457 } else {
458 false
459 }
460 }
461 }
462
463 fn parent_direction_changed(&self, previous_direction: TextDirection) {
464 unsafe {
465 let data = Self::type_data();
466 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
467 if let Some(f) = (*parent_class).direction_changed {
468 f(
469 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
470 previous_direction.into_glib(),
471 )
472 }
473 }
474 }
475
476 fn parent_focus(&self, direction_type: DirectionType) -> bool {
478 unsafe {
479 let data = Self::type_data();
480 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
481 if let Some(f) = (*parent_class).focus {
482 from_glib(f(
483 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
484 direction_type.into_glib(),
485 ))
486 } else {
487 false
488 }
489 }
490 }
491
492 fn parent_request_mode(&self) -> SizeRequestMode {
493 unsafe {
494 let data = Self::type_data();
495 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
496 let f = (*parent_class)
497 .get_request_mode
498 .expect("No parent class impl for \"get_request_mode\"");
499 from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
500 }
501 }
502
503 fn parent_grab_focus(&self) -> bool {
505 unsafe {
506 let data = Self::type_data();
507 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
508 if let Some(f) = (*parent_class).grab_focus {
509 from_glib(f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0))
510 } else {
511 false
512 }
513 }
514 }
515
516 #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
517 #[allow(deprecated)]
518 fn parent_hide(&self) {
519 unsafe {
520 let data = Self::type_data();
521 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
522 if let Some(f) = (*parent_class).hide {
523 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
524 }
525 }
526 }
527
528 fn parent_keynav_failed(&self, direction_type: DirectionType) -> bool {
532 unsafe {
533 let data = Self::type_data();
534 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
535 if let Some(f) = (*parent_class).keynav_failed {
536 from_glib(f(
537 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
538 direction_type.into_glib(),
539 ))
540 } else {
541 false
542 }
543 }
544 }
545
546 fn parent_map(&self) {
547 unsafe {
548 let data = Self::type_data();
549 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
550 if let Some(f) = (*parent_class).map {
551 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
552 }
553 }
554 }
555
556 fn parent_measure(&self, orientation: Orientation, for_size: i32) -> (i32, i32, i32, i32) {
557 unsafe {
558 let data = Self::type_data();
559 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
560
561 let f = (*parent_class)
562 .measure
563 .expect("No parent class impl for \"measure\"");
564
565 let mut min = 0;
566 let mut nat = 0;
567 let mut min_base = -1;
568 let mut nat_base = -1;
569 f(
570 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
571 orientation.into_glib(),
572 for_size,
573 &mut min,
574 &mut nat,
575 &mut min_base,
576 &mut nat_base,
577 );
578 (min, nat, min_base, nat_base)
579 }
580 }
581
582 fn parent_mnemonic_activate(&self, group_cycling: bool) -> bool {
584 unsafe {
585 let data = Self::type_data();
586 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
587 if let Some(f) = (*parent_class).mnemonic_activate {
588 from_glib(f(
589 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
590 group_cycling.into_glib(),
591 ))
592 } else {
593 false
594 }
595 }
596 }
597
598 fn parent_move_focus(&self, direction_type: DirectionType) {
599 unsafe {
600 let data = Self::type_data();
601 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
602 if let Some(f) = (*parent_class).move_focus {
603 f(
604 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
605 direction_type.into_glib(),
606 )
607 }
608 }
609 }
610
611 fn parent_query_tooltip(
612 &self,
613 x: i32,
614 y: i32,
615 keyboard_tooltip: bool,
616 tooltip: &Tooltip,
617 ) -> bool {
618 unsafe {
619 let data = Self::type_data();
620 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
621 if let Some(f) = (*parent_class).query_tooltip {
622 from_glib(f(
623 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
624 x,
625 y,
626 keyboard_tooltip.into_glib(),
627 tooltip.to_glib_none().0,
628 ))
629 } else {
630 false
631 }
632 }
633 }
634
635 fn parent_realize(&self) {
636 unsafe {
637 let data = Self::type_data();
638 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
639 if let Some(f) = (*parent_class).realize {
640 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
641 }
642 }
643 }
644
645 fn parent_root(&self) {
646 unsafe {
647 let data = Self::type_data();
648 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
649 if let Some(f) = (*parent_class).root {
650 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
651 }
652 }
653 }
654
655 fn parent_set_focus_child(&self, child: Option<&Widget>) {
656 unsafe {
657 let data = Self::type_data();
658 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
659 if let Some(f) = (*parent_class).set_focus_child {
660 f(
661 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
662 child.to_glib_none().0,
663 )
664 }
665 }
666 }
667
668 #[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
669 #[allow(deprecated)]
670 fn parent_show(&self) {
671 unsafe {
672 let data = Self::type_data();
673 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
674 if let Some(f) = (*parent_class).show {
675 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
676 }
677 }
678 }
679
680 fn parent_size_allocate(&self, width: i32, height: i32, baseline: i32) {
681 unsafe {
682 let data = Self::type_data();
683 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
684 if let Some(f) = (*parent_class).size_allocate {
685 f(
686 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
687 width,
688 height,
689 baseline,
690 )
691 }
692 }
693 }
694
695 fn parent_snapshot(&self, snapshot: &Snapshot) {
696 unsafe {
697 let data = Self::type_data();
698 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
699 if let Some(f) = (*parent_class).snapshot {
700 f(
701 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
702 snapshot.to_glib_none().0,
703 )
704 }
705 }
706 }
707
708 fn parent_state_flags_changed(&self, state_flags: &StateFlags) {
709 unsafe {
710 let data = Self::type_data();
711 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
712 if let Some(f) = (*parent_class).state_flags_changed {
713 f(
714 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
715 state_flags.into_glib(),
716 )
717 }
718 }
719 }
720
721 fn parent_system_setting_changed(&self, settings: &SystemSetting) {
722 unsafe {
723 let data = Self::type_data();
724 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
725 if let Some(f) = (*parent_class).system_setting_changed {
726 f(
727 self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0,
728 settings.into_glib(),
729 )
730 }
731 }
732 }
733
734 fn parent_unmap(&self) {
735 unsafe {
736 let data = Self::type_data();
737 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
738 if let Some(f) = (*parent_class).unmap {
739 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
740 }
741 }
742 }
743
744 fn parent_unrealize(&self) {
745 unsafe {
746 let data = Self::type_data();
747 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
748 if let Some(f) = (*parent_class).unrealize {
749 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
750 }
751 }
752 }
753
754 fn parent_unroot(&self) {
755 unsafe {
756 let data = Self::type_data();
757 let parent_class = data.as_ref().parent_class() as *mut ffi::GtkWidgetClass;
758 if let Some(f) = (*parent_class).unroot {
759 f(self.obj().unsafe_cast_ref::<Widget>().to_glib_none().0)
760 }
761 }
762 }
763}
764
765impl<T: WidgetImpl> WidgetImplExt for T {}
766
767unsafe impl<T: WidgetImpl> IsSubclassable<T> for Widget {
768 fn class_init(class: &mut ::glib::Class<Self>) {
769 Self::parent_class_init::<T>(class);
770
771 assert_initialized_main_thread!();
772
773 let klass = class.as_mut();
774 unsafe {
775 let mut data = T::type_data();
776 let data = data.as_mut();
777 data.set_class_data(<T as ObjectSubclassType>::type_(), Internal::default());
779 }
780
781 klass.compute_expand = Some(widget_compute_expand::<T>);
782 klass.contains = Some(widget_contains::<T>);
783 klass.direction_changed = Some(widget_direction_changed::<T>);
784 klass.focus = Some(widget_focus::<T>);
785 klass.get_request_mode = Some(widget_get_request_mode::<T>);
786 klass.grab_focus = Some(widget_grab_focus::<T>);
787 klass.hide = Some(widget_hide::<T>);
788 klass.keynav_failed = Some(widget_keynav_failed::<T>);
789 klass.map = Some(widget_map::<T>);
790 klass.measure = Some(widget_measure::<T>);
791 klass.mnemonic_activate = Some(widget_mnemonic_activate::<T>);
792 klass.move_focus = Some(widget_move_focus::<T>);
793 klass.query_tooltip = Some(widget_query_tooltip::<T>);
794 klass.realize = Some(widget_realize::<T>);
795 klass.root = Some(widget_root::<T>);
796 klass.set_focus_child = Some(widget_set_focus_child::<T>);
797 klass.show = Some(widget_show::<T>);
798 klass.size_allocate = Some(widget_size_allocate::<T>);
799 klass.snapshot = Some(widget_snapshot::<T>);
800 klass.state_flags_changed = Some(widget_state_flags_changed::<T>);
801 klass.system_setting_changed = Some(widget_system_setting_changed::<T>);
802 klass.unmap = Some(widget_unmap::<T>);
803 klass.unrealize = Some(widget_unrealize::<T>);
804 klass.unroot = Some(widget_unroot::<T>);
805 }
806}
807
808unsafe extern "C" fn widget_compute_expand<T: WidgetImpl>(
809 ptr: *mut ffi::GtkWidget,
810 hexpand_ptr: *mut glib::ffi::gboolean,
811 vexpand_ptr: *mut glib::ffi::gboolean,
812) {
813 unsafe {
814 let instance = &*(ptr as *mut T::Instance);
815 let imp = instance.imp();
816
817 let widget = imp.obj();
818 let widget = widget.unsafe_cast_ref::<Widget>();
819 let mut hexpand: bool = if widget.is_hexpand_set() {
820 widget.hexpands()
821 } else {
822 from_glib(*hexpand_ptr)
823 };
824 let mut vexpand: bool = if widget.is_vexpand_set() {
825 widget.vexpands()
826 } else {
827 from_glib(*vexpand_ptr)
828 };
829
830 imp.compute_expand(&mut hexpand, &mut vexpand);
831
832 *hexpand_ptr = hexpand.into_glib();
833 *vexpand_ptr = vexpand.into_glib();
834 }
835}
836
837unsafe extern "C" fn widget_contains<T: WidgetImpl>(
838 ptr: *mut ffi::GtkWidget,
839 x: f64,
840 y: f64,
841) -> glib::ffi::gboolean {
842 unsafe {
843 let instance = &*(ptr as *mut T::Instance);
844 let imp = instance.imp();
845
846 imp.contains(x, y).into_glib()
847 }
848}
849
850unsafe extern "C" fn widget_direction_changed<T: WidgetImpl>(
851 ptr: *mut ffi::GtkWidget,
852 direction_ptr: ffi::GtkTextDirection,
853) {
854 unsafe {
855 let instance = &*(ptr as *mut T::Instance);
856 let imp = instance.imp();
857 let direction_wrap = from_glib(direction_ptr);
858
859 imp.direction_changed(direction_wrap)
860 }
861}
862
863unsafe extern "C" fn widget_focus<T: WidgetImpl>(
864 ptr: *mut ffi::GtkWidget,
865 direction_type_ptr: ffi::GtkDirectionType,
866) -> glib::ffi::gboolean {
867 unsafe {
868 let instance = &*(ptr as *mut T::Instance);
869 let imp = instance.imp();
870 let direction_type = from_glib(direction_type_ptr);
871
872 imp.focus(direction_type).into_glib()
873 }
874}
875
876unsafe extern "C" fn widget_get_request_mode<T: WidgetImpl>(
877 ptr: *mut ffi::GtkWidget,
878) -> ffi::GtkSizeRequestMode {
879 unsafe {
880 let instance = &*(ptr as *mut T::Instance);
881 let imp = instance.imp();
882
883 imp.request_mode().into_glib()
884 }
885}
886
887unsafe extern "C" fn widget_grab_focus<T: WidgetImpl>(
888 ptr: *mut ffi::GtkWidget,
889) -> glib::ffi::gboolean {
890 unsafe {
891 let instance = &*(ptr as *mut T::Instance);
892 let imp = instance.imp();
893
894 imp.grab_focus().into_glib()
895 }
896}
897
898unsafe extern "C" fn widget_hide<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
899 unsafe {
900 let instance = &*(ptr as *mut T::Instance);
901 let imp = instance.imp();
902
903 imp.hide()
904 }
905}
906
907unsafe extern "C" fn widget_keynav_failed<T: WidgetImpl>(
908 ptr: *mut ffi::GtkWidget,
909 direction_type_ptr: ffi::GtkDirectionType,
910) -> glib::ffi::gboolean {
911 unsafe {
912 let instance = &*(ptr as *mut T::Instance);
913 let imp = instance.imp();
914 let direction_type = from_glib(direction_type_ptr);
915
916 imp.keynav_failed(direction_type).into_glib()
917 }
918}
919
920unsafe extern "C" fn widget_map<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
921 unsafe {
922 let instance = &*(ptr as *mut T::Instance);
923 let imp = instance.imp();
924
925 imp.map()
926 }
927}
928
929unsafe extern "C" fn widget_measure<T: WidgetImpl>(
930 ptr: *mut ffi::GtkWidget,
931 orientation_ptr: ffi::GtkOrientation,
932 for_size: i32,
933 min_ptr: *mut libc::c_int,
934 nat_ptr: *mut libc::c_int,
935 min_base_ptr: *mut libc::c_int,
936 nat_base_ptr: *mut libc::c_int,
937) {
938 unsafe {
939 let instance = &*(ptr as *mut T::Instance);
940 let imp = instance.imp();
941 let orientation = from_glib(orientation_ptr);
942 let (min, nat, min_base, nat_base) = imp.measure(orientation, for_size);
943 if !min_ptr.is_null() {
944 *min_ptr = min;
945 }
946 if !nat_ptr.is_null() {
947 *nat_ptr = nat;
948 }
949 if !min_base_ptr.is_null() {
950 *min_base_ptr = min_base;
951 }
952 if !nat_base_ptr.is_null() {
953 *nat_base_ptr = nat_base;
954 }
955 }
956}
957
958unsafe extern "C" fn widget_mnemonic_activate<T: WidgetImpl>(
959 ptr: *mut ffi::GtkWidget,
960 group_cycling_ptr: glib::ffi::gboolean,
961) -> glib::ffi::gboolean {
962 unsafe {
963 let instance = &*(ptr as *mut T::Instance);
964 let imp = instance.imp();
965 let group_cycling: bool = from_glib(group_cycling_ptr);
966
967 imp.mnemonic_activate(group_cycling).into_glib()
968 }
969}
970
971unsafe extern "C" fn widget_move_focus<T: WidgetImpl>(
972 ptr: *mut ffi::GtkWidget,
973 direction_type_ptr: ffi::GtkDirectionType,
974) {
975 unsafe {
976 let instance = &*(ptr as *mut T::Instance);
977 let imp = instance.imp();
978 let direction_type = from_glib(direction_type_ptr);
979
980 imp.move_focus(direction_type)
981 }
982}
983
984unsafe extern "C" fn widget_query_tooltip<T: WidgetImpl>(
985 ptr: *mut ffi::GtkWidget,
986 x: i32,
987 y: i32,
988 keyboard_tooltip_ptr: glib::ffi::gboolean,
989 tooltip_ptr: *mut ffi::GtkTooltip,
990) -> glib::ffi::gboolean {
991 unsafe {
992 let instance = &*(ptr as *mut T::Instance);
993 let imp = instance.imp();
994
995 let keyboard_tooltip: bool = from_glib(keyboard_tooltip_ptr);
996 let tooltip = from_glib_borrow(tooltip_ptr);
997
998 imp.query_tooltip(x, y, keyboard_tooltip, &tooltip)
999 .into_glib()
1000 }
1001}
1002
1003unsafe extern "C" fn widget_realize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1004 unsafe {
1005 let instance = &*(ptr as *mut T::Instance);
1006 let imp = instance.imp();
1007
1008 imp.realize()
1009 }
1010}
1011
1012unsafe extern "C" fn widget_root<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1013 unsafe {
1014 let instance = &*(ptr as *mut T::Instance);
1015 let imp = instance.imp();
1016
1017 imp.root()
1018 }
1019}
1020
1021unsafe extern "C" fn widget_set_focus_child<T: WidgetImpl>(
1022 ptr: *mut ffi::GtkWidget,
1023 child_ptr: *mut ffi::GtkWidget,
1024) {
1025 unsafe {
1026 let instance = &*(ptr as *mut T::Instance);
1027 let imp = instance.imp();
1028 let child: Borrowed<Option<Widget>> = from_glib_borrow(child_ptr);
1029
1030 imp.set_focus_child(child.as_ref().as_ref())
1031 }
1032}
1033
1034unsafe extern "C" fn widget_show<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1035 unsafe {
1036 let instance = &*(ptr as *mut T::Instance);
1037 let imp = instance.imp();
1038
1039 imp.show()
1040 }
1041}
1042
1043unsafe extern "C" fn widget_size_allocate<T: WidgetImpl>(
1044 ptr: *mut ffi::GtkWidget,
1045 width: i32,
1046 height: i32,
1047 baseline: i32,
1048) {
1049 unsafe {
1050 let instance = &*(ptr as *mut T::Instance);
1051 let imp = instance.imp();
1052
1053 imp.size_allocate(width, height, baseline)
1054 }
1055}
1056
1057unsafe extern "C" fn widget_snapshot<T: WidgetImpl>(
1058 ptr: *mut ffi::GtkWidget,
1059 snapshot_ptr: *mut ffi::GtkSnapshot,
1060) {
1061 unsafe {
1062 let instance = &*(ptr as *mut T::Instance);
1063 let imp = instance.imp();
1064 let snapshot = from_glib_borrow(snapshot_ptr);
1065
1066 imp.snapshot(&snapshot)
1067 }
1068}
1069
1070unsafe extern "C" fn widget_state_flags_changed<T: WidgetImpl>(
1071 ptr: *mut ffi::GtkWidget,
1072 state_flags_ptr: ffi::GtkStateFlags,
1073) {
1074 unsafe {
1075 let instance = &*(ptr as *mut T::Instance);
1076 let imp = instance.imp();
1077 let state_flags = from_glib(state_flags_ptr);
1078
1079 imp.state_flags_changed(&state_flags)
1080 }
1081}
1082
1083unsafe extern "C" fn widget_system_setting_changed<T: WidgetImpl>(
1084 ptr: *mut ffi::GtkWidget,
1085 settings_ptr: ffi::GtkSystemSetting,
1086) {
1087 unsafe {
1088 let instance = &*(ptr as *mut T::Instance);
1089 let imp = instance.imp();
1090 let settings = from_glib(settings_ptr);
1091
1092 imp.system_setting_changed(&settings)
1093 }
1094}
1095
1096unsafe extern "C" fn widget_unmap<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1097 unsafe {
1098 let instance = &*(ptr as *mut T::Instance);
1099 let imp = instance.imp();
1100
1101 imp.unmap()
1102 }
1103}
1104
1105unsafe extern "C" fn widget_unrealize<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1106 unsafe {
1107 let instance = &*(ptr as *mut T::Instance);
1108 let imp = instance.imp();
1109
1110 imp.unrealize()
1111 }
1112}
1113
1114unsafe extern "C" fn widget_unroot<T: WidgetImpl>(ptr: *mut ffi::GtkWidget) {
1115 unsafe {
1116 let instance = &*(ptr as *mut T::Instance);
1117 let imp = instance.imp();
1118
1119 imp.unroot()
1120 }
1121}
1122
1123#[allow(clippy::missing_safety_doc)]
1124pub unsafe trait WidgetClassExt: ClassStruct {
1125 #[doc(alias = "gtk_widget_class_set_template")]
1126 fn set_template_bytes(&mut self, template: &glib::Bytes) {
1127 unsafe {
1128 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1129 ffi::gtk_widget_class_set_template(widget_class, template.to_glib_none().0);
1130 }
1131 }
1132
1133 fn set_template(&mut self, template: &[u8]) {
1144 let template_bytes = glib::Bytes::from(template);
1145 self.set_template_bytes(&template_bytes);
1146 }
1147
1148 fn set_template_static(&mut self, template: &'static [u8]) {
1149 let template_bytes = glib::Bytes::from_static(template);
1150 self.set_template_bytes(&template_bytes);
1151 }
1152
1153 #[doc(alias = "gtk_widget_class_set_template_from_resource")]
1162 fn set_template_from_resource(&mut self, resource_name: &str) {
1163 unsafe {
1164 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1165 ffi::gtk_widget_class_set_template_from_resource(
1166 widget_class,
1167 resource_name.to_glib_none().0,
1168 );
1169 }
1170 }
1171
1172 fn install_action_async<Fut, F>(
1173 &mut self,
1174 action_name: &str,
1175 parameter_type: Option<&glib::VariantTy>,
1176 activate: F,
1177 ) where
1178 F: Fn(
1179 <<Self as ClassStruct>::Type as ObjectSubclass>::Type,
1180 String,
1181 Option<Variant>,
1182 ) -> Fut
1183 + 'static
1184 + Clone,
1185 Fut: Future<Output = ()>,
1186 {
1187 self.install_action(
1188 action_name,
1189 parameter_type,
1190 move |this, action_name, parameter_type| {
1191 let ctx = glib::MainContext::default();
1192 let action_name = action_name.to_owned();
1193 let parameter_type = parameter_type.map(ToOwned::to_owned);
1194 ctx.spawn_local(glib::clone!(
1195 #[strong]
1196 this,
1197 #[strong]
1198 action_name,
1199 #[strong]
1200 parameter_type,
1201 #[strong]
1202 activate,
1203 async move {
1204 activate(this, action_name, parameter_type).await;
1205 }
1206 ));
1207 },
1208 );
1209 }
1210
1211 #[doc(alias = "gtk_widget_class_install_action")]
1225 fn install_action<F>(
1226 &mut self,
1227 action_name: &str,
1228 parameter_type: Option<&glib::VariantTy>,
1229 activate: F,
1230 ) where
1231 F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
1232 + 'static,
1233 {
1234 unsafe {
1235 let mut data = <Self::Type as ObjectSubclassType>::type_data();
1238 let data = data.as_mut();
1239
1240 let f: Box_<F> = Box_::new(activate);
1241
1242 let internal = data
1243 .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1244 .expect("Something bad happened at class_init, the internal class_data is missing");
1245 let callback_ptr = Box_::into_raw(f) as glib::ffi::gpointer;
1246 internal
1247 .actions
1248 .insert(action_name.to_string(), callback_ptr);
1249
1250 unsafe extern "C" fn activate_trampoline<F, S>(
1251 this: *mut ffi::GtkWidget,
1252 action_name: *const libc::c_char,
1253 parameter: *mut glib::ffi::GVariant,
1254 ) where
1255 S: ClassStruct,
1256 <S as ClassStruct>::Type: ObjectSubclass,
1257 F: Fn(&<<S as ClassStruct>::Type as ObjectSubclass>::Type, &str, Option<&Variant>)
1258 + 'static,
1259 {
1260 unsafe {
1261 let action_name = GString::from_glib_borrow(action_name);
1262
1263 let data = <S::Type as ObjectSubclassType>::type_data();
1264 let internal = data
1265 .as_ref()
1266 .class_data::<Internal>(<S::Type as ObjectSubclassType>::type_())
1267 .unwrap();
1268 let activate_callback = *internal
1269 .actions
1270 .get(action_name.as_str())
1271 .unwrap_or_else(|| {
1272 panic!("Action name '{}' was not found", action_name.as_str());
1273 });
1274
1275 let widget = Widget::from_glib_borrow(this);
1276
1277 let f: &F = &*(activate_callback as *const F);
1278 f(
1279 widget.unsafe_cast_ref(),
1280 &action_name,
1281 Option::<Variant>::from_glib_borrow(parameter)
1282 .as_ref()
1283 .as_ref(),
1284 )
1285 }
1286 }
1287 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1288 let callback = activate_trampoline::<F, Self>;
1289 ffi::gtk_widget_class_install_action(
1290 widget_class,
1291 action_name.to_glib_none().0,
1292 parameter_type.map(|p| p.as_str()).to_glib_none().0,
1293 Some(callback),
1294 );
1295 }
1296 }
1297
1298 #[doc(alias = "gtk_widget_class_query_action")]
1326 fn query_action(&self) -> WidgetActionIter {
1327 let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1328 WidgetActionIter::new(widget_class)
1329 }
1330
1331 #[doc(alias = "gtk_widget_class_set_template_scope")]
1341 fn set_template_scope<S: IsA<BuilderScope>>(&mut self, scope: &S) {
1342 unsafe {
1343 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1344 ffi::gtk_widget_class_set_template_scope(widget_class, scope.as_ref().to_glib_none().0);
1345 }
1346 }
1347
1348 #[doc(alias = "gtk_widget_class_add_binding")]
1373 fn add_binding<
1374 F: Fn(&<<Self as ClassStruct>::Type as ObjectSubclass>::Type) -> glib::Propagation + 'static,
1375 >(
1376 &mut self,
1377 keyval: gdk::Key,
1378 mods: gdk::ModifierType,
1379 callback: F,
1380 ) {
1381 let shortcut = crate::Shortcut::new(
1382 Some(crate::KeyvalTrigger::new(keyval, mods)),
1383 Some(crate::CallbackAction::new(
1384 move |widget, _| -> glib::Propagation {
1385 unsafe { callback(widget.unsafe_cast_ref()) }
1386 },
1387 )),
1388 );
1389 self.add_shortcut(&shortcut);
1390 }
1391
1392 #[doc(alias = "gtk_widget_class_add_binding_action")]
1415 fn add_binding_action(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, action_name: &str) {
1416 let shortcut = crate::Shortcut::new(
1417 Some(crate::KeyvalTrigger::new(keyval, mods)),
1418 Some(crate::NamedAction::new(action_name)),
1419 );
1420 self.add_shortcut(&shortcut);
1421 }
1422
1423 #[doc(alias = "gtk_widget_class_add_binding_signal")]
1446 fn add_binding_signal(&mut self, keyval: gdk::Key, mods: gdk::ModifierType, signal_name: &str) {
1447 let type_ = <Self::Type as ObjectSubclassType>::type_();
1448 assert!(
1449 SignalId::lookup(signal_name, type_).is_some(),
1450 "Signal '{signal_name}' doesn't exists for type '{type_}'",
1451 );
1452
1453 let shortcut = crate::Shortcut::new(
1454 Some(crate::KeyvalTrigger::new(keyval, mods)),
1455 Some(crate::SignalAction::new(signal_name)),
1456 );
1457 self.add_shortcut(&shortcut);
1458 }
1459
1460 #[doc(alias = "gtk_widget_class_add_shortcut")]
1473 fn add_shortcut(&mut self, shortcut: &Shortcut) {
1474 unsafe {
1475 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1476 ffi::gtk_widget_class_add_shortcut(widget_class, shortcut.to_glib_none().0);
1477 }
1478 }
1479
1480 #[doc(alias = "gtk_widget_class_install_property_action")]
1501 fn install_property_action(&mut self, action_name: &str, property_name: &str) {
1502 unsafe {
1503 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1504 ffi::gtk_widget_class_install_property_action(
1505 widget_class,
1506 action_name.to_glib_none().0,
1507 property_name.to_glib_none().0,
1508 );
1509 }
1510 }
1511
1512 #[doc(alias = "gtk_widget_class_get_activate_signal")]
1522 #[doc(alias = "get_activate_signal")]
1523 fn activate_signal(&self) -> Option<SignalId> {
1524 unsafe {
1525 let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1526 let signal_id = ffi::gtk_widget_class_get_activate_signal(widget_class);
1527 if signal_id == 0 {
1528 None
1529 } else {
1530 Some(from_glib(signal_id))
1531 }
1532 }
1533 }
1534
1535 #[doc(alias = "gtk_widget_class_set_activate_signal")]
1544 fn set_activate_signal(&mut self, signal_id: SignalId) {
1545 unsafe {
1546 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1547 ffi::gtk_widget_class_set_activate_signal(widget_class, signal_id.into_glib())
1548 }
1549 }
1550
1551 #[doc(alias = "gtk_widget_class_set_activate_signal_from_name")]
1562 fn set_activate_signal_from_name(&mut self, signal_name: &str) {
1563 let type_ = <Self::Type as ObjectSubclassType>::type_();
1564 assert!(
1565 SignalId::lookup(signal_name, type_).is_some(),
1566 "Signal '{signal_name}' doesn't exists for type '{type_}'",
1567 );
1568
1569 unsafe {
1570 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1571 ffi::gtk_widget_class_set_activate_signal_from_name(
1572 widget_class,
1573 signal_name.to_glib_none().0,
1574 );
1575 }
1576 }
1577
1578 #[doc(alias = "gtk_widget_class_set_layout_manager_type")]
1589 fn set_layout_manager_type<T: IsA<LayoutManager>>(&mut self) {
1590 unsafe {
1591 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1592 ffi::gtk_widget_class_set_layout_manager_type(
1593 widget_class,
1594 T::static_type().into_glib(),
1595 );
1596 }
1597 }
1598
1599 #[doc(alias = "gtk_widget_class_get_layout_manager_type")]
1608 #[doc(alias = "get_layout_manager_type")]
1609 fn layout_manager_type(&self) -> glib::Type {
1610 unsafe {
1611 let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1612 from_glib(ffi::gtk_widget_class_get_layout_manager_type(widget_class))
1613 }
1614 }
1615
1616 #[doc(alias = "gtk_widget_class_set_css_name")]
1624 fn set_css_name(&mut self, name: &str) {
1625 unsafe {
1626 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1627 ffi::gtk_widget_class_set_css_name(widget_class, name.to_glib_none().0);
1628 }
1629 }
1630
1631 #[doc(alias = "gtk_widget_class_get_css_name")]
1639 #[doc(alias = "get_css_name")]
1640 fn css_name(&self) -> glib::GString {
1641 unsafe {
1642 let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1643 from_glib_none(ffi::gtk_widget_class_get_css_name(widget_class))
1644 }
1645 }
1646
1647 #[doc(alias = "gtk_widget_class_set_accessible_role")]
1654 fn set_accessible_role(&mut self, role: AccessibleRole) {
1655 unsafe {
1656 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1657 ffi::gtk_widget_class_set_accessible_role(widget_class, role.into_glib());
1658 }
1659 }
1660
1661 #[doc(alias = "gtk_widget_class_get_accessible_role")]
1672 #[doc(alias = "get_accessible_role")]
1673 fn accessible_role(&self) -> AccessibleRole {
1674 unsafe {
1675 let widget_class = self as *const _ as *mut ffi::GtkWidgetClass;
1676 from_glib(ffi::gtk_widget_class_get_accessible_role(widget_class))
1677 }
1678 }
1679
1680 #[allow(clippy::missing_safety_doc)]
1681 #[doc(alias = "gtk_widget_class_bind_template_child_full")]
1682 unsafe fn bind_template_child_with_offset<T>(
1683 &mut self,
1684 name: &str,
1685 internal: bool,
1686 offset: field_offset::FieldOffset<Self::Type, TemplateChild<T>>,
1687 ) where
1688 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1689 {
1690 unsafe {
1691 let widget_class = self as *mut _ as *mut ffi::GtkWidgetClass;
1692 let private_offset = <Self::Type as ObjectSubclassType>::type_data()
1693 .as_ref()
1694 .impl_offset();
1695 ffi::gtk_widget_class_bind_template_child_full(
1696 widget_class,
1697 name.to_glib_none().0,
1698 internal.into_glib(),
1699 private_offset + (offset.get_byte_offset() as isize),
1700 )
1701 }
1702 }
1703
1704 fn rust_template_scope(&mut self) -> BuilderRustScope {
1705 assert_initialized_main_thread!();
1706 unsafe {
1707 let mut data = <Self::Type as ObjectSubclassType>::type_data();
1708 let internal = data
1709 .as_mut()
1710 .class_data_mut::<Internal>(<Self::Type as ObjectSubclassType>::type_())
1711 .expect("Something bad happened at class_init, the internal class_data is missing");
1712 let scope = internal.scope.get_or_insert_with(|| {
1713 let scope = BuilderRustScope::new();
1714 self.set_template_scope(&scope);
1715 scope.into_glib_ptr()
1716 });
1717 from_glib_none(*scope)
1718 }
1719 }
1720}
1721
1722unsafe impl<T: ClassStruct> WidgetClassExt for T where T::Type: WidgetImpl {}
1723
1724#[derive(Debug, PartialEq, Eq)]
1725#[repr(transparent)]
1726pub struct TemplateChild<T>
1727where
1728 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1729{
1730 ptr: *mut <T as ObjectType>::GlibType,
1731}
1732
1733impl<T: Property> Property for TemplateChild<T>
1734where
1735 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1736{
1737 type Value = T::Value;
1738}
1739
1740impl<T> Default for TemplateChild<T>
1741where
1742 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1743{
1744 fn default() -> Self {
1745 T::static_type();
1746
1747 Self {
1748 ptr: std::ptr::null_mut(),
1749 }
1750 }
1751}
1752
1753impl<T> PropertyGet for TemplateChild<T>
1754where
1755 T: Property + ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1756{
1757 type Value = T;
1758
1759 fn get<R, F: Fn(&Self::Value) -> R>(&self, f: F) -> R {
1760 f(&self.get())
1761 }
1762}
1763
1764impl<T> std::ops::Deref for TemplateChild<T>
1765where
1766 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1767{
1768 type Target = T;
1769
1770 #[inline]
1771 fn deref(&self) -> &Self::Target {
1772 unsafe {
1773 if !self.is_bound() {
1774 let name = Self::name();
1775 panic!(
1776 "Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute."
1777 );
1778 }
1779 &*(&self.ptr as *const _ as *const T)
1780 }
1781 }
1782}
1783
1784impl<T> Downgrade for TemplateChild<T>
1785where
1786 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType> + Downgrade,
1787{
1788 type Weak = T::Weak;
1789
1790 fn downgrade(&self) -> Self::Weak {
1791 T::downgrade(&self.get())
1792 }
1793}
1794
1795impl<T> TemplateChild<T>
1796where
1797 T: ObjectType + FromGlibPtrNone<*mut <T as ObjectType>::GlibType>,
1798{
1799 pub(crate) fn name<'a>() -> &'a str {
1800 T::static_type().name()
1801 }
1802
1803 #[track_caller]
1804 pub fn get(&self) -> T {
1805 self.try_get()
1806 .unwrap_or_else(|| {
1807 let name = Self::name();
1808 panic!("Failed to retrieve template child. Please check that all fields of type `{name}` have been bound and have a #[template_child] attribute.");
1809 })
1810 }
1811
1812 pub fn is_bound(&self) -> bool {
1816 !self.ptr.is_null()
1817 }
1818
1819 pub fn try_get(&self) -> Option<T> {
1822 unsafe { Option::<T>::from_glib_none(self.ptr) }
1823 }
1824}
1825
1826pub trait CompositeTemplate: WidgetImpl {
1832 fn bind_template(klass: &mut Self::Class);
1833 fn check_template_children(widget: &<Self as ObjectSubclass>::Type);
1834}
1835
1836pub trait CompositeTemplateClass {
1841 fn bind_template(&mut self);
1845}
1846
1847impl<T, U> CompositeTemplateClass for T
1848where
1849 T: ClassStruct<Type = U>,
1850 U: ObjectSubclass<Class = T> + CompositeTemplate,
1851{
1852 fn bind_template(&mut self) {
1853 <U as CompositeTemplate>::bind_template(self);
1854 }
1855}
1856
1857pub type TemplateCallback = (&'static str, fn(&[glib::Value]) -> Option<glib::Value>);
1858
1859pub trait CompositeTemplateCallbacks {
1865 const CALLBACKS: &'static [TemplateCallback];
1866
1867 fn bind_template_callbacks<T: WidgetClassExt>(klass: &mut T) {
1871 Self::add_callbacks_to_scope(&klass.rust_template_scope());
1872 }
1873 fn bind_template_callbacks_prefixed<T: WidgetClassExt>(klass: &mut T, prefix: &str) {
1877 Self::add_callbacks_to_scope_prefixed(&klass.rust_template_scope(), prefix);
1878 }
1879 fn add_callbacks_to_scope(scope: &BuilderRustScope) {
1882 for (name, func) in Self::CALLBACKS {
1883 scope.add_callback(*name, func);
1884 }
1885 }
1886 fn add_callbacks_to_scope_prefixed(scope: &BuilderRustScope, prefix: &str) {
1890 for (name, func) in Self::CALLBACKS {
1891 scope.add_callback(format!("{prefix}{name}"), func);
1892 }
1893 }
1894}
1895
1896pub trait CompositeTemplateCallbacksClass {
1901 fn bind_template_callbacks(&mut self);
1905}
1906
1907impl<T, U> CompositeTemplateCallbacksClass for T
1908where
1909 T: ClassStruct<Type = U> + WidgetClassExt,
1910 U: ObjectSubclass<Class = T> + CompositeTemplateCallbacks,
1911{
1912 fn bind_template_callbacks(&mut self) {
1913 <U as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1914 }
1915}
1916
1917pub trait CompositeTemplateInstanceCallbacksClass {
1923 fn bind_template_instance_callbacks(&mut self);
1927}
1928
1929impl<T, U, V> CompositeTemplateInstanceCallbacksClass for T
1930where
1931 T: ClassStruct<Type = U> + WidgetClassExt,
1932 U: ObjectSubclass<Class = T, Type = V>,
1933 V: CompositeTemplateCallbacks,
1934{
1935 fn bind_template_instance_callbacks(&mut self) {
1936 <V as CompositeTemplateCallbacks>::bind_template_callbacks(self);
1937 }
1938}
1939
1940pub trait CompositeTemplateInitializingExt {
1941 fn init_template(&self);
1942}
1943
1944impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateInitializingExt
1945 for glib::subclass::InitializingObject<T>
1946{
1947 fn init_template(&self) {
1948 unsafe {
1949 let widget = self
1950 .as_ref()
1951 .unsafe_cast_ref::<<T as ObjectSubclass>::Type>();
1952 ffi::gtk_widget_init_template(AsRef::<Widget>::as_ref(widget).to_glib_none().0);
1953
1954 <T as CompositeTemplate>::check_template_children(widget);
1955 }
1956 }
1957}
1958
1959pub trait CompositeTemplateDisposeExt {
1960 #[cfg(feature = "v4_8")]
1961 #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1962 fn dispose_template(&self);
1963}
1964
1965impl<T: WidgetImpl + CompositeTemplate> CompositeTemplateDisposeExt for T {
1966 #[cfg(feature = "v4_8")]
1967 #[cfg_attr(docsrs, doc(cfg(feature = "v4_8")))]
1968 fn dispose_template(&self) {
1969 unsafe {
1970 ffi::gtk_widget_dispose_template(
1971 self.obj().upcast_ref::<Widget>().to_glib_none().0,
1972 <T as ObjectSubclass>::Type::static_type().into_glib(),
1973 );
1974 }
1975 }
1976}
1977
1978#[cfg(test)]
1979mod tests {
1980 use super::*;
1981 use crate::{self as gtk4};
1982
1983 mod imp {
1987 use super::*;
1988
1989 #[derive(Default)]
1990 pub struct CustomClassWidget;
1991
1992 #[glib::object_subclass]
1993 impl ObjectSubclass for CustomClassWidget {
1994 const NAME: &'static str = "GtkRsTestCustomClassWidget";
1995 type Type = super::CustomClassWidget;
1996 type ParentType = Widget;
1997 type Class = super::CustomClassWidgetClass;
1998
1999 fn class_init(klass: &mut Self::Class) {
2000 klass.set_css_name("gtkrstestcustomclasswidget");
2001 klass.set_accessible_role(AccessibleRole::Group);
2002 klass.set_layout_manager_type::<crate::BinLayout>();
2003
2004 klass.install_property_action("test.visible", "visible");
2005 klass.add_binding_action(
2006 gdk::Key::a,
2007 gdk::ModifierType::CONTROL_MASK,
2008 "test.visible",
2009 );
2010 klass.add_shortcut(&crate::Shortcut::new(
2011 Some(crate::KeyvalTrigger::new(
2012 gdk::Key::b,
2013 gdk::ModifierType::CONTROL_MASK,
2014 )),
2015 Some(crate::NamedAction::new("test.visible")),
2016 ));
2017
2018 let _ = klass.css_name();
2025 let _ = klass.accessible_role();
2026 let _ = klass.layout_manager_type();
2027 let _ = klass.activate_signal();
2028 let _ = klass.query_action();
2029 }
2030 }
2031
2032 impl ObjectImpl for CustomClassWidget {}
2033 impl WidgetImpl for CustomClassWidget {}
2034 }
2035
2036 #[cfg(feature = "v4_10")]
2037 glib::wrapper! {
2038 pub struct CustomClassWidget(ObjectSubclass<imp::CustomClassWidget>)
2039 @extends gtk4::Widget,
2040 @implements gtk4::Accessible, gtk4::Buildable, gtk4::ConstraintTarget;
2041 }
2042
2043 #[cfg(not(feature = "v4_10"))]
2044 glib::wrapper! {
2045 pub struct CustomClassWidget(ObjectSubclass<imp::CustomClassWidget>)
2046 @extends gtk4::Widget,
2047 @implements gtk4::Buildable, gtk4::ConstraintTarget;
2048 }
2049
2050 #[repr(C)]
2054 pub struct CustomClassWidgetClass {
2055 pub parent_class: ffi::GtkWidgetClass,
2056 }
2057
2058 unsafe impl ClassStruct for CustomClassWidgetClass {
2059 type Type = imp::CustomClassWidget;
2060 }
2061
2062 #[crate::test]
2063 fn class_methods_on_custom_class_struct() {
2064 let widget = glib::Object::new::<CustomClassWidget>();
2067
2068 let class = widget.class();
2072 assert_eq!(class.css_name(), "gtkrstestcustomclasswidget");
2073 assert_eq!(class.accessible_role(), AccessibleRole::Group);
2074 assert_eq!(class.layout_manager_type(), crate::BinLayout::static_type());
2075 assert!(class.activate_signal().is_none());
2076
2077 let actions: Vec<_> = class.query_action().map(|a| a.name().to_owned()).collect();
2081 assert!(
2082 actions.iter().any(|name| name == "test.visible"),
2083 "installed action missing from {actions:?}"
2084 );
2085
2086 let class = glib::Class::<CustomClassWidget>::from_type(CustomClassWidget::static_type())
2091 .expect("CustomClassWidget class");
2092 class.add_binding_action(gdk::Key::c, gdk::ModifierType::CONTROL_MASK, "test.visible");
2093 assert!(class.query_action().any(|a| a.name() == "test.visible"));
2094 }
2095}