rust-windowing / winit

Window handling library in pure Rust
https://docs.rs/winit/
Apache License 2.0
4.87k stars 910 forks source link

MacOS panic: "tried to handle event while another event is currently being handled" #3992

Open madsmtm opened 1 week ago

madsmtm commented 1 week ago

Discussed in https://github.com/rust-windowing/winit/discussions/3990 by @AlexanderHarrison

Originally posted by **AlexanderHarrison** November 9, 2024 Hi! I'm running into the aforementioned error on startup on macos. Linux and windows both work fine. I couldn't find *any* information about this error, or find anyone who has run into it before. Unfortunately, I am relying on the help of a volunteer to compile on macos, so I am very limited in the amount of debugging I can do myself. From looking at the winit source, it looks like each event call borrows a `RefCell` of the `EventHandlerData`, and somehow we are not dropping the `RefMut` before handing another event. The comment states that the panic "avoids re-entrancy". I assume that one of my handled events is somehow causing the event loop to handle another event, before dropping `RefMut`. Would this be caused by a method call into the event loop? Or a some method on the window? Not sure, I would love a pointer as to how this panic could come about. Here's the (abridged) structure of my app. I don't think I'm doing anything crazy. ```rust enum WinitRunner<'a> { // avoid lifetime issues None, Uninit { window: &'a mut Option, }, Init { st: State, ctx: Ctx<'a>, }, } impl<'a> ApplicationHandler for WinitRunner<'a> { fn resumed(&mut self, event_loop: &ActiveEventLoop) { if matches!(self, WinitRunner::Init { .. }) { return } env_logger::init(); // avoid lifetime issues let s = std::mem::replace(self, WinitRunner::None); let window = match s { WinitRunner::Uninit { window } => window, _ => unreachable!(), }; let window: &Window = window.insert(event_loop.create_window( Window::default_attributes() .with_min_inner_size(winit::dpi::PhysicalSize::new(MIN_WIDTH, MIN_HEIGHT)) .with_title("title!") ).unwrap()); let mut ctx = Ctx::new(window); let st = State::new(&mut ctx); *self = WinitRunner::Init { st, ctx } } fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { let (st, ctx) = match self { WinitRunner::Init { st, ctx } => (st, ctx), _ => return, }; st.window_event(ctx, event_loop, window_id, event); } fn user_event(&mut self, event_loop: &ActiveEventLoop, _event: Update) { let (st, ctx) = match self { WinitRunner::Init { st, ctx } => (st, ctx), _ => return, }; st.user_event(ctx, event_loop); } } fn main() { let event_loop = EventLoop::with_user_event().build().unwrap(); let event_sender = event_loop.create_proxy(); std::thread::spawn(move || { loop { let _ = event_sender.send_event(Update); std::thread::sleep(UPDATE_PERIOD); } }); let mut window = None; let mut runner: WinitRunner = WinitRunner::Uninit { window: &mut window }; event_loop.run_app(&mut runner).unwrap(); } ```
madsmtm commented 1 week ago

@AlexanderHarrison: Since I cannot run your sample code (it is not a minimum reproducible one), it's a bit hard to test.

What Winit version are you using? (I'm assuming v0.30.5?) And could you try it on the latest master? And could you post the backtrace (set RUST_BACKTRACE=1)?

EDIT: Wait nevermind, you said you're limited in the amount of debugging... Hmm...

madsmtm commented 1 week ago

Are you are doing anything to the window inside Ctx::new or State::new?

AlexanderHarrison commented 1 week ago

Yes, inside Ctx::new I'm initiating a wgpu context and creating a surface using window, then setting the window icon, and finally configuring the surface with the result of window.inner_size().

I'm using winit v0.30.5 with wgpu v22.1.0.

I will try to put together a minimal example.