'Should I try to access self in a PointerPressed event handler for a CoreApp in the Rust Crate for Windows?
E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement. E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement.
#![windows_subsystem = "windows"]
use windows::{
core::*,
Foundation::*,
ApplicationModel::Core::*,
Foundation::Numerics::*,
Foundation::TypedEventHandler,
Win32::System::Com::*,
UI::{
Core::*,
Composition::*,
},
};
use windows as Windows;
#[implement(Windows::ApplicationModel::Core::IFrameworkViewSource)]
struct App();
#[allow(non_snake_case)]
impl App {
fn CreateView(&self) -> Result<IFrameworkView> {
// TODO: need self query `self.into()` to support implementing both IFrameworkViewSource and IFrameworkView on the same object.
Ok(AppView::new().into())
}
}
#[implement(Windows::ApplicationModel::Core::IFrameworkView)]
struct AppView {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
#[allow(non_snake_case)]
impl AppView {
fn new() -> Self {
Self {
m_target: None,
m_visuals: None,
m_selected: None,
m_offset: None,
}
}
fn Initialize(&self, _: &Option<CoreApplicationView>) -> Result<()> {
Ok(())
}
fn Load(&self, _: &HSTRING) -> Result<()> {
Ok(())
}
fn Uninitialize(&self) -> Result<()> {
Ok(())
}
fn Run(&self) -> Result<()> {
let window = CoreWindow::GetForCurrentThread()?;
window.Activate()?;
let dispatcher = window.Dispatcher()?;
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit)?;
Ok(())
}
fn SetWindow(&mut self, window: &Option<CoreWindow>) -> Result<()> {
let compositor = Compositor::new()?;
let root = compositor.CreateContainerVisual()?;
self.m_target = Some(compositor.CreateTargetForCurrentView()?);
let target = self.m_target.as_ref().unwrap();
target.SetRoot(&root)?;
self.m_visuals = Some(root.Children()?);
let visuals = self.m_visuals.as_ref().unwrap(); // extra line for test is ok
window.as_ref().unwrap().PointerPressed(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args|
{
let args = args.as_ref().unwrap();
let currentpoint = args.CurrentPoint().unwrap();
let point = currentpoint.Position().unwrap(); // Point not Vector2
//let visuals: &VisualCollection = self.m_visuals.as_ref().unwrap();
let visuals = self.m_visuals.as_ref().unwrap(); // E0759 self has an anonymous lifetime '_ but it need to satisfy a 'static lifetime requirement
Ok(())
}
))?;
window.as_ref().unwrap().PointerMoved(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, _args|
{
Ok(())
}
))?;
window.as_ref().unwrap().PointerReleased(TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, _args|
{
Ok(())
}
))?;
Ok(())
}
fn AddVisual(_point: Point) {
//...
}
}
fn main() -> Result<()> {
unsafe {
CoInitializeEx(std::ptr::null_mut(), COINIT_MULTITHREADED)?;
}
let app: IFrameworkViewSource = App().into();
CoreApplication::Run(app)?;
Ok(())
}
Solution 1:[1]
Capturing AppView's instance self reference in v0.30 doesn't seem to be possible, because TypedEventHandler::new has a + 'static requirement for the callback (see), so any reference it captures must be 'static (a global variable basically).
Please raise an issue here if you want this. Your code looks like a reasonable way to use this API.
Until then, as a workaround you could make a level of indirection, where instead of storing the state directly in AppView, you store it in a shared helper object, for example:
struct AppView {
m_state: Rc<RefCell<AppViewState>>,
}
struct AppViewState {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
You can clone it move into the callback for modification:
let pointer_pressed_state = Rc::clone(self.m_state);
let pointer_pressed_handler = TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args| {
let state_ref = pointer_pressed_state.borrow(); // or .borrow_mut()
...
});
let pointer_moved_state = Rc::clone(self.m_state);
let pointer_moved_handler = TypedEventHandler::<CoreWindow, PointerEventArgs>::new(move |_, args| {
let state_ref = pointer_moved_state.borrow(); // or .borrow_mut()
...
});
This should work, because now the closure doesn't capture any references (everything gets moved).
If you want, you can add methods to AppViewState, and call them from the closures like state_ref.OnPointerPressed(...).
Another option that I don't recommend is to use unsafe and cast self to 'static.
Solution 2:[2]
Rc<RefCell> gives a thread related compiler error but changing to Arc<Mutex> resolves this.
struct AppView {
m_state: Arc<Mutex<AppViewState>>,
}
struct AppViewState {
m_target: Option<CompositionTarget>,
m_visuals: Option<VisualCollection>,
m_selected: Option<Visual>,
m_offset: Option<Vector2>,
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | MRahilly |
