virtual_desktop_manager\tray_plugins/
desktop_events_dynamic.rs1#![cfg(feature = "winvd_dynamic")]
5
6use windows::Win32::Foundation::HWND;
7
8use crate::{
9 dynamic_gui::DynamicUiHooks,
10 nwg_ext::FastTimerControl,
11 tray::{SystemTray, SystemTrayRef, TrayPlugin, TrayRoot},
12 vd,
13};
14use std::{any::TypeId, cell::Cell, cmp::Ordering, rc::Rc, time::Duration};
15
16const MESSAGE_OFFSET: u32 = 0x1400;
24
25#[derive(nwd::NwgPartial, Default)]
26pub struct DynamicVirtualDesktopEventManager {
27 tray_ref: SystemTrayRef,
28 #[nwg_control(interval: Duration::from_millis(1000))]
29 #[nwg_events(OnNotice: [Self::on_poll_timer])]
30 poll_timer: FastTimerControl,
31 registered_at: Cell<Option<HWND>>,
32 prev_window_count: Cell<u32>,
33}
34impl DynamicVirtualDesktopEventManager {
35 fn on_poll_timer(&self) {
36 let Some(tray) = self.tray_ref.get() else {
37 return;
38 };
39 let Some(Ok(_)) = vd::dynamic::get_loaded_symbols() else {
40 return;
41 };
42 let new_count = match vd::get_desktop_count() {
43 Ok(count) => count,
44 Err(e) => {
45 tracing::warn!("Failed to get desktop count from the dynamic library: {e:?}");
46 return;
47 }
48 };
49
50 match new_count.cmp(&self.prev_window_count.get()) {
51 Ordering::Equal => return,
52 Ordering::Less => {
53 tray.notify_desktop_event(vd::DesktopEvent::DesktopDestroyed {
54 destroyed: vd::get_desktop(self.prev_window_count.get() - 1),
55 fallback: match vd::get_current_desktop() {
56 Ok(desk) => desk,
57 Err(e) => {
58 tracing::warn!(
59 "Failed to get current desktop from the dynamic library: {e:?}"
60 );
61 return;
62 }
63 },
64 });
65 }
66 Ordering::Greater => {
67 tray.notify_desktop_event(vd::DesktopEvent::DesktopCreated(vd::get_desktop(
68 new_count - 1,
69 )));
70 }
71 }
72
73 self.prev_window_count.set(new_count);
74 }
75}
76impl DynamicUiHooks<SystemTray> for DynamicVirtualDesktopEventManager {
77 fn before_partial_build(
78 &mut self,
79 tray: &Rc<SystemTray>,
80 _should_build: &mut bool,
81 ) -> Option<(nwg::ControlHandle, TypeId)> {
82 self.tray_ref.set(tray);
83 Some((tray.root().window.handle, TypeId::of::<TrayRoot>()))
84 }
85 fn after_partial_build(&mut self, tray_ui: &Rc<SystemTray>) {
86 let Some(Ok(symbols)) = vd::dynamic::get_loaded_symbols() else {
87 self.poll_timer.cancel_last();
88 return;
89 };
90 let handle = tray_ui.root().window.handle;
91 let handle = HWND(
92 handle
93 .hwnd()
94 .expect("Root window should have a valid handle")
95 .cast(),
96 );
97
98 let res = unsafe { symbols.RegisterPostMessageHook(handle, MESSAGE_OFFSET) };
99 if let Err(e) = res {
100 tracing::error!("Failed to register post message hook for virtual desktop events from the dynamic library: {e:?}");
101 tray_ui.show_notification(
102 "Virtual Desktop Manager Error",
103 &format!("Failed to start listening for virtual desktop events: {e:?}"),
104 );
105 } else {
106 self.registered_at.set(Some(handle));
107 }
108 }
109 fn before_rebuild(&mut self, _dynamic_ui: &Rc<SystemTray>) {
110 let mut old = std::mem::take(self);
111 let Some(Ok(symbols)) = vd::dynamic::get_loaded_symbols() else {
112 return;
113 };
114
115 let Some(hwnd) = old.registered_at.get_mut().take() else {
116 return;
117 };
118
119 if let Err(e) = unsafe { symbols.UnregisterPostMessageHook(hwnd) } {
120 tracing::warn!("Failed to unregister post message hook for virtual desktop events from the dynamic library: {e:?}");
121 }
122 }
123 fn process_raw_event(
124 &self,
125 dynamic_ui: &Rc<SystemTray>,
126 hwnd: isize,
127 msg: u32,
128 w: usize,
129 l: isize,
130 _window: nwg::ControlHandle,
131 ) -> Option<isize> {
132 if Some(HWND(hwnd as *mut _)) != self.registered_at.get() {
133 return None;
134 }
135 if msg != MESSAGE_OFFSET {
136 return None;
137 }
138 dynamic_ui.notify_desktop_event(vd::DesktopEvent::DesktopChanged {
139 old: vd::get_desktop(w as u32),
140 new: vd::get_desktop(l as u32),
141 });
142 None
143 }
144}
145impl TrayPlugin for DynamicVirtualDesktopEventManager {}