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