@@ -13,7 +13,7 @@ use std::collections::VecDeque;
13
13
use std:: marker:: PhantomData ;
14
14
use std:: rc:: Rc ;
15
15
use wasm_bindgen:: { prelude:: * , JsCast } ;
16
- use web_sys:: { EventTarget , FocusEvent , HtmlCanvasElement , KeyboardEvent , PointerEvent , WheelEvent } ;
16
+ use web_sys:: { EventTarget , FocusEvent , KeyboardEvent , PointerEvent , WheelEvent } ;
17
17
use window:: WindowId as RootWI ;
18
18
19
19
#[ derive( Debug , Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
@@ -27,6 +27,7 @@ impl DeviceId {
27
27
28
28
pub struct EventLoop < T : ' static > {
29
29
elw : RootELW < T > ,
30
+ callbacks : CallbackRegistry < T > ,
30
31
}
31
32
32
33
pub struct EventLoopWindowTarget < T : ' static > {
@@ -71,12 +72,13 @@ struct EventLoopRunner<T> {
71
72
72
73
impl < T > EventLoop < T > {
73
74
pub fn new ( ) -> Self {
74
- EventLoop {
75
- elw : RootELW {
76
- p : EventLoopWindowTarget :: new ( ) ,
77
- _marker : PhantomData ,
78
- } ,
79
- }
75
+ let elw = RootELW {
76
+ p : EventLoopWindowTarget :: new ( ) ,
77
+ _marker : PhantomData ,
78
+ } ;
79
+ let document = document ( ) ;
80
+ let callbacks = CallbackRegistry :: new ( elw. p . runner . clone ( ) , document. unchecked_into ( ) ) ;
81
+ EventLoop { elw, callbacks }
80
82
}
81
83
82
84
pub fn available_monitors ( & self ) -> VecDequeIter < MonitorHandle > {
@@ -87,7 +89,7 @@ impl<T> EventLoop<T> {
87
89
MonitorHandle
88
90
}
89
91
90
- pub fn run < F > ( self , mut event_handler : F ) -> !
92
+ pub fn run < F > ( mut self , mut event_handler : F ) -> !
91
93
where
92
94
F : ' static + FnMut ( Event < T > , & RootELW < T > , & mut ControlFlow ) ,
93
95
{
@@ -99,20 +101,19 @@ impl<T> EventLoop<T> {
99
101
} ;
100
102
runner. set_listener ( Box :: new ( move |evt, ctrl| event_handler ( evt, & relw, ctrl) ) ) ;
101
103
102
- let document = & document ( ) ;
103
- add_event ( & runner, document, "blur" , |elrs, _: FocusEvent | {
104
+ self . callbacks . add_event ( "blur" , |elrs, _: FocusEvent | {
104
105
elrs. send_event ( Event :: WindowEvent {
105
106
window_id : RootWI ( WindowId ) ,
106
107
event : WindowEvent :: Focused ( false ) ,
107
108
} ) ;
108
109
} ) ;
109
- add_event ( & runner , document , "focus" , |elrs, _: FocusEvent | {
110
+ self . callbacks . add_event ( "focus" , |elrs, _: FocusEvent | {
110
111
elrs. send_event ( Event :: WindowEvent {
111
112
window_id : RootWI ( WindowId ) ,
112
113
event : WindowEvent :: Focused ( true ) ,
113
114
} ) ;
114
115
} ) ;
115
- add_event ( & runner , document , "keydown" , |elrs, event : KeyboardEvent | {
116
+ self . callbacks . add_event ( "keydown" , |elrs, event : KeyboardEvent | {
116
117
let key = event. key ( ) ;
117
118
let mut characters = key. chars ( ) ;
118
119
let first = characters. next ( ) ;
@@ -136,7 +137,7 @@ impl<T> EventLoop<T> {
136
137
} ,
137
138
} ) ;
138
139
} ) ;
139
- add_event ( & runner , document , "keyup" , |elrs, event : KeyboardEvent | {
140
+ self . callbacks . add_event ( "keyup" , |elrs, event : KeyboardEvent | {
140
141
elrs. send_event ( Event :: WindowEvent {
141
142
window_id : RootWI ( WindowId ) ,
142
143
event : WindowEvent :: KeyboardInput {
@@ -169,24 +170,43 @@ impl<T> EventLoop<T> {
169
170
}
170
171
}
171
172
172
- pub fn register < T : ' static > ( elrs : & EventLoopRunnerShared < T > , canvas : & HtmlCanvasElement ) {
173
- add_event ( elrs, canvas, "pointerout" , |elrs, event : PointerEvent | {
173
+ struct SavedCallback {
174
+ pub event : & ' static str ,
175
+ pub callback : Box < dyn AsRef < JsValue > > ,
176
+ }
177
+
178
+ /**
179
+ * Manages the lifetime of the closures that are used to bind Web events to `winit` events
180
+ */
181
+ pub struct CallbackRegistry < T : ' static > {
182
+ runner : EventLoopRunnerShared < T > ,
183
+ event_target : EventTarget ,
184
+ callbacks : Vec < SavedCallback > ,
185
+ }
186
+
187
+ impl < T : ' static > CallbackRegistry < T > {
188
+ pub fn new ( runner : EventLoopRunnerShared < T > , event_target : EventTarget ) -> Self {
189
+ CallbackRegistry { runner, event_target, callbacks : Vec :: new ( ) }
190
+ }
191
+
192
+ pub fn register_window_events ( & mut self ) {
193
+ self . add_event ( "pointerout" , |elrs, event : PointerEvent | {
174
194
elrs. send_event ( Event :: WindowEvent {
175
195
window_id : RootWI ( WindowId ) ,
176
196
event : WindowEvent :: CursorLeft {
177
197
device_id : RootDI ( DeviceId ( event. pointer_id ( ) ) ) ,
178
198
} ,
179
199
} ) ;
180
200
} ) ;
181
- add_event ( elrs , canvas , "pointerover" , |elrs, event : PointerEvent | {
201
+ self . add_event ( "pointerover" , |elrs, event : PointerEvent | {
182
202
elrs. send_event ( Event :: WindowEvent {
183
203
window_id : RootWI ( WindowId ) ,
184
204
event : WindowEvent :: CursorEntered {
185
205
device_id : RootDI ( DeviceId ( event. pointer_id ( ) ) ) ,
186
206
} ,
187
207
} ) ;
188
208
} ) ;
189
- add_event ( elrs , canvas , "pointermove" , |elrs, event : PointerEvent | {
209
+ self . add_event ( "pointermove" , |elrs, event : PointerEvent | {
190
210
elrs. send_event ( Event :: WindowEvent {
191
211
window_id : RootWI ( WindowId ) ,
192
212
event : WindowEvent :: CursorMoved {
@@ -199,7 +219,7 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &HtmlCanvas
199
219
} ,
200
220
} ) ;
201
221
} ) ;
202
- add_event ( elrs , canvas , "pointerup" , |elrs, event : PointerEvent | {
222
+ self . add_event ( "pointerup" , |elrs, event : PointerEvent | {
203
223
elrs. send_event ( Event :: WindowEvent {
204
224
window_id : RootWI ( WindowId ) ,
205
225
event : WindowEvent :: MouseInput {
@@ -210,7 +230,7 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &HtmlCanvas
210
230
} ,
211
231
} ) ;
212
232
} ) ;
213
- add_event ( elrs , canvas , "pointerdown" , |elrs, event : PointerEvent | {
233
+ self . add_event ( "pointerdown" , |elrs, event : PointerEvent | {
214
234
elrs. send_event ( Event :: WindowEvent {
215
235
window_id : RootWI ( WindowId ) ,
216
236
event : WindowEvent :: MouseInput {
@@ -221,7 +241,7 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &HtmlCanvas
221
241
} ,
222
242
} ) ;
223
243
} ) ;
224
- add_event ( elrs , canvas , "wheel" , |elrs, event : WheelEvent | {
244
+ self . add_event ( "wheel" , |elrs, event : WheelEvent | {
225
245
let x = event. delta_x ( ) ;
226
246
let y = event. delta_y ( ) ;
227
247
let delta = match event. delta_mode ( ) {
@@ -241,18 +261,17 @@ pub fn register<T: 'static>(elrs: &EventLoopRunnerShared<T>, canvas: &HtmlCanvas
241
261
} ) ;
242
262
}
243
263
244
- fn add_event < T : ' static , E , F > (
245
- elrs : & EventLoopRunnerShared < T > ,
246
- target : & EventTarget ,
247
- event : & str ,
264
+ fn add_event < E , F > (
265
+ & mut self ,
266
+ event : & ' static str ,
248
267
mut handler : F ,
249
268
) where
250
269
E : AsRef < web_sys:: Event > + wasm_bindgen:: convert:: FromWasmAbi + ' static ,
251
270
F : FnMut ( & EventLoopRunnerShared < T > , E ) + ' static ,
252
271
{
253
- let elrs = elrs . clone ( ) ;
272
+ let elrs = self . runner . clone ( ) ;
254
273
255
- let closure = Closure :: wrap ( Box :: new ( move |event : E | {
274
+ let callback = Closure :: wrap ( Box :: new ( move |event : E | {
256
275
// Don't capture the event if the events loop has been destroyed
257
276
match & * elrs. runner . borrow ( ) {
258
277
Some ( ref runner) if runner. control == ControlFlow :: Exit => return ,
@@ -267,8 +286,17 @@ fn add_event<T: 'static, E, F>(
267
286
handler ( & elrs, event) ;
268
287
} ) as Box < dyn FnMut ( E ) > ) ;
269
288
270
- target. add_event_listener_with_callback ( event, & closure. as_ref ( ) . unchecked_ref ( ) ) ;
271
- closure. forget ( ) ; // TODO: don't leak this.
289
+ self . event_target . add_event_listener_with_callback ( event, & callback. as_ref ( ) . unchecked_ref ( ) ) ;
290
+ self . callbacks . push ( SavedCallback { event, callback : Box :: new ( callback) } ) ;
291
+ }
292
+ }
293
+
294
+ impl < T : ' static > Drop for CallbackRegistry < T > {
295
+ fn drop ( & mut self ) {
296
+ for callback in self . callbacks . iter ( ) {
297
+ self . event_target . remove_event_listener_with_callback ( callback. event , callback. callback . as_ref ( ) . as_ref ( ) . unchecked_ref ( ) ) ;
298
+ }
299
+ }
272
300
}
273
301
274
302
impl < T > ELRShared < T > {
0 commit comments