11use std:: {
2+ cell:: { RefCell , RefMut } ,
23 collections:: VecDeque ,
34 fmt:: { self , Debug } ,
45 hint:: unreachable_unchecked,
56 mem,
6- rc:: Rc ,
7+ rc:: { Rc , Weak } ,
78 sync:: {
89 atomic:: { AtomicBool , Ordering } ,
910 Mutex , MutexGuard ,
@@ -12,19 +13,18 @@ use std::{
1213} ;
1314
1415use cocoa:: {
15- appkit:: { NSApp , NSEventType :: NSApplicationDefined , NSWindow } ,
16+ appkit:: { NSApp , NSWindow } ,
1617 base:: { id, nil} ,
17- foundation:: { NSAutoreleasePool , NSPoint , NSSize } ,
18+ foundation:: { NSAutoreleasePool , NSSize } ,
1819} ;
1920
20- use objc:: runtime:: YES ;
21-
2221use crate :: {
2322 dpi:: LogicalSize ,
2423 event:: { Event , StartCause , WindowEvent } ,
2524 event_loop:: { ControlFlow , EventLoopWindowTarget as RootWindowTarget } ,
2625 platform_impl:: platform:: {
2726 event:: { EventProxy , EventWrapper } ,
27+ event_loop:: { post_dummy_event, PanicInfo } ,
2828 observer:: EventLoopWaker ,
2929 util:: { IdRef , Never } ,
3030 window:: get_window_id,
@@ -52,11 +52,31 @@ pub trait EventHandler: Debug {
5252}
5353
5454struct EventLoopHandler < T : ' static > {
55- callback : Box < dyn FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) > ,
55+ callback : Weak < RefCell < dyn FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) > > ,
5656 will_exit : bool ,
5757 window_target : Rc < RootWindowTarget < T > > ,
5858}
5959
60+ impl < T > EventLoopHandler < T > {
61+ fn with_callback < F > ( & mut self , f : F )
62+ where
63+ F : FnOnce (
64+ & mut EventLoopHandler < T > ,
65+ RefMut < ' _ , dyn FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) > ,
66+ ) ,
67+ {
68+ if let Some ( callback) = self . callback . upgrade ( ) {
69+ let callback = callback. borrow_mut ( ) ;
70+ ( f) ( self , callback) ;
71+ } else {
72+ panic ! (
73+ "Tried to dispatch an event, but the event loop that \
74+ owned the event handler callback seems to be destroyed"
75+ ) ;
76+ }
77+ }
78+ }
79+
6080impl < T > Debug for EventLoopHandler < T > {
6181 fn fmt ( & self , formatter : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
6282 formatter
@@ -68,23 +88,27 @@ impl<T> Debug for EventLoopHandler<T> {
6888
6989impl < T > EventHandler for EventLoopHandler < T > {
7090 fn handle_nonuser_event ( & mut self , event : Event < ' _ , Never > , control_flow : & mut ControlFlow ) {
71- ( self . callback ) ( event. userify ( ) , & self . window_target , control_flow) ;
72- self . will_exit |= * control_flow == ControlFlow :: Exit ;
73- if self . will_exit {
74- * control_flow = ControlFlow :: Exit ;
75- }
91+ self . with_callback ( |this, mut callback| {
92+ ( callback) ( event. userify ( ) , & this. window_target , control_flow) ;
93+ this. will_exit |= * control_flow == ControlFlow :: Exit ;
94+ if this. will_exit {
95+ * control_flow = ControlFlow :: Exit ;
96+ }
97+ } ) ;
7698 }
7799
78100 fn handle_user_events ( & mut self , control_flow : & mut ControlFlow ) {
79- let mut will_exit = self . will_exit ;
80- for event in self . window_target . p . receiver . try_iter ( ) {
81- ( self . callback ) ( Event :: UserEvent ( event) , & self . window_target , control_flow) ;
82- will_exit |= * control_flow == ControlFlow :: Exit ;
83- if will_exit {
84- * control_flow = ControlFlow :: Exit ;
101+ self . with_callback ( |this, mut callback| {
102+ let mut will_exit = this. will_exit ;
103+ for event in this. window_target . p . receiver . try_iter ( ) {
104+ ( callback) ( Event :: UserEvent ( event) , & this. window_target , control_flow) ;
105+ will_exit |= * control_flow == ControlFlow :: Exit ;
106+ if will_exit {
107+ * control_flow = ControlFlow :: Exit ;
108+ }
85109 }
86- }
87- self . will_exit = will_exit ;
110+ this . will_exit = will_exit ;
111+ } ) ;
88112 }
89113}
90114
@@ -229,20 +253,12 @@ pub static INTERRUPT_EVENT_LOOP_EXIT: AtomicBool = AtomicBool::new(false);
229253pub enum AppState { }
230254
231255impl AppState {
232- // This function extends lifetime of `callback` to 'static as its side effect
233- pub unsafe fn set_callback < F , T > ( callback : F , window_target : Rc < RootWindowTarget < T > > )
234- where
235- F : FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) ,
236- {
256+ pub fn set_callback < T > (
257+ callback : Weak < RefCell < dyn FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) > > ,
258+ window_target : Rc < RootWindowTarget < T > > ,
259+ ) {
237260 * HANDLER . callback . lock ( ) . unwrap ( ) = Some ( Box :: new ( EventLoopHandler {
238- // This transmute is always safe, in case it was reached through `run`, since our
239- // lifetime will be already 'static. In other cases caller should ensure that all data
240- // they passed to callback will actually outlive it, some apps just can't move
241- // everything to event loop, so this is something that they should care about.
242- callback : mem:: transmute :: <
243- Box < dyn FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) > ,
244- Box < dyn FnMut ( Event < ' _ , T > , & RootWindowTarget < T > , & mut ControlFlow ) > ,
245- > ( Box :: new ( callback) ) ,
261+ callback,
246262 will_exit : false ,
247263 window_target,
248264 } ) ) ;
@@ -265,8 +281,11 @@ impl AppState {
265281 HANDLER . set_in_callback ( false ) ;
266282 }
267283
268- pub fn wakeup ( ) {
269- if !HANDLER . is_ready ( ) {
284+ pub fn wakeup ( panic_info : Weak < PanicInfo > ) {
285+ let panic_info = panic_info
286+ . upgrade ( )
287+ . expect ( "The panic info must exist here. This failure indicates a developer error." ) ;
288+ if panic_info. is_panicking ( ) || !HANDLER . is_ready ( ) {
270289 return ;
271290 }
272291 let start = HANDLER . get_start_time ( ) . unwrap ( ) ;
@@ -318,8 +337,11 @@ impl AppState {
318337 HANDLER . events ( ) . append ( & mut wrappers) ;
319338 }
320339
321- pub fn cleared ( ) {
322- if !HANDLER . is_ready ( ) {
340+ pub fn cleared ( panic_info : Weak < PanicInfo > ) {
341+ let panic_info = panic_info
342+ . upgrade ( )
343+ . expect ( "The panic info must exist here. This failure indicates a developer error." ) ;
344+ if panic_info. is_panicking ( ) || !HANDLER . is_ready ( ) {
323345 return ;
324346 }
325347 if !HANDLER . get_in_callback ( ) {
@@ -357,21 +379,9 @@ impl AppState {
357379 && !dialog_open
358380 && !dialog_is_closing
359381 {
360- let _: ( ) = msg_send ! [ app, stop: nil] ;
361-
362- let dummy_event: id = msg_send ! [ class!( NSEvent ) ,
363- otherEventWithType: NSApplicationDefined
364- location: NSPoint :: new( 0.0 , 0.0 )
365- modifierFlags: 0
366- timestamp: 0
367- windowNumber: 0
368- context: nil
369- subtype: 0
370- data1: 0
371- data2: 0
372- ] ;
382+ let ( ) = msg_send ! [ app, stop: nil] ;
373383 // To stop event loop immediately, we need to post some event here.
374- let _ : ( ) = msg_send ! [ app, postEvent : dummy_event atStart : YES ] ;
384+ post_dummy_event ( app) ;
375385 }
376386 pool. drain ( ) ;
377387
0 commit comments