Skip to content

Conversation

bennysj
Copy link
Contributor

@bennysj bennysj commented Sep 16, 2025

The idea to make it easier and more convenient to pass a reference to a Slint global instance into a Rust closure / lambda.

The current implementation works the following way:

  pub fn init(blogica_api: &BLogicAAPI) {
        blogica_api.on_update_data({
            let blogica_api_weak = blogica_api.as_weak();
            |bdata| {
                let blogica_api = blogica_api_weak.upgrade().unwrap();
                // It would have been very nice if the call to .global() could avoided, as it depends on the lifetime
                // of the GlobalStrong<T> it's needed
                let blogica_api = blogica_api_weak.to_global();

                // Do stuff here with blogica_api
            }
        });
    }

Fixes #9389

@bennysj bennysj force-pushed the global_comp_improvments branch 4 times, most recently from ab2a50a to 595f2e2 Compare September 16, 2025 14:06
pub use weak_handle::*;

/// This trait provides the necessary functionality for allowing creating strongly-referenced
/// clones and conversion into/ a weak pointer for a Global slint component.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

into/ ?

Did you mean into/from maybe, or is the / a typo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

/// Returns a new GlobalStrong struct, where it's possible to get the global component
/// struct interface. Ff some other instance still
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ff => If

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if std::thread::current().id() != self.thread {
return None;
}
let coso = T::upgrade_from_weak_inner(&self.inner)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coso?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to 'inner'

/// // now forward the data to the main thread using upgrade_in_event_loop
/// my_app_data_weak.upgrade_in_event_loop(move |my_app_data| my_app_data.set_foo(foo));
/// });
/// # thread.join().unwrap(); return; // don't run the event loop in examples
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. This is docu, not actual example, why the commented-out code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a lot of copy / paste from the same function for Weak - at line 930

@bennysj bennysj force-pushed the global_comp_improvments branch 3 times, most recently from d2882a0 to 91264dc Compare September 25, 2025 18:47
where
Self: Sized;

/// Internal function used when upgrading a weak reference to a strong one.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Internal function used when upgrading a weak reference to a strong one.
/// Internal function used when upgrading a weak reference to a strong one.
#[doc(hidden)]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

#[repr(C)]
#[pin]
#pub_token struct #inner_component_id {
pub struct #inner_component_id {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed as part of this feature?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to remember,... but it's due to the PinnedInner type, unfortunately to make this work, this may need to be 'pub'

Comment on lines 1004 to 1006
pub fn to_global<'a>(&'a self) -> T::Global<'a> {
T::to_self(&self.0)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it perhaps make more sense to implement AsRef<T> for GlobalStrong<T>, instead of this new function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That might be a good idea, let me try implement that.

Copy link
Contributor Author

@bennysj bennysj Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementing AsRef and/or Deref for GlobalStrong is not possible (unless there is some Rust wizardy that I don't know about yet) The reason is that Global has a reference '&' and a lifetime 'a to the inner.
I've just renamed this method to 'global', that may be more appropriate.
'as_ref' does not feel right, as it's not returning a reference '&'

Comment on lines 1056 to 1057
/// If the current thread is not the thread that created the component the functor
/// will not be called and this function will do nothing.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit unfortunate that that's a silent error. I think my preference would be to omit this function, as it can "fail" for two unrelated reasons that the user won't be able to find out about.

If I call upgrade_in() from the wrong thread, it's a programmer error. If the upgrade fails because the global doesn't exist anymore, it's what could be a normal condition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it, I think both should be a programmer error.

  • Different thread, let's just panic
  • If it does not exist anymore, then it's called after the MainWindow is destroyed, I think this is also a programmer error, let also panic

move |bdata| {
{
let blogica_api = blogica_api.upgrade().unwrap();
let blogica_api = blogica_api.to_global();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where I think .as_ref() is the idiomatic name. It could also implement Deref perhaps? Conceptually I think this should behave like a smart pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On my previous comment, it does not return a reference '&', therefor, at least me, it does not feel correct

@bennysj bennysj force-pushed the global_comp_improvments branch from 91264dc to 46a0a06 Compare October 17, 2025 13:16
The idea to make it easier and more convenient to pass a reference
to a Slint global instance into a Rust closure / lambda.

Fixes slint-ui#9389
@bennysj bennysj force-pushed the global_comp_improvments branch from 46a0a06 to 14718b4 Compare October 17, 2025 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement .as_weak() and .upgrade() for global component instances

3 participants