1macro_rules! _forward_to_dynamic_ui {
7 ($dynamic_ui:ident => $($method_name:ident),* $(,)?) => {
8 $(
9 fn $method_name(&self) {
10 let Some($dynamic_ui) = self.$dynamic_ui.get() else { return };
11 $dynamic_ui.$method_name();
12 }
13 )*
14 }
15}
16
17#[allow(unused_imports)]
18pub(crate) use _forward_to_dynamic_ui as forward_to_dynamic_ui;
19
20use std::{
21 any::{self, TypeId},
22 cell::{Cell, OnceCell, Ref, RefCell},
23 collections::VecDeque,
24 fmt,
25 marker::PhantomData,
26 ops::Deref,
27 rc::{Rc, Weak},
28};
29
30use crate::nwg_ext::enum_child_windows;
31
32pub trait PartialUiDyn {
34 fn build_partial_dyn(
36 &mut self,
37 parent: Option<nwg::ControlHandle>,
38 ) -> Result<(), nwg::NwgError>;
39
40 fn process_event_dyn(
42 &self,
43 _evt: nwg::Event,
44 _evt_data: &nwg::EventData,
45 _handle: nwg::ControlHandle,
46 ) {
47 }
48
49 fn handles_dyn(&self) -> Vec<&'_ nwg::ControlHandle> {
51 vec![]
52 }
53}
54impl<T> PartialUiDyn for T
55where
56 T: nwg::PartialUi,
57{
58 fn build_partial_dyn(
59 &mut self,
60 parent: Option<nwg::ControlHandle>,
61 ) -> Result<(), nwg::NwgError> {
62 <T as nwg::PartialUi>::build_partial(self, parent)
63 }
64 fn process_event_dyn(
65 &self,
66 evt: nwg::Event,
67 evt_data: &nwg::EventData,
68 handle: nwg::ControlHandle,
69 ) {
70 <T as nwg::PartialUi>::process_event(self, evt, evt_data, handle)
71 }
72 fn handles_dyn(&self) -> Vec<&'_ nwg::ControlHandle> {
73 <T as nwg::PartialUi>::handles(self)
74 }
75}
76
77pub trait AsAny {
79 fn as_any(&self) -> &dyn any::Any;
80 fn type_name(&self) -> &'static str;
81 fn swap_dyn(&mut self, other: &mut dyn any::Any) -> bool;
84}
85impl<T> AsAny for T
86where
87 T: Sized + 'static,
88{
89 fn as_any(&self) -> &dyn any::Any {
90 self
91 }
92 #[cfg(debug_assertions)]
93 fn type_name(&self) -> &'static str {
94 any::type_name::<T>()
95 }
96 #[cfg(not(debug_assertions))]
97 fn type_name(&self) -> &'static str {
98 any::type_name::<dyn AsAny>()
99 }
100 fn swap_dyn(&mut self, other: &mut dyn any::Any) -> bool {
101 if let Some(other) = <dyn any::Any>::downcast_mut::<T>(other) {
102 core::mem::swap(self, other);
103 true
104 } else {
105 false
106 }
107 }
108}
109
110pub trait DynWithDefault: AsAny {
111 fn with_default_mut(&mut self, f: &mut dyn FnMut(&mut dyn DynWithDefault, &mut dyn any::Any));
116
117 fn clear_and_inspect_old(
120 &mut self,
121 f: &mut dyn FnMut(&mut dyn DynWithDefault, &mut dyn any::Any),
122 ) {
123 self.with_default_mut(&mut |current, new| {
124 current.swap_dyn(new);
125 let old = new;
126 f(current, old);
127 });
128 }
129
130 fn clear(&mut self) {
131 self.with_default_mut(&mut |current, new| {
132 current.swap_dyn(new);
133 });
134 }
135}
136impl<T> DynWithDefault for T
137where
138 T: Default + AsAny + 'static,
139{
140 fn with_default_mut(&mut self, f: &mut dyn FnMut(&mut dyn DynWithDefault, &mut dyn any::Any)) {
141 f(self, &mut T::default())
142 }
143 fn clear_and_inspect_old(
144 &mut self,
145 f: &mut dyn FnMut(&mut dyn DynWithDefault, &mut dyn any::Any),
146 ) {
147 let mut old = core::mem::take(self);
148 f(self, &mut old);
149 }
150 fn clear(&mut self) {
151 *self = T::default();
152 }
153}
154
155pub trait DynamicUiHooks<T: ?Sized>: PartialUiDyn + DynWithDefault + 'static {
204 fn before_partial_build(
215 &mut self,
216 _dynamic_ui: &Rc<T>,
217 _should_build: &mut bool,
218 ) -> Option<(nwg::ControlHandle, TypeId)>;
219
220 fn after_partial_build(&mut self, _dynamic_ui: &Rc<T>) {}
224
225 fn after_handles<'a>(
228 &'a self,
229 _dynamic_ui: &Rc<T>,
230 _handles: &mut Vec<&'a nwg::ControlHandle>,
231 ) {
232 }
233
234 fn need_raw_events_for_children(&self) -> bool {
237 false
238 }
239
240 fn after_process_events(
244 &self,
245 _dynamic_ui: &Rc<T>,
246 _evt: nwg::Event,
247 _evt_data: &nwg::EventData,
248 _handle: nwg::ControlHandle,
249 _window: nwg::ControlHandle,
250 ) {
251 }
252 fn process_raw_event(
261 &self,
262 _dynamic_ui: &Rc<T>,
263 _hwnd: isize,
264 _msg: u32,
265 _w: usize,
266 _l: isize,
267 _window: nwg::ControlHandle,
268 ) -> Option<isize> {
269 None
270 }
271
272 fn need_rebuild(&self, _dynamic_ui: &Rc<T>) -> bool {
279 false
280 }
281 fn is_ordered_in_parent(&self) -> bool {
287 true
288 }
289 fn before_rebuild(&mut self, _dynamic_ui: &Rc<T>) {
292 self.clear();
293 }
294}
295
296pub trait DynamicUiWrapper: Sized + 'static {
297 type Hooks: ?Sized + DynamicUiHooks<Self>;
298
299 fn get_dynamic_ui(&self) -> &DynamicUi<Self>;
300 fn get_dynamic_ui_mut(&mut self) -> &mut DynamicUi<Self>;
301}
302
303pub struct DynamicUiRef<T>(OnceCell<Weak<T>>);
306impl<T> DynamicUiRef<T> {
307 pub const fn new() -> Self {
308 Self(OnceCell::new())
309 }
310 pub fn set(&self, dynamic_ui: &Rc<T>) {
311 let _ = self.0.set(Rc::downgrade(dynamic_ui));
312 }
313 pub fn is_set(&self) -> bool {
314 self.0.get().map_or(false, |tray| tray.strong_count() > 0)
315 }
316 pub fn get(&self) -> Option<Rc<T>> {
317 self.0.get().and_then(Weak::upgrade)
318 }
319}
320impl<T> fmt::Debug for DynamicUiRef<T> {
321 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322 f.debug_tuple("DynamicUiRef").field(&self.0).finish()
323 }
324}
325impl<T> Clone for DynamicUiRef<T> {
326 fn clone(&self) -> Self {
327 Self(self.0.clone())
328 }
329}
330impl<T> Default for DynamicUiRef<T> {
331 fn default() -> Self {
332 Self(OnceCell::new())
333 }
334}
335impl<T> From<&'_ Rc<T>> for DynamicUiRef<T> {
336 fn from(dynamic_ui: &Rc<T>) -> Self {
337 let this = Self::new();
338 this.set(dynamic_ui);
339 this
340 }
341}
342
343struct DelayEventsGuard<'a>(&'a Cell<bool>);
346impl<'a> DelayEventsGuard<'a> {
347 fn new(delay_events: &'a Cell<bool>) -> Self {
348 delay_events.set(true);
349 Self(delay_events)
350 }
351}
352impl Drop for DelayEventsGuard<'_> {
353 fn drop(&mut self) {
354 self.0.set(false);
355 }
356}
357
358#[derive(Debug, Clone, Copy, PartialEq, Eq)]
359enum PluginState {
360 Destroyed,
361 Built,
362}
363
364struct PluginData<T: DynamicUiWrapper> {
366 ui: Box<T::Hooks>,
367 parent_id: Option<TypeId>,
369 state: PluginState,
371}
372impl<T: DynamicUiWrapper> PluginData<T> {
373 fn new(ui: Box<T::Hooks>) -> Self {
374 Self {
375 ui,
376 parent_id: None,
377 state: PluginState::Destroyed,
378 }
379 }
380 fn after_build(ui: Box<T::Hooks>, parent_id: Option<TypeId>) -> Self {
381 Self {
382 ui,
383 parent_id,
384 state: PluginState::Built,
385 }
386 }
387 fn id(&self) -> TypeId {
388 <T::Hooks as AsAny>::as_any(&*self.ui).type_id()
389 }
390 fn plugin_type_name(&self) -> &'static str {
391 <T::Hooks as AsAny>::type_name(&*self.ui)
392 }
393}
394enum RawEventHandlerData {
395 WithChildren(Vec<nwg::RawEventHandler>),
396 ParentOnly(nwg::RawEventHandler),
397 FailedToBind,
398}
399impl RawEventHandlerData {
400 fn as_slice(&self) -> &[nwg::RawEventHandler] {
401 match self {
402 RawEventHandlerData::WithChildren(handlers) => handlers.as_slice(),
403 RawEventHandlerData::ParentOnly(parent) => core::array::from_ref(parent),
404 RawEventHandlerData::FailedToBind => &[],
405 }
406 }
407}
408struct EventHandlerData {
409 plugin_id: TypeId,
410 window: nwg::ControlHandle,
411 handler: nwg::EventHandler,
412 raw_handler: RawEventHandlerData,
413}
414impl Drop for EventHandlerData {
415 fn drop(&mut self) {
416 nwg::unbind_event_handler(&self.handler);
417 for raw_handler in self.raw_handler.as_slice() {
418 let _ = nwg::unbind_raw_event_handler(raw_handler);
419 }
420 }
421}
422
423pub struct DynamicUi<T: DynamicUiWrapper> {
426 ui_list: RefCell<Vec<PluginData<T>>>,
445
446 #[allow(clippy::type_complexity)]
448 event_queue: RefCell<VecDeque<Box<dyn FnOnce(&Rc<T>)>>>,
449
450 delay_events: Cell<bool>,
454
455 should_destroy: Cell<bool>,
457
458 event_handlers: RefCell<Vec<EventHandlerData>>,
464
465 prevent_recursive_events: Cell<bool>,
467
468 self_wrapper_ty: PhantomData<T>,
469}
470impl<T: DynamicUiWrapper> Default for DynamicUi<T> {
471 fn default() -> Self {
472 Self {
473 ui_list: Default::default(),
474 event_queue: Default::default(),
475 delay_events: Default::default(),
476 should_destroy: Default::default(),
477 event_handlers: Default::default(),
478 prevent_recursive_events: Default::default(),
479 self_wrapper_ty: Default::default(),
480 }
481 }
482}
483impl<T> fmt::Debug for DynamicUi<T>
484where
485 T: DynamicUiWrapper,
486{
487 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
488 f.debug_struct("DynamicUi")
489 .field(
490 "plugins",
491 &self.ui_list.try_borrow().map_or_else(
492 |e| vec![e.to_string()],
493 |plugins| {
494 plugins
495 .iter()
496 .map(|p| <T::Hooks as AsAny>::type_name(&*p.ui).to_string())
497 .collect::<Vec<_>>()
498 },
499 ),
500 )
501 .field(
502 "event_queue_len",
503 &self.event_queue.try_borrow().map(|q| q.len()).ok(),
504 )
505 .field("delay_events", &self.delay_events)
506 .finish()
507 }
508}
509impl<T> DynamicUi<T>
510where
511 T: DynamicUiWrapper,
512{
513 pub fn new(ui_list: Vec<Box<T::Hooks>>) -> Self {
514 let mut ui_list: Vec<_> = ui_list.into_iter().map(|ui| PluginData::new(ui)).collect();
515 ui_list.shrink_to_fit();
516 Self {
517 ui_list: RefCell::new(ui_list),
518 event_queue: Default::default(),
519 delay_events: Default::default(),
520 should_destroy: Default::default(),
521 event_handlers: Default::default(),
522 prevent_recursive_events: Default::default(),
523 self_wrapper_ty: Default::default(),
524 }
525 }
526
527 pub fn set_prevent_recursive_events(&self, value: bool) {
528 self.prevent_recursive_events.set(value);
529 }
530
531 pub fn with_paused_events<R>(&self, f: impl FnOnce() -> R) -> R {
533 let _prevent_other_actions = DelayEventsGuard::new(&self.delay_events);
534 f()
535 }
536
537 pub fn get_ui<U: DynamicUiHooks<T>>(&self) -> Option<Ref<'_, U>> {
541 let guard = self.ui_list.borrow();
546 Ref::filter_map(guard, |guard| {
547 guard
548 .iter()
549 .find_map(|p| <T::Hooks as AsAny>::as_any(&*p.ui).downcast_ref::<U>())
550 })
551 .ok()
552 }
553 pub fn with_all_ui<R>(&self, f: impl FnOnce(&mut dyn Iterator<Item = &T::Hooks>) -> R) -> R {
554 f(&mut self
556 .ui_list
557 .borrow()
558 .iter()
559 .filter(|item| item.state == PluginState::Built)
560 .map(|p| &*p.ui))
561 }
562 pub fn for_each_ui(&self, f: impl FnMut(&T::Hooks)) {
563 self.ui_list
565 .borrow()
566 .iter()
567 .filter(|item| item.state == PluginState::Built)
568 .map(|p| &*p.ui)
569 .for_each(f);
570 }
571 pub fn maybe_preform_action<R>(wrapper: &Rc<T>, action: impl FnOnce(&Rc<T>) -> R) -> Option<R> {
574 let this = wrapper.get_dynamic_ui();
575 if this.delay_events.get() {
576 tracing::warn!("A UI action was not performed because the UI was being rebuilt");
577 None
578 } else {
579 let mut state = Some(Err(action));
580 Self::preform_action_and_maybe_rebuild(
581 wrapper,
582 Some(&mut |wrapper| {
583 if let Some(Err(action)) = state.take() {
584 state = Some(Ok(action(wrapper)));
585 }
586 }),
587 );
588 Some(
589 state
590 .expect("callback panicked")
591 .ok()
592 .expect("callback never called"),
593 )
594 }
595 }
596 pub fn preform_action<R>(
602 wrapper: &Rc<T>,
603 action: impl FnOnce(&Rc<T>, bool) -> R + 'static,
604 ) -> Option<R> {
605 let this = wrapper.get_dynamic_ui();
606 if this.delay_events.get() {
607 this.event_queue
608 .borrow_mut()
609 .push_back(Box::new(move |wrapper| drop(action(wrapper, true))));
610 None
611 } else {
612 let mut state = Some(Err(action));
613 Self::preform_action_and_maybe_rebuild(
614 wrapper,
615 Some(&mut |wrapper| {
616 if let Some(Err(action)) = state.take() {
617 state = Some(Ok(action(wrapper, false)));
618 }
619 }),
620 );
621 Some(
622 state
623 .expect("callback panicked")
624 .ok()
625 .expect("callback never called"),
626 )
627 }
628 }
629 pub fn preform_action_adv<S>(
630 wrapper: &Rc<T>,
631 state: S,
632 delay_action: impl FnOnce(S) -> Option<Box<dyn FnOnce(&Rc<T>) + 'static>>,
633 preform_action: impl FnOnce(S),
634 ) {
635 let this = wrapper.get_dynamic_ui();
636 if this.delay_events.get() {
637 if let Some(delayed) = delay_action(state) {
638 this.event_queue.borrow_mut().push_back(delayed);
639 }
640 } else {
641 let mut state = Some((state, preform_action));
642 Self::preform_action_and_maybe_rebuild(
643 wrapper,
644 Some(&mut |_wrapper| {
645 if let Some((state, preform_action)) = state.take() {
646 preform_action(state);
647 }
648 }),
649 );
650 }
651 }
652 #[allow(clippy::type_complexity)]
653 fn preform_action_and_maybe_rebuild(
654 wrapper: &Rc<T>,
655 mut action: Option<&mut dyn FnMut(&Rc<T>)>,
656 ) {
657 let this = wrapper.get_dynamic_ui();
658 if this.delay_events.get() {
659 return;
660 }
661
662 loop {
663 if this.should_destroy.get() {
664 Self::destroy_ui(wrapper);
665 return;
666 }
667
668 let first_queued = this.event_queue.borrow_mut().pop_front();
669 if let Some(queued) = first_queued {
670 queued(wrapper);
671 continue;
672 } else if let Some(action) = action.take() {
673 action(wrapper);
674 } else {
675 }
678
679 let mut rebuild_ids = VecDeque::new();
681 for item in &*this.ui_list.borrow() {
682 if item.ui.need_rebuild(wrapper) {
683 rebuild_ids.push_back(item.id());
684 tracing::info!("Dynamic ui required rebuild: {}", item.plugin_type_name());
685 }
686 }
687 if rebuild_ids.is_empty() {
688 return;
689 }
690
691 let _prevent_other_actions = DelayEventsGuard::new(&this.delay_events);
693 {
694 let Ok(mut guard) = this.ui_list.try_borrow_mut() else {
695 tracing::warn!(
699 "Failed to lock plugin list in DynamicUi, this should never happen"
700 );
701 return;
702 };
703 let len = guard.len();
704 let mut affected_parents = Vec::new();
705 while let Some(rebuild_id) = rebuild_ids.pop_front() {
706 affected_parents.clear();
707 for ix in 0..len {
708 let item = &guard[ix];
709 let plugin = &item.ui;
710 let parent_id = item.parent_id;
711 let plugin_id = item.id();
712
713 if !affected_parents.is_empty() {
714 if let Some(parent_id) = parent_id {
719 if !affected_parents.contains(&parent_id) {
720 continue; }
722 } else {
723 continue; }
725 if !plugin.is_ordered_in_parent() {
727 continue;
730 }
731 rebuild_ids.retain(|&id| id != plugin_id);
733 } else if plugin_id != rebuild_id {
734 continue; }
736 let prev_state = item.state;
737
738 let mut plugin = guard.swap_remove(ix).ui;
740
741 drop(guard);
743 tracing::info!(
744 "Rebuilding dynamic ui: {}",
745 <T::Hooks as AsAny>::type_name(&*plugin)
746 );
747
748 if prev_state == PluginState::Built {
749 let mut handles = plugin.handles_dyn();
752 plugin.after_handles(wrapper, &mut handles);
753 Self::unbind_specific_event_handlers(wrapper, &handles);
754
755 plugin.before_rebuild(wrapper);
756 }
757 let mut should_build = true;
758 let parent = plugin.before_partial_build(wrapper, &mut should_build);
759 let (plugin_data, res) = if should_build {
760 let res = plugin.build_partial_dyn(parent.map(|p| p.0));
761 <T::Hooks as DynamicUiHooks<T>>::after_partial_build(
762 &mut plugin,
763 wrapper,
764 );
765
766 let parent_id = parent.map(|(_, id)| id);
767 if let Some(parent_id) = parent_id {
769 if !affected_parents.contains(&parent_id) {
770 affected_parents.push(parent_id);
771 }
772 }
773
774 (PluginData::after_build(plugin, parent_id), res)
775 } else {
776 (PluginData::new(plugin), Ok(()))
777 };
778
779 guard = this.ui_list.borrow_mut();
781 guard.push(plugin_data);
782 guard.swap(ix, len - 1);
783
784 if let Err(e) = res {
786 tracing::error!(
787 "Rebuild of dynamic ui {} failed: {e:?}",
788 guard[ix].plugin_type_name()
789 );
790 }
791
792 for child in &*guard {
794 if child.parent_id == Some(plugin_id) {
798 let id = child.id();
799 if !rebuild_ids.contains(&id) {
800 rebuild_ids.push_back(id);
801 }
802 }
803 }
804
805 if affected_parents.is_empty() {
806 break; }
808 }
809 }
810 }
811
812 Self::bind_event_handlers(wrapper);
814
815 }
817 }
818
819 fn initial_build(wrapper: &Rc<T>) -> Result<(), nwg::NwgError> {
820 {
821 let this = wrapper.get_dynamic_ui();
822 let ui_list = &this.ui_list;
823 let mut guard = ui_list.borrow_mut();
824
825 let _prevent_other_actions = DelayEventsGuard::new(&this.delay_events);
828
829 let mut plugin_ix = 0;
831 loop {
832 let len = guard.len();
833 if plugin_ix >= len {
834 break;
835 }
836 let mut plugin = guard.swap_remove(plugin_ix).ui;
838
839 drop(guard);
841 let mut should_build = true;
842 let parent = plugin.before_partial_build(wrapper, &mut should_build);
843 let (plugin, res) = if should_build {
844 let res = plugin.build_partial_dyn(parent.map(|p| p.0));
845 DynamicUiHooks::after_partial_build(&mut *plugin, wrapper);
846
847 let parent_id = parent.map(|(_, id)| id);
848 (PluginData::after_build(plugin, parent_id), res)
849 } else {
850 (PluginData::new(plugin), Ok(()))
851 };
852
853 guard = ui_list.borrow_mut();
855 guard.insert(len - 1, plugin);
856 guard.swap(plugin_ix, len - 1);
857
858 res?;
859
860 plugin_ix += 1;
861 }
862 }
863
864 Ok(())
865 }
866 fn all_handles(wrapper: &Rc<T>) -> Vec<(TypeId, bool, nwg::ControlHandle)> {
867 wrapper
868 .get_dynamic_ui()
869 .ui_list
870 .borrow()
871 .iter()
872 .filter(|item| item.state == PluginState::Built)
873 .flat_map(|item| {
874 let mut item_handles = item.ui.handles_dyn();
877 item.ui.after_handles(wrapper, &mut item_handles);
879
880 let raw_child_handlers = item.ui.need_raw_events_for_children();
881
882 let id = item.id();
884 item_handles
885 .into_iter()
886 .copied()
887 .map(move |handle| (id, raw_child_handlers, handle))
888 })
889 .collect()
890 }
891 fn process_events_for_plugin_and_children(
892 wrapper: &Rc<T>,
893 plugin_id: TypeId,
894 mut f: impl FnMut(&PluginData<T>),
895 ) {
896 let this = wrapper.get_dynamic_ui();
897 let _event_guard = this
898 .prevent_recursive_events
899 .get()
900 .then(|| DelayEventsGuard::new(&this.delay_events));
901 let guard = this.ui_list.borrow();
902 let mut parent_ids = Vec::<TypeId>::with_capacity(guard.len());
903
904 for item in &*guard {
905 if item.state != PluginState::Built {
906 continue;
907 }
908 if parent_ids.is_empty() {
909 let id = item.id();
910 if id != plugin_id {
911 continue; }
913 parent_ids.push(id);
914 } else if let Some(parent_id) = item.parent_id {
915 if !parent_ids.contains(&parent_id) {
916 continue; } else {
918 parent_ids.push(item.id());
919 }
920 } else {
921 continue; }
923
924 f(item);
925 }
926 }
927 fn process_event(
928 wrapper: &Rc<T>,
929 evt: nwg::Event,
930 evt_data: &nwg::EventData,
931 handle: nwg::ControlHandle,
932 window: nwg::ControlHandle,
933 plugin_id: TypeId,
934 ) {
935 if !matches!(
936 evt,
937 nwg::Event::OnNotice | nwg::Event::OnMouseMove | nwg::Event::Unknown
938 ) {
939 tracing::trace!(
941 event = ?evt,
942 event_data = ?evt_data,
943 handle = ?handle,
944 window = ?window,
945 "SystemTrayUiAdaptor::process_event()"
946 );
947 }
948 Self::process_events_for_plugin_and_children(wrapper, plugin_id, move |item| {
949 item.ui.process_event_dyn(evt, evt_data, handle);
950 item.ui
951 .after_process_events(wrapper, evt, evt_data, handle, window);
952 });
953 }
954 fn process_raw_event(
955 wrapper: &Rc<T>,
956 hwnd: isize,
957 msg: u32,
958 w: usize,
959 l: isize,
960 window: nwg::ControlHandle,
961 plugin_id: TypeId,
962 ) -> Option<isize> {
963 let mut first = None;
964 Self::process_events_for_plugin_and_children(wrapper, plugin_id, |item| {
965 if let Some(result) = item.ui.process_raw_event(wrapper, hwnd, msg, w, l, window) {
966 if let Some(first_result) = first {
967 tracing::warn!(
968 ?first_result,
969 ?result,
970 "Multiple raw event handlers returned a result, the first result will be used"
971 )
972 } else {
973 first = Some(result);
974 }
975 }
976 });
977 first
978 }
979 fn unbind_specific_event_handlers(wrapper: &Rc<T>, window_handles: &[&nwg::ControlHandle]) {
980 let this = wrapper.get_dynamic_ui();
981 this.event_handlers
982 .borrow_mut()
983 .retain(|data| !window_handles.contains(&&data.window));
984 }
985 fn unbind_event_handlers(wrapper: &Rc<T>) {
986 let this = wrapper.get_dynamic_ui();
987 this.event_handlers.take();
988 }
989 fn bind_event_handlers(wrapper: &Rc<T>) {
990 let this = wrapper.get_dynamic_ui();
991 let window_handles = Self::all_handles(wrapper);
992 let current_handles = this
993 .event_handlers
994 .borrow()
995 .iter()
996 .map(|data| {
997 (
998 data.plugin_id,
999 matches!(data.raw_handler, RawEventHandlerData::WithChildren(_)),
1000 data.window,
1001 )
1002 })
1003 .collect::<Vec<_>>();
1004 if window_handles == current_handles {
1005 return;
1006 }
1007 tracing::debug!(
1008 ?window_handles,
1009 previous_handles = ?current_handles,
1010 "Binding event handlers to windows"
1011 );
1012
1013 Self::unbind_event_handlers(wrapper);
1014
1015 let mut handlers = Vec::with_capacity(window_handles.len());
1016 for &(plugin_id, raw_child_events, window) in window_handles.iter() {
1017 let evt_ui = Rc::downgrade(wrapper);
1020 let handle_raw_events = move |hwnd, msg, l, w| {
1021 if let Some(ui) = evt_ui.upgrade() {
1022 Self::preform_action(&ui, {
1024 move |ui, delayed| {
1025 let res = DynamicUi::process_raw_event(
1026 ui,
1027 hwnd as isize,
1028 msg,
1029 l,
1030 w,
1031 window,
1032 plugin_id,
1033 );
1034 if let (Some(res), true) = (res, delayed) {
1035 tracing::warn!(
1036 return_value = ?res,
1037 "Delayed handling of raw event and now can't handle return value"
1038 );
1039 }
1040 res
1041 }
1042 })
1043 .flatten()
1044 .inspect(|val| {
1045 tracing::debug!(
1046 return_value = ?val,
1047 "Returned custom value from raw event handle"
1048 );
1049 })
1050 } else {
1051 None
1052 }
1053 };
1054 let raw_event_handler = match nwg::bind_raw_event_handler(
1055 &window,
1056 0x85dead,
1058 handle_raw_events.clone(),
1059 ) {
1060 Ok(event_handler) => {
1061 if raw_child_events {
1062 if let Some(hwnd) = window.hwnd() {
1063 let mut handlers = vec![event_handler];
1064 enum_child_windows(
1065 Some(windows::Win32::Foundation::HWND(hwnd.cast())),
1066 |child| {
1067 match nwg::bind_raw_event_handler(
1068 &window,
1069 0xc85dead,
1071 handle_raw_events.clone(),
1072 ) {
1073 Ok(handler) => handlers.push(handler),
1074 Err(e) => {
1075 tracing::warn!(?window, ?child, "Failed to register raw event handler for child window: {e}");
1076 }
1077 }
1078 std::ops::ControlFlow::Continue(())
1079 },
1080 );
1081 RawEventHandlerData::WithChildren(handlers)
1082 } else {
1083 tracing::warn!("Could not find child windows since parent handle wasn't for a window");
1084 RawEventHandlerData::ParentOnly(event_handler)
1085 }
1086 } else {
1087 RawEventHandlerData::ParentOnly(event_handler)
1088 }
1089 }
1090 Err(e) => {
1091 tracing::warn!(?window, "Failed to register raw event handler: {e}");
1092 RawEventHandlerData::FailedToBind
1093 }
1094 };
1095
1096 let evt_ui = Rc::downgrade(wrapper);
1097 let handle_events = move |evt, evt_data, handle| {
1098 if let Some(ui) = evt_ui.upgrade() {
1099 Self::preform_action(&ui, {
1101 move |ui, _| {
1102 DynamicUi::process_event(ui, evt, &evt_data, handle, window, plugin_id);
1103 }
1104 });
1105 }
1106 };
1107 let event_handler = nwg::full_bind_event_handler(&window, handle_events);
1108
1109 handlers.push(EventHandlerData {
1110 plugin_id,
1111 window,
1112 handler: event_handler,
1113 raw_handler: raw_event_handler,
1114 });
1115 }
1116
1117 *this.event_handlers.borrow_mut() = handlers;
1118 }
1119 fn destroy_ui(wrapper: &Rc<T>) {
1122 let this = wrapper.get_dynamic_ui();
1123 this.should_destroy.set(true);
1124
1125 Self::unbind_event_handlers(wrapper);
1126
1127 if this.delay_events.get() {
1128 return;
1129 }
1130 let _prevent_other_actions = DelayEventsGuard::new(&this.delay_events);
1131 for item in &mut *this.ui_list.borrow_mut() {
1132 if item.state == PluginState::Destroyed {
1133 continue;
1134 }
1135 item.ui.before_rebuild(wrapper);
1136 item.state = PluginState::Destroyed;
1137 }
1138 }
1139}
1140
1141pub struct DynamicUiOwner<T>(Rc<T>)
1143where
1144 T: DynamicUiWrapper;
1145impl<T> Deref for DynamicUiOwner<T>
1146where
1147 T: DynamicUiWrapper,
1148{
1149 type Target = Rc<T>;
1150
1151 fn deref(&self) -> &Self::Target {
1152 &self.0
1153 }
1154}
1155impl<T> Drop for DynamicUiOwner<T>
1156where
1157 T: DynamicUiWrapper,
1158{
1159 fn drop(&mut self) {
1160 DynamicUi::destroy_ui(&self.0);
1161 }
1162}
1163
1164impl<T> nwg::NativeUi<DynamicUiOwner<T>> for Rc<T>
1176where
1177 T: DynamicUiWrapper,
1178{
1179 fn build_ui(data: Self) -> Result<DynamicUiOwner<T>, nwg::NwgError> {
1180 let data = DynamicUiOwner(data);
1181 DynamicUi::initial_build(&data.0)?;
1182 DynamicUi::bind_event_handlers(&data.0);
1183 Ok(data)
1184 }
1185}