Skip to main content

native_windows_gui2/controls/
notice.rs

1use super::control_handle::ControlHandle;
2use crate::NwgError;
3use crate::win32::{window::build_notice, window_helper as wh};
4
5const NOT_BOUND: &'static str = "Notice is not yet bound to a winapi object";
6const UNUSABLE_NOTICE: &'static str = "Notice parent window was freed";
7const BAD_HANDLE: &'static str = "INTERNAL ERROR: Notice handle is not Notice!";
8
9/**
10An invisible component that can be triggered by other thread.
11
12A notice object does not send data between threads. Rust has already plenty of way to do this.
13The notice object only serve to "wake up" the GUI thread.
14
15A notice must have a parent window. If the parent is destroyed before the notice, the notice becomes invalid.
16
17Requires the `notice` feature.
18
19## Example
20
21```rust
22use native_windows_gui2 as nwg;
23fn build_notice(notice: &mut nwg::Notice, window: &nwg::Window) {
24    nwg::Notice::builder()
25        .parent(window)
26        .build(notice);
27}
28```
29
30```rust
31use native_windows_gui2 as nwg;
32use std::thread;
33use std::time;
34
35fn notice(noticer: &nwg::Notice) {
36    let sender = noticer.sender();
37
38    thread::spawn(move || {
39        thread::sleep(time::Duration::new(5, 0));
40        sender.notice();
41    });
42}
43
44```
45
46*/
47#[derive(Default, PartialEq, Eq)]
48pub struct Notice {
49    pub handle: ControlHandle,
50}
51
52impl Notice {
53    pub fn builder() -> NoticeBuilder {
54        NoticeBuilder { parent: None }
55    }
56
57    /// A shortcut over the builder API for the notice object
58    pub fn create<C: Into<ControlHandle>>(parent: C) -> Result<Notice, NwgError> {
59        let mut notice = Self::default();
60        Self::builder().parent(parent).build(&mut notice)?;
61
62        Ok(notice)
63    }
64
65    /// Checks if the notice is still usable. A notice becomes unusable when the parent window is destroyed.
66    /// This will also return false if the notice is not initialized.
67    pub fn valid(&self) -> bool {
68        if self.handle.blank() {
69            return false;
70        }
71        let (hwnd, _) = self.handle.notice().expect(BAD_HANDLE);
72        wh::window_valid(hwnd)
73    }
74
75    /// Return an handle to the notice window or `None` if the window was destroyed.
76    pub fn window_handle(&self) -> Option<ControlHandle> {
77        match self.valid() {
78            true => Some(ControlHandle::Hwnd(self.handle.notice().unwrap().0)),
79            false => None,
80        }
81    }
82
83    /// Change the parent window of the notice. This won't update the NoticeSender already created.
84    /// Panics if the control is not a window-like control or if the notice was not initialized
85    pub fn set_window_handle<C: Into<ControlHandle>>(&mut self, window: C) {
86        if self.handle.blank() {
87            panic!("{}", NOT_BOUND);
88        }
89
90        let hwnd = window
91            .into()
92            .hwnd()
93            .expect("New notice parent is not a window control");
94        let (_, id) = self.handle.notice().expect(BAD_HANDLE);
95
96        self.handle = ControlHandle::Notice(hwnd, id);
97    }
98
99    /// Create a new `NoticeSender` bound to this Notice
100    pub fn sender(&self) -> NoticeSender {
101        if self.handle.blank() {
102            panic!("{}", NOT_BOUND);
103        }
104        if !self.valid() {
105            panic!("{}", UNUSABLE_NOTICE);
106        }
107        let (hwnd, id) = self.handle.notice().expect(BAD_HANDLE);
108
109        NoticeSender {
110            hwnd: hwnd as usize,
111            id,
112        }
113    }
114}
115
116impl Drop for Notice {
117    fn drop(&mut self) {
118        self.handle.destroy();
119    }
120}
121
122/// NoticeSender sends message to its parent `Notice` from another thread
123#[derive(Clone, Copy)]
124pub struct NoticeSender {
125    hwnd: usize,
126    id: u32,
127}
128
129impl NoticeSender {
130    /// Send a message to the thread of the parent `Notice`
131    pub fn notice(&self) {
132        use winapi::shared::minwindef::{LPARAM, WPARAM};
133        use winapi::shared::windef::HWND;
134        use winapi::um::winuser::SendNotifyMessageW;
135
136        unsafe {
137            SendNotifyMessageW(
138                self.hwnd as HWND,
139                wh::NOTICE_MESSAGE,
140                self.id as WPARAM,
141                self.hwnd as LPARAM,
142            );
143        }
144    }
145}
146
147pub struct NoticeBuilder {
148    parent: Option<ControlHandle>,
149}
150
151impl NoticeBuilder {
152    pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> NoticeBuilder {
153        self.parent = Some(p.into());
154        self
155    }
156
157    pub fn build(self, out: &mut Notice) -> Result<(), NwgError> {
158        let parent = match self.parent {
159            Some(p) => match p.hwnd() {
160                Some(handle) => Ok(handle),
161                None => Err(NwgError::control_create("Wrong parent type")),
162            },
163            None => Err(NwgError::no_parent("Notice")),
164        }?;
165
166        out.handle = build_notice(parent);
167
168        Ok(())
169    }
170}