Skip to main content

everything_ipc/wm/
shared.rs

1use std::sync::{Arc, Mutex, Weak};
2
3use crate::wm::{EverythingClient, IpcError};
4
5static SHARED: Mutex<Weak<EverythingClient>> = Mutex::new(Weak::new());
6
7impl EverythingClient {
8    /// Get a globally-shared, lazily-created [`EverythingClient`].
9    ///
10    /// The first call creates and returns an [`Arc`]-wrapped client. Subsequent
11    /// calls return a clone of the same [`Arc`]. When all returned [`Arc`]s are
12    /// dropped, the underlying client (and its reply window thread) is dropped.
13    /// A new client is automatically created on the next call.
14    ///
15    /// ## Note
16    /// [`EverythingClient::query()`] will cancel the previous query.
17    /// Use with caution.
18    pub fn shared() -> Result<Arc<Self>, IpcError> {
19        let mut guard = SHARED.lock().unwrap();
20        if let Some(client) = guard.upgrade() {
21            return Ok(client);
22        }
23        let client = Arc::new(Self::new()?);
24        *guard = Arc::downgrade(&client);
25        Ok(client)
26    }
27
28    /// Quit and join the message thread of the last [`shared`](Self::shared) client instance.
29    ///
30    /// This function is meant to manually make sure the thread is exited before DLL unloading.
31    /// While `drop-join-thread` feature also works for `static`s,
32    /// it will break `thread_local`s.
33    ///
34    /// ## Safety
35    /// This function is `!Sync`. It's unlikely that you need `Sync` though.
36    pub unsafe fn shared_quit_join_thread() {
37        let mut guard = SHARED.lock().unwrap();
38        if let Some(client) = guard.upgrade() {
39            *guard = Default::default();
40            drop(guard);
41
42            // TODO: Arc::get_mut_unchecked()
43            let client = unsafe { &mut *Arc::as_ptr(&client).cast_mut() };
44            client.reply_window.quit_join_thread();
45        }
46    }
47}