1use error_code::ErrorCode;
4use windows_win::{
5 raw,
6 Window,
7 Messages
8};
9
10use windows_win::sys::{
11 HWND,
12 AddClipboardFormatListener,
13 RemoveClipboardFormatListener,
14 PostMessageW,
15 WM_CLIPBOARDUPDATE,
16};
17
18const CLOSE_PARAM: isize = -1;
19
20pub struct Shutdown {
26 window: HWND,
27}
28
29unsafe impl Send for Shutdown {}
30
31impl Drop for Shutdown {
32 #[inline(always)]
33 fn drop(&mut self) {
34 unsafe {
35 PostMessageW(self.window, WM_CLIPBOARDUPDATE, 0, CLOSE_PARAM)
36 };
37 }
38}
39
40struct ClipboardListener(HWND);
44
45impl ClipboardListener {
46 #[inline]
47 pub fn new(window: &Window) -> Result<Self, ErrorCode> {
49 let window = window.inner();
50 unsafe {
51 if AddClipboardFormatListener(window) != 1 {
52 Err(ErrorCode::last_system())
53 } else {
54 Ok(ClipboardListener(window))
55 }
56 }
57 }
58}
59
60impl Drop for ClipboardListener {
61 #[inline]
62 fn drop(&mut self) {
63 unsafe {
64 RemoveClipboardFormatListener(self.0);
65 }
66 }
67}
68
69pub struct Monitor {
89 _listener: ClipboardListener,
90 window: Window,
91}
92
93impl Monitor {
94 #[inline(always)]
95 pub fn new() -> Result<Self, ErrorCode> {
97 let window = Window::from_builder(raw::window::Builder::new().class_name("STATIC").parent_message())?;
98 let _listener = ClipboardListener::new(&window)?;
99
100 Ok(Self {
101 _listener,
102 window
103 })
104 }
105
106 #[inline(always)]
107 fn iter(&self) -> Messages {
108 let mut msg = Messages::new();
109 msg.window(Some(self.window.inner()))
110 .low(Some(WM_CLIPBOARDUPDATE))
111 .high(Some(WM_CLIPBOARDUPDATE));
112 msg
113 }
114
115 #[inline(always)]
116 pub fn shutdown_channel(&self) -> Shutdown {
118 Shutdown {
119 window: self.window.inner()
120 }
121 }
122
123 pub fn recv(&mut self) -> Result<bool, ErrorCode> {
129 for msg in self.iter() {
130 let msg = msg?;
131 match msg.id() {
132 WM_CLIPBOARDUPDATE => return Ok(msg.inner().lParam != CLOSE_PARAM),
133 _ => unreachable!(),
134 }
135 }
136
137 unreachable!();
138 }
139
140 pub fn try_recv(&mut self) -> Result<bool, ErrorCode> {
147 let mut iter = self.iter();
148 iter.non_blocking();
149 while let Some(msg) = iter.next() {
150 let msg = msg?;
151 match msg.id() {
152 WM_CLIPBOARDUPDATE => {
153 if msg.inner().lParam == CLOSE_PARAM {
155 continue;
156 }
157
158 return Ok(true);
159 }
160 _ => unreachable!(),
161 }
162 }
163
164 Ok(false)
165 }
166}
167
168impl Iterator for Monitor {
169 type Item = Result<bool, ErrorCode>;
170
171 #[inline(always)]
172 fn next(&mut self) -> Option<Self::Item> {
173 Some(self.recv())
174 }
175}