1use std::collections::HashSet;
25use std::sync::atomic::{AtomicU64, Ordering};
26use std::sync::{Arc, OnceLock, RwLock};
27
28#[derive(Clone, Debug, Default)]
34pub struct EventData {
35 pub event_type: String,
37 pub target: u64,
39 pub current_target: u64,
42 pub local: (f64, f64),
44 pub client: (f64, f64),
46 pub key: String,
48 pub shift: bool,
50 pub ctrl: bool,
52 pub alt: bool,
54 pub super_: bool,
56 pub button: i64,
58 pub delta: (f64, f64),
60 pub value: String,
62 pub default_prevented: bool,
64 pub propagation_stopped: bool,
66 pub immediate_stopped: bool,
68}
69
70static CURRENT_EVENT: OnceLock<RwLock<EventData>> = OnceLock::new();
75
76fn current_cell() -> &'static RwLock<EventData> {
77 CURRENT_EVENT.get_or_init(|| RwLock::new(EventData::default()))
78}
79
80pub fn set_current_event(data: EventData) {
82 if let Ok(mut g) = current_cell().write() {
83 *g = data;
84 }
85}
86
87pub fn current_event() -> EventData {
89 current_cell().read().map(|g| g.clone()).unwrap_or_default()
90}
91
92pub fn set_current_target(node: u64) {
95 if let Ok(mut g) = current_cell().write() {
96 g.current_target = node;
97 }
98}
99
100pub fn event_target() -> u64 {
102 current_cell().read().map(|g| g.target).unwrap_or(0)
103}
104
105pub fn event_current_target() -> u64 {
107 current_cell().read().map(|g| g.current_target).unwrap_or(0)
108}
109
110pub fn event_type() -> String {
112 current_cell()
113 .read()
114 .map(|g| g.event_type.clone())
115 .unwrap_or_default()
116}
117
118pub fn event_position_local() -> (f64, f64) {
120 current_cell().read().map(|g| g.local).unwrap_or((0.0, 0.0))
121}
122
123pub fn event_position_client() -> (f64, f64) {
125 current_cell()
126 .read()
127 .map(|g| g.client)
128 .unwrap_or((0.0, 0.0))
129}
130
131pub fn event_key() -> String {
133 current_cell()
134 .read()
135 .map(|g| g.key.clone())
136 .unwrap_or_default()
137}
138
139pub fn event_modifiers() -> (bool, bool, bool, bool) {
141 current_cell()
142 .read()
143 .map(|g| (g.shift, g.ctrl, g.alt, g.super_))
144 .unwrap_or((false, false, false, false))
145}
146
147pub fn event_button() -> i64 {
149 current_cell().read().map(|g| g.button).unwrap_or(-1)
150}
151
152pub fn event_delta() -> (f64, f64) {
154 current_cell().read().map(|g| g.delta).unwrap_or((0.0, 0.0))
155}
156
157pub fn event_value() -> String {
159 current_cell()
160 .read()
161 .map(|g| g.value.clone())
162 .unwrap_or_default()
163}
164
165pub fn event_prevent_default() {
167 if let Ok(mut g) = current_cell().write() {
168 g.default_prevented = true;
169 }
170}
171
172pub fn event_stop_propagation() {
174 if let Ok(mut g) = current_cell().write() {
175 g.propagation_stopped = true;
176 }
177}
178
179pub fn event_stop_immediate_propagation() {
181 if let Ok(mut g) = current_cell().write() {
182 g.propagation_stopped = true;
183 g.immediate_stopped = true;
184 }
185}
186
187fn is_propagation_stopped() -> bool {
188 current_cell()
189 .read()
190 .map(|g| g.propagation_stopped)
191 .unwrap_or(false)
192}
193
194fn is_immediate_stopped() -> bool {
195 current_cell()
196 .read()
197 .map(|g| g.immediate_stopped)
198 .unwrap_or(false)
199}
200
201#[derive(Clone)]
207pub enum EventHandler {
208 Host,
211 Native(Arc<dyn Fn() + Send + Sync>),
214}
215
216impl std::fmt::Debug for EventHandler {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 match self {
219 EventHandler::Host => f.write_str("Host"),
220 EventHandler::Native(_) => f.write_str("Native"),
221 }
222 }
223}
224
225#[derive(Clone, Debug)]
227pub struct EventBinding {
228 pub token: u64,
230 pub node: u64,
232 pub event_type: String,
234 pub capture: bool,
236 pub handler: EventHandler,
238}
239
240static EVENT_TOKEN: AtomicU64 = AtomicU64::new(1);
241static BINDINGS: OnceLock<RwLock<Vec<EventBinding>>> = OnceLock::new();
242
243fn bindings() -> &'static RwLock<Vec<EventBinding>> {
244 BINDINGS.get_or_init(|| RwLock::new(Vec::new()))
245}
246
247pub fn mint_event_token() -> u64 {
249 EVENT_TOKEN.fetch_add(1, Ordering::Relaxed)
250}
251
252pub fn register_host_binding(token: u64, node: u64, event_type: String, capture: bool) {
255 register(EventBinding {
256 token,
257 node,
258 event_type,
259 capture,
260 handler: EventHandler::Host,
261 });
262}
263
264pub fn register_native_binding(
267 node: u64,
268 event_type: String,
269 capture: bool,
270 callback: Arc<dyn Fn() + Send + Sync>,
271) -> u64 {
272 let token = mint_event_token();
273 register(EventBinding {
274 token,
275 node,
276 event_type,
277 capture,
278 handler: EventHandler::Native(callback),
279 });
280 token
281}
282
283fn register(binding: EventBinding) {
284 if let Ok(mut b) = bindings().write() {
285 b.retain(|e| e.token != binding.token);
287 b.push(binding);
288 }
289}
290
291pub fn unregister_binding(token: u64) -> Option<EventBinding> {
293 let mut b = bindings().write().ok()?;
294 let idx = b.iter().position(|e| e.token == token)?;
295 Some(b.remove(idx))
296}
297
298pub fn clear_host_bindings() {
301 if let Ok(mut b) = bindings().write() {
302 b.retain(|e| !matches!(e.handler, EventHandler::Host));
303 }
304}
305
306pub fn take_host_bindings() -> Vec<EventBinding> {
313 let Ok(mut b) = bindings().write() else {
314 return Vec::new();
315 };
316 let mut taken = Vec::new();
317 b.retain(|e| {
318 if matches!(e.handler, EventHandler::Host) {
319 taken.push(e.clone());
320 false
321 } else {
322 true
323 }
324 });
325 taken
326}
327
328pub fn restore_host_bindings(prior: Vec<EventBinding>) -> Vec<u64> {
341 let Ok(mut b) = bindings().write() else {
342 return Vec::new();
343 };
344 let mut dropped = Vec::new();
345 let mut carried = Vec::new();
346 for e in prior {
347 let superseded = b
348 .iter()
349 .any(|n| n.node == e.node && n.event_type == e.event_type && n.capture == e.capture);
350 if superseded {
351 dropped.push(e.token);
352 } else {
353 carried.push(e);
354 }
355 }
356 carried.append(&mut b);
357 *b = carried;
358 dropped
359}
360
361pub fn clear_all_bindings() {
363 if let Ok(mut b) = bindings().write() {
364 b.clear();
365 }
366}
367
368fn bindings_for(event_type: &str) -> Vec<EventBinding> {
370 bindings()
371 .read()
372 .map(|b| {
373 b.iter()
374 .filter(|e| e.event_type == event_type)
375 .cloned()
376 .collect()
377 })
378 .unwrap_or_default()
379}
380
381pub fn has_bindings_for(event_type: &str) -> bool {
383 bindings()
384 .read()
385 .map(|b| b.iter().any(|e| e.event_type == event_type))
386 .unwrap_or(false)
387}
388
389static PREVENTED_CLICKS: OnceLock<RwLock<HashSet<u64>>> = OnceLock::new();
400
401fn prevented_clicks() -> &'static RwLock<HashSet<u64>> {
402 PREVENTED_CLICKS.get_or_init(|| RwLock::new(HashSet::new()))
403}
404
405pub fn clear_prevented_clicks() {
408 if let Ok(mut s) = prevented_clicks().write() {
409 s.clear();
410 }
411}
412
413pub fn mark_prevented_click(target: u64) {
416 if let Ok(mut s) = prevented_clicks().write() {
417 s.insert(target);
418 }
419}
420
421pub fn is_click_default_prevented(target: u64) -> bool {
425 prevented_clicks()
426 .read()
427 .map(|s| s.contains(&target))
428 .unwrap_or(false)
429}
430
431pub fn event_bubbles(event_type: &str) -> bool {
439 !matches!(
440 event_type,
441 "focus" | "blur" | "pointerenter" | "pointerleave" | "scroll"
442 )
443}
444
445#[derive(Clone, Copy, PartialEq)]
450enum Phase {
451 Capture,
452 Target,
453 Bubble,
454}
455
456pub fn dispatch(
466 data: EventData,
467 ancestors_root_first: &[u64],
468 bubbles: bool,
469 mut invoke_host: impl FnMut(u64),
470) -> EventData {
471 let etype = data.event_type.clone();
472 let target = data.target;
473 set_current_event(data);
474
475 let all = bindings_for(&etype);
476 if all.is_empty() {
477 return current_event();
478 }
479
480 let mut plan: Vec<(u64, Phase)> = Vec::new();
481 for &n in ancestors_root_first {
482 plan.push((n, Phase::Capture));
483 }
484 plan.push((target, Phase::Target));
485 if bubbles {
486 for &n in ancestors_root_first.iter().rev() {
487 plan.push((n, Phase::Bubble));
488 }
489 }
490
491 'outer: for (node, phase) in plan {
492 set_current_target(node);
493 for b in all.iter().filter(|b| b.node == node) {
494 let want = match phase {
495 Phase::Capture => b.capture,
496 Phase::Bubble => !b.capture,
497 Phase::Target => true,
498 };
499 if !want {
500 continue;
501 }
502 match &b.handler {
503 EventHandler::Native(f) => f(),
504 EventHandler::Host => invoke_host(b.token),
505 }
506 if is_immediate_stopped() {
507 break 'outer;
508 }
509 }
510 if is_propagation_stopped() {
511 break;
512 }
513 }
514
515 current_event()
516}
517
518#[cfg(test)]
523pub(crate) static TEST_GUARD: std::sync::Mutex<()> = std::sync::Mutex::new(());
524
525#[cfg(test)]
526mod tests {
527 use super::TEST_GUARD as GUARD;
528 use super::*;
529 use std::sync::Mutex;
530
531 fn record(log: &Arc<Mutex<Vec<String>>>, tag: &'static str) -> Arc<dyn Fn() + Send + Sync> {
532 let log = log.clone();
533 Arc::new(move || log.lock().unwrap().push(tag.to_string()))
534 }
535
536 #[test]
537 fn native_handler_fires_with_event_fields() {
538 let _g = GUARD.lock().unwrap();
539 clear_all_bindings();
540 let seen = Arc::new(Mutex::new((0u64, String::new())));
541 let s = seen.clone();
542 let cb: Arc<dyn Fn() + Send + Sync> = Arc::new(move || {
543 *s.lock().unwrap() = (event_target(), event_key());
544 });
545 register_native_binding(10, "keydown".into(), false, cb);
546 let data = EventData {
547 event_type: "keydown".into(),
548 target: 10,
549 key: "Enter".into(),
550 ..Default::default()
551 };
552 dispatch(data, &[], event_bubbles("keydown"), |_| {});
553 assert_eq!(*seen.lock().unwrap(), (10, "Enter".to_string()));
554 clear_all_bindings();
555 }
556
557 #[test]
558 fn capture_then_target_then_bubble_order() {
559 let _g = GUARD.lock().unwrap();
560 clear_all_bindings();
561 let log = Arc::new(Mutex::new(Vec::new()));
562 register_native_binding(1, "click".into(), true, record(&log, "root-cap"));
564 register_native_binding(1, "click".into(), false, record(&log, "root-bub"));
565 register_native_binding(2, "click".into(), true, record(&log, "mid-cap"));
566 register_native_binding(2, "click".into(), false, record(&log, "mid-bub"));
567 register_native_binding(3, "click".into(), true, record(&log, "leaf-cap"));
568 register_native_binding(3, "click".into(), false, record(&log, "leaf-bub"));
569 let data = EventData {
570 event_type: "click".into(),
571 target: 3,
572 ..Default::default()
573 };
574 dispatch(data, &[1, 2], true, |_| {});
575 assert_eq!(
576 *log.lock().unwrap(),
577 vec![
578 "root-cap", "mid-cap", "leaf-cap", "leaf-bub", "mid-bub", "root-bub", ]
582 );
583 clear_all_bindings();
584 }
585
586 #[test]
587 fn stop_propagation_halts_after_current_node() {
588 let _g = GUARD.lock().unwrap();
589 clear_all_bindings();
590 let log = Arc::new(Mutex::new(Vec::new()));
591 let l = log.clone();
592 register_native_binding(
593 2,
594 "click".into(),
595 false,
596 Arc::new(move || {
597 l.lock().unwrap().push("mid".to_string());
598 event_stop_propagation();
599 }),
600 );
601 register_native_binding(1, "click".into(), false, record(&log, "root"));
602 let data = EventData {
603 event_type: "click".into(),
604 target: 2,
605 ..Default::default()
606 };
607 dispatch(data, &[1], true, |_| {});
608 assert_eq!(*log.lock().unwrap(), vec!["mid"]);
610 clear_all_bindings();
611 }
612
613 #[test]
614 fn stop_immediate_halts_remaining_on_same_node() {
615 let _g = GUARD.lock().unwrap();
616 clear_all_bindings();
617 let log = Arc::new(Mutex::new(Vec::new()));
618 let l = log.clone();
619 register_native_binding(
620 5,
621 "click".into(),
622 false,
623 Arc::new(move || {
624 l.lock().unwrap().push("first".to_string());
625 event_stop_immediate_propagation();
626 }),
627 );
628 register_native_binding(5, "click".into(), false, record(&log, "second"));
629 let data = EventData {
630 event_type: "click".into(),
631 target: 5,
632 ..Default::default()
633 };
634 dispatch(data, &[], true, |_| {});
635 assert_eq!(*log.lock().unwrap(), vec!["first"]);
636 clear_all_bindings();
637 }
638
639 #[test]
640 fn prevent_default_records_on_returned_event() {
641 let _g = GUARD.lock().unwrap();
642 clear_all_bindings();
643 register_native_binding(7, "click".into(), false, Arc::new(event_prevent_default));
644 let data = EventData {
645 event_type: "click".into(),
646 target: 7,
647 ..Default::default()
648 };
649 let out = dispatch(data, &[], true, |_| {});
650 assert!(out.default_prevented);
651 clear_all_bindings();
652 }
653
654 #[test]
655 fn unbind_stops_delivery() {
656 let _g = GUARD.lock().unwrap();
657 clear_all_bindings();
658 let log = Arc::new(Mutex::new(Vec::new()));
659 let tok = register_native_binding(9, "click".into(), false, record(&log, "hit"));
660 assert!(unregister_binding(tok).is_some());
661 let data = EventData {
662 event_type: "click".into(),
663 target: 9,
664 ..Default::default()
665 };
666 dispatch(data, &[], true, |_| {});
667 assert!(log.lock().unwrap().is_empty());
668 clear_all_bindings();
669 }
670
671 #[test]
672 fn non_bubbling_event_skips_ancestors() {
673 let _g = GUARD.lock().unwrap();
674 clear_all_bindings();
675 let log = Arc::new(Mutex::new(Vec::new()));
676 register_native_binding(1, "focus".into(), false, record(&log, "root-bub"));
677 register_native_binding(2, "focus".into(), false, record(&log, "target"));
678 let data = EventData {
679 event_type: "focus".into(),
680 target: 2,
681 ..Default::default()
682 };
683 dispatch(data, &[1], event_bubbles("focus"), |_| {});
684 assert_eq!(*log.lock().unwrap(), vec!["target"]);
686 clear_all_bindings();
687 }
688}