virtual_desktop_manager\tray_plugins/
desktop_events.rs

1//! Tray plugin that forwards Virtual Desktop events to the tray UI using
2//! [`winvd`] crate.
3
4#![cfg(feature = "winvd_static")]
5use crate::{
6    dynamic_gui::DynamicUiHooks,
7    tray::{SystemTray, SystemTrayRef, TrayPlugin, TrayRoot},
8};
9use std::{any::TypeId, cell::RefCell, rc::Rc, sync::mpsc};
10
11#[derive(nwd::NwgPartial, Default)]
12pub struct VirtualDesktopEventManager {
13    tray: SystemTrayRef,
14
15    /// State used to keep listening to Virtual Desktop events.
16    background: RefCell<
17        Option<(
18            winvd::DesktopEventThread,
19            mpsc::Receiver<winvd::DesktopEvent>,
20        )>,
21    >,
22
23    /// This notice will be triggered when there are new Virtual Desktop events
24    /// that should be handled.
25    #[nwg_control]
26    #[nwg_events( OnNotice: [Self::on_background_event] )]
27    background_notice: nwg::Notice,
28}
29impl DynamicUiHooks<SystemTray> for VirtualDesktopEventManager {
30    fn before_partial_build(
31        &mut self,
32        tray: &Rc<SystemTray>,
33        _should_build: &mut bool,
34    ) -> Option<(nwg::ControlHandle, TypeId)> {
35        self.tray.set(tray);
36        Some((tray.root().window.handle, TypeId::of::<TrayRoot>()))
37    }
38    fn after_partial_build(&mut self, tray_ui: &Rc<SystemTray>) {
39        let (sender, receiver_1) = mpsc::channel::<winvd::DesktopEvent>();
40        match winvd::listen_desktop_events(sender) {
41            Err(e) => {
42                tray_ui.show_notification(
43                    "Virtual Desktop Manager Error",
44                    &format!("Failed to start listening for virtual desktop events: {e:?}"),
45                );
46            }
47            Ok(guard) => {
48                let (sender, receiver_2) = mpsc::channel::<winvd::DesktopEvent>();
49                let notice = self.background_notice.sender();
50                std::thread::spawn(move || {
51                    // Forward events and notify the main thread that there are
52                    // more messages in the channel.
53                    for event in receiver_1 {
54                        if sender.send(event).is_err() {
55                            return;
56                        }
57                        notice.notice();
58                    }
59                });
60                self.background.replace(Some((guard, receiver_2)));
61            }
62        }
63    }
64    fn before_rebuild(&mut self, _dynamic_ui: &Rc<SystemTray>) {
65        self.background_notice = Default::default();
66    }
67}
68impl TrayPlugin for VirtualDesktopEventManager {}
69impl VirtualDesktopEventManager {
70    fn on_background_event(&self) {
71        // Note: this has a shared reference to self and a rebuild can only
72        // happen after a mutable reference so "self.background" can never be
73        // mutably borrowed during "tray.on_desktop_event(..)".
74        let background = self.background.borrow();
75        let Some((_, receiver)) = background.as_ref() else {
76            return;
77        };
78        while let Ok(event) = receiver.try_recv() {
79            if let Some(tray) = self.tray.get() {
80                tray.notify_desktop_event(event.into());
81            }
82        }
83    }
84}