Skip to main content

pacenotes_installer\worker/
channel.rs

1/// Runs `work` on a new thread and posts its result to `window`, tagged with
2/// `request` so a scene can drop an answer it has moved past.
3pub fn spawn<F>(window: windows_sys::Win32::Foundation::HWND, request: usize, work: F)
4where
5    F: FnOnce() -> super::Message + Send + 'static,
6{
7    spawn_reporting(window, request, move |_| work());
8}
9
10/// Like `spawn`, for a job that posts progress through the `Reporter` it is
11/// handed instead of a window handle it could misuse.
12pub fn spawn_reporting<F>(window: windows_sys::Win32::Foundation::HWND, request: usize, work: F)
13where
14    F: FnOnce(&Reporter) -> super::Message + Send + 'static,
15{
16    // A window handle is not `Send`, but `PostMessageW` may be called from any thread.
17    let target = window as isize;
18    std::thread::spawn(move || {
19        let reporter = Reporter { target, request };
20        let message = work(&reporter);
21        post(target, super::WM_WORKER_DONE, request, message);
22    });
23}
24
25/// A job's one-way channel to the UI thread.
26pub struct Reporter {
27    target: isize,
28    request: usize,
29}
30
31impl Reporter {
32    /// A line for the log pane and nothing else.
33    pub fn log(&self, line: String) {
34        self.send(super::Progress {
35            phase: super::Phase::Install,
36            item: String::new(),
37            item_done: 0,
38            item_size: 0,
39            done: 0,
40            total: 0,
41            log: Some(line),
42        });
43    }
44
45    pub fn send(&self, progress: super::Progress) {
46        post(
47            self.target,
48            super::WM_WORKER_PROGRESS,
49            self.request,
50            progress,
51        );
52    }
53}
54
55fn post<T>(target: isize, message_id: u32, request: usize, payload: T) {
56    let boxed = Box::new(payload);
57    unsafe {
58        windows_sys::Win32::UI::WindowsAndMessaging::PostMessageW(
59            target as windows_sys::Win32::Foundation::HWND,
60            message_id,
61            request,
62            Box::into_raw(boxed) as windows_sys::Win32::Foundation::LPARAM,
63        );
64    }
65}
66
67/// Reclaims the `Message` a `WM_WORKER_DONE` carries.
68///
69/// # Safety
70/// Call exactly once per received `WM_WORKER_DONE`, with its `LPARAM`.
71pub unsafe fn take(lparam: windows_sys::Win32::Foundation::LPARAM) -> Option<super::Message> {
72    if lparam == 0 {
73        return None;
74    }
75    Some(*Box::from_raw(lparam as *mut super::Message))
76}
77
78/// Reclaims the `Progress` a `WM_WORKER_PROGRESS` carries.
79///
80/// # Safety
81/// Call exactly once per received `WM_WORKER_PROGRESS`, with its `LPARAM`.
82pub unsafe fn take_progress(
83    lparam: windows_sys::Win32::Foundation::LPARAM,
84) -> Option<Box<super::Progress>> {
85    if lparam == 0 {
86        return None;
87    }
88    Some(Box::from_raw(lparam as *mut super::Progress))
89}