@@ -955,6 +955,173 @@ mod weak_handle {
955955
956956pub use weak_handle:: * ;
957957
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. If some other instance still holds a strong reference.
1041+ /// 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 inner = T :: upgrade_from_weak_inner ( & self . inner ) ?;
1051+ Some ( GlobalStrong ( inner. 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+
9581125/// Adds the specified function to an internal queue, notifies the event loop to wake up.
9591126/// Once woken up, any queued up functors will be invoked.
9601127///
0 commit comments