1
1
use std:: {
2
+ cell:: { RefCell , RefMut } ,
2
3
collections:: VecDeque ,
3
4
fmt:: { self , Debug } ,
4
5
hint:: unreachable_unchecked,
5
6
mem,
6
- rc:: Rc ,
7
+ rc:: { Rc , Weak } ,
7
8
sync:: {
8
9
atomic:: { AtomicBool , Ordering } ,
9
10
Mutex , MutexGuard ,
@@ -12,19 +13,18 @@ use std::{
12
13
} ;
13
14
14
15
use cocoa:: {
15
- appkit:: { NSApp , NSEventType :: NSApplicationDefined , NSWindow } ,
16
+ appkit:: { NSApp , NSWindow } ,
16
17
base:: { id, nil} ,
17
- foundation:: { NSAutoreleasePool , NSPoint , NSSize } ,
18
+ foundation:: { NSAutoreleasePool , NSSize } ,
18
19
} ;
19
20
20
- use objc:: runtime:: YES ;
21
-
22
21
use crate :: {
23
22
dpi:: LogicalSize ,
24
23
event:: { Event , StartCause , WindowEvent } ,
25
24
event_loop:: { ControlFlow , EventLoopWindowTarget as RootWindowTarget } ,
26
25
platform_impl:: platform:: {
27
26
event:: { EventProxy , EventWrapper } ,
27
+ event_loop:: { post_dummy_event, PanicInfo } ,
28
28
observer:: EventLoopWaker ,
29
29
util:: { IdRef , Never } ,
30
30
window:: get_window_id,
@@ -52,11 +52,31 @@ pub trait EventHandler: Debug {
52
52
}
53
53
54
54
struct 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 ) > > ,
56
56
will_exit : bool ,
57
57
window_target : Rc < RootWindowTarget < T > > ,
58
58
}
59
59
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
+
60
80
impl < T > Debug for EventLoopHandler < T > {
61
81
fn fmt ( & self , formatter : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
62
82
formatter
@@ -68,23 +88,27 @@ impl<T> Debug for EventLoopHandler<T> {
68
88
69
89
impl < T > EventHandler for EventLoopHandler < T > {
70
90
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
+ } ) ;
76
98
}
77
99
78
100
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
+ }
85
109
}
86
- }
87
- self . will_exit = will_exit ;
110
+ this . will_exit = will_exit ;
111
+ } ) ;
88
112
}
89
113
}
90
114
@@ -229,20 +253,12 @@ pub static INTERRUPT_EVENT_LOOP_EXIT: AtomicBool = AtomicBool::new(false);
229
253
pub enum AppState { }
230
254
231
255
impl 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
+ ) {
237
260
* 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,
246
262
will_exit : false ,
247
263
window_target,
248
264
} ) ) ;
@@ -265,8 +281,11 @@ impl AppState {
265
281
HANDLER . set_in_callback ( false ) ;
266
282
}
267
283
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 ( ) {
270
289
return ;
271
290
}
272
291
let start = HANDLER . get_start_time ( ) . unwrap ( ) ;
@@ -318,8 +337,11 @@ impl AppState {
318
337
HANDLER . events ( ) . append ( & mut wrappers) ;
319
338
}
320
339
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 ( ) {
323
345
return ;
324
346
}
325
347
if !HANDLER . get_in_callback ( ) {
@@ -357,21 +379,9 @@ impl AppState {
357
379
&& !dialog_open
358
380
&& !dialog_is_closing
359
381
{
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] ;
373
383
// 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) ;
375
385
}
376
386
pool. drain ( ) ;
377
387
0 commit comments