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