@@ -955,6 +955,173 @@ mod weak_handle {
955
955
956
956
pub use weak_handle:: * ;
957
957
958
+ /// This trait provides the necessary functionality for allowing creating strongly-referenced
959
+ /// clones and conversion into/ a weak pointer for a Global slint component.
960
+ ///
961
+ /// This trait is implemented by the [generated component](index.html#generated-components)
962
+ pub trait GlobalComponentHandle {
963
+ /// The type for the public global component interface.
964
+ #[ doc( hidden) ]
965
+ type Global < ' a > ;
966
+ /// The internal Inner type for `Weak<Self>::inner`.
967
+ #[ doc( hidden) ]
968
+ type WeakInner : Clone + Default ;
969
+ /// The internal Inner type for the 'Pin<sp::Rc<InnerSelf>'.
970
+ #[ doc( hidden) ]
971
+ type PinnedInner : Clone ;
972
+
973
+ /// Internal function used when upgrading a weak reference to a strong one.
974
+ #[ doc( hidden) ]
975
+ fn upgrade_from_weak_inner ( inner : & Self :: WeakInner ) -> Option < Self :: PinnedInner >
976
+ where
977
+ Self : Sized ;
978
+
979
+ /// Internal function used when upgrading a weak reference to a strong one.
980
+ fn to_self < ' a > ( inner : & ' a Self :: PinnedInner ) -> Self :: Global < ' a >
981
+ where
982
+ Self : Sized ;
983
+ }
984
+
985
+ pub use global_weak_handle:: * ;
986
+
987
+ mod global_weak_handle {
988
+ use super :: * ;
989
+
990
+ /// Struct that's used to hold weak references of a [Slint global component](index.html#generated-components)
991
+ ///
992
+ /// In order to create a GlobalWeak, you should call .as_weak() on the global component instance.
993
+ pub struct GlobalWeak < T : GlobalComponentHandle > {
994
+ inner : T :: WeakInner ,
995
+ #[ cfg( feature = "std" ) ]
996
+ thread : std:: thread:: ThreadId ,
997
+ }
998
+
999
+ /// Struct that's used to hold a strong reference of a Slint global component
1000
+ pub struct GlobalStrong < T : GlobalComponentHandle > ( T :: PinnedInner ) ;
1001
+
1002
+ impl < T : GlobalComponentHandle > GlobalStrong < T > {
1003
+ /// Get the actual global component
1004
+ pub fn to_global < ' a > ( & ' a self ) -> T :: Global < ' a > {
1005
+ T :: to_self ( & self . 0 )
1006
+ }
1007
+ }
1008
+
1009
+ impl < T : GlobalComponentHandle > Default for GlobalWeak < T > {
1010
+ fn default ( ) -> Self {
1011
+ Self {
1012
+ inner : T :: WeakInner :: default ( ) ,
1013
+ #[ cfg( feature = "std" ) ]
1014
+ thread : std:: thread:: current ( ) . id ( ) ,
1015
+ }
1016
+ }
1017
+ }
1018
+
1019
+ impl < T : GlobalComponentHandle > Clone for GlobalWeak < T > {
1020
+ fn clone ( & self ) -> Self {
1021
+ Self {
1022
+ inner : self . inner . clone ( ) ,
1023
+ #[ cfg( feature = "std" ) ]
1024
+ thread : self . thread ,
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ impl < T : GlobalComponentHandle > GlobalWeak < T > {
1030
+ #[ doc( hidden) ]
1031
+ pub fn new ( inner : T :: WeakInner ) -> Self {
1032
+ Self {
1033
+ inner,
1034
+ #[ cfg( feature = "std" ) ]
1035
+ thread : std:: thread:: current ( ) . id ( ) ,
1036
+ }
1037
+ }
1038
+
1039
+ /// Returns a new GlobalStrong struct, where it's possible to get the global component
1040
+ /// struct interface. Ff some other instance still
1041
+ /// holds a strong reference. Otherwise, returns None.
1042
+ ///
1043
+ /// This also returns None if the current thread is not the thread that created
1044
+ /// the component
1045
+ pub fn upgrade ( & self ) -> Option < GlobalStrong < T > > {
1046
+ #[ cfg( feature = "std" ) ]
1047
+ if std:: thread:: current ( ) . id ( ) != self . thread {
1048
+ return None ;
1049
+ }
1050
+ let coso = T :: upgrade_from_weak_inner ( & self . inner ) ?;
1051
+ Some ( GlobalStrong ( coso. clone ( ) ) )
1052
+ }
1053
+
1054
+ /// Convenience function where a given functor is called with the global component
1055
+ ///
1056
+ /// If the current thread is not the thread that created the component the functor
1057
+ /// will not be called and this function will do nothing.
1058
+ pub fn upgrade_in ( & self , func : impl FnOnce ( T :: Global < ' _ > ) ) {
1059
+ #[ cfg( feature = "std" ) ]
1060
+ if std:: thread:: current ( ) . id ( ) != self . thread {
1061
+ return ;
1062
+ }
1063
+
1064
+ if let Some ( inner) = T :: upgrade_from_weak_inner ( & self . inner ) {
1065
+ func ( T :: to_self ( & inner) ) ;
1066
+ }
1067
+ }
1068
+
1069
+ /// Convenience function that combines [`invoke_from_event_loop()`] with [`Self::upgrade()`]
1070
+ ///
1071
+ /// The given functor will be added to an internal queue and will wake the event loop.
1072
+ /// On the next iteration of the event loop, the functor will be executed with a `T` as an argument.
1073
+ ///
1074
+ /// If the component was dropped because there are no more strong reference to the component,
1075
+ /// the functor will not be called.
1076
+ /// # Example
1077
+ /// ```rust
1078
+ /// # i_slint_backend_testing::init_no_event_loop();
1079
+ /// slint::slint! {
1080
+ /// export global MyAppData { in property<int> foo; }
1081
+ /// export component MyApp inherits Window { /* ... */ } }
1082
+ /// }
1083
+ /// let ui = MyApp::new().unwrap();
1084
+ /// let my_app_data = ui.global::<MyAppData>();
1085
+ /// let my_app_data_weak = my_app_data.as_weak();
1086
+ ///
1087
+ /// let thread = std::thread::spawn(move || {
1088
+ /// // ... Do some computation in the thread
1089
+ /// let foo = 42;
1090
+ /// # assert!(my_app_data_weak.upgrade().is_none()); // note that upgrade fails in a thread
1091
+ /// # return; // don't upgrade_in_event_loop in our examples
1092
+ /// // now forward the data to the main thread using upgrade_in_event_loop
1093
+ /// my_app_data_weak.upgrade_in_event_loop(move |my_app_data| my_app_data.set_foo(foo));
1094
+ /// });
1095
+ /// # thread.join().unwrap(); return; // don't run the event loop in examples
1096
+ /// ui.run().unwrap();
1097
+ /// ```
1098
+ #[ cfg( any( feature = "std" , feature = "unsafe-single-threaded" ) ) ]
1099
+ pub fn upgrade_in_event_loop (
1100
+ & self ,
1101
+ func : impl FnOnce ( T :: Global < ' _ > ) + Send + ' static ,
1102
+ ) -> Result < ( ) , EventLoopError >
1103
+ where
1104
+ T : ' static ,
1105
+ {
1106
+ let weak_handle = self . clone ( ) ;
1107
+ super :: invoke_from_event_loop ( move || {
1108
+ if let Some ( h) = weak_handle. upgrade ( ) {
1109
+ func ( h. to_global ( ) ) ;
1110
+ }
1111
+ } )
1112
+ }
1113
+ }
1114
+
1115
+ // Safety: we make sure in upgrade that the thread is the proper one,
1116
+ // and the Weak only use atomic pointer so it is safe to clone and drop in another thread
1117
+ #[ allow( unsafe_code) ]
1118
+ #[ cfg( any( feature = "std" , feature = "unsafe-single-threaded" ) ) ]
1119
+ unsafe impl < T : GlobalComponentHandle > Send for GlobalWeak < T > { }
1120
+ #[ allow( unsafe_code) ]
1121
+ #[ cfg( any( feature = "std" , feature = "unsafe-single-threaded" ) ) ]
1122
+ unsafe impl < T : GlobalComponentHandle > Sync for GlobalWeak < T > { }
1123
+ }
1124
+
958
1125
/// Adds the specified function to an internal queue, notifies the event loop to wake up.
959
1126
/// Once woken up, any queued up functors will be invoked.
960
1127
///
0 commit comments