• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use anyhow::Context;
6 use anyhow::Result;
7 use base::error;
8 use base::warn;
9 #[cfg(feature = "kiwi")]
10 use vm_control::ServiceSendToGpu;
11 use winapi::shared::minwindef::LPARAM;
12 use winapi::shared::minwindef::LRESULT;
13 use winapi::shared::minwindef::TRUE;
14 use winapi::shared::minwindef::UINT;
15 use winapi::shared::minwindef::WPARAM;
16 use winapi::um::winuser::*;
17 
18 use super::window::MessagePacket;
19 use super::window::Window;
20 use super::window_message_dispatcher::DisplayEventDispatcher;
21 use super::ObjectId;
22 use crate::EventDevice;
23 
24 /// Thread message for killing the window during a `WndProcThread` drop. This indicates an error
25 /// within crosvm that internally causes the WndProc thread to be dropped, rather than when the
26 /// user/service initiates the window to be killed.
27 /// TODO(b/238678893): During such an abnormal event, window messages might not be reliable anymore.
28 /// Relying on destructors might be a safer choice.
29 pub(crate) const WM_USER_WNDPROC_THREAD_DROP_KILL_WINDOW_INTERNAL: UINT = WM_USER;
30 
31 // Thread message for handling the message sent from service. When the main event loop receives a
32 // message from service, it converts that to `ServiceSendToGpu` enum and sends it through a tube.
33 // The message relay thread receives it and sends the pointer to `ServiceSendToGpu` as the lParam.
34 #[cfg(feature = "kiwi")]
35 pub(crate) const WM_USER_HANDLE_SERVICE_MESSAGE_INTERNAL: UINT = WM_USER + 1;
36 
37 // Message for handling the change in host viewport. This is sent when the host window size changes
38 // and we need to render to a different part of the window. The new width and height are sent as the
39 // low/high word of lParam.
40 pub(crate) const WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL: UINT = WM_USER + 2;
41 
42 /// Thread message for handling the message sent from the GPU worker thread. A pointer to enum
43 /// `DisplaySendToWndProc` is sent as the lParam. Note that the receiver is responsible for
44 /// destructing the message.
45 pub(crate) const WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL: UINT = WM_USER + 3;
46 
47 pub type CreateMessageHandlerFunction<T> =
48     Box<dyn FnOnce(&Window, DisplayEventDispatcher) -> Result<T>>;
49 
50 /// Called after the handler creation finishes. The argument indicates whether that was successful.
51 pub type CreateMessageHandlerCallback = Box<dyn FnOnce(bool)>;
52 
53 /// Messages sent from the GPU worker thread to the WndProc thread.
54 pub enum DisplaySendToWndProc<T: HandleWindowMessage> {
55     CreateSurface {
56         function: CreateMessageHandlerFunction<T>,
57         callback: CreateMessageHandlerCallback,
58     },
59     ImportEventDevice {
60         event_device_id: ObjectId,
61         event_device: EventDevice,
62     },
63 }
64 
65 /// A trait for processing messages retrieved from the window message queue. All messages routed to
66 /// a trait object would target the same window.
67 pub trait HandleWindowMessage {
68     /// Called once when it is safe to assume all future messages targeting this window will be
69     /// dispatched to this handler.
on_message_dispatcher_attached(&mut self, _window: &Window)70     fn on_message_dispatcher_attached(&mut self, _window: &Window) {}
71 
72     /// Called when processing `WM_ACTIVATE`.
on_activate(&mut self, _window: &Window, _w_param: WPARAM)73     fn on_activate(&mut self, _window: &Window, _w_param: WPARAM) {}
74 
75     /// Called when processing `WM_MOUSEACTIVATE`. See possible return values:
76     /// https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mouseactivate#return-value
on_mouse_activate(&self, _l_param: LPARAM) -> i3277     fn on_mouse_activate(&self, _l_param: LPARAM) -> i32 {
78         MA_NOACTIVATE as i32
79     }
80 
81     /// Called when processing `WM_SETFOCUS`.
on_set_focus(&mut self)82     fn on_set_focus(&mut self) {}
83 
84     /// Called when processing `WM_INPUT`.
on_raw_input(&mut self, _window: &Window, _l_param: LPARAM)85     fn on_raw_input(&mut self, _window: &Window, _l_param: LPARAM) {}
86 
87     /// Called when processing `WM_MOUSEMOVE`.
on_mouse_move(&mut self, _w_param: WPARAM, _l_param: LPARAM)88     fn on_mouse_move(&mut self, _w_param: WPARAM, _l_param: LPARAM) {}
89 
90     /// Called when processing `WM_LBUTTONDOWN` and `WM_LBUTTONUP`.
on_mouse_button_left(&mut self, _window: &Window, _is_down: bool, _l_param: LPARAM)91     fn on_mouse_button_left(&mut self, _window: &Window, _is_down: bool, _l_param: LPARAM) {}
92 
93     /// Called when processing `WM_RBUTTONDOWN` and `WM_RBUTTONUP`.
on_mouse_button_right(&mut self, _is_down: bool)94     fn on_mouse_button_right(&mut self, _is_down: bool) {}
95 
96     /// Called when processing `WM_MOUSEWHEEL`.
on_mouse_wheel(&mut self, _w_param: WPARAM)97     fn on_mouse_wheel(&mut self, _w_param: WPARAM) {}
98 
99     /// Called when processing `WM_SETCURSOR`. It should return true if the cursor has been handled
100     /// and the default processing should be skipped.
on_set_cursor(&mut self, _window: &Window) -> bool101     fn on_set_cursor(&mut self, _window: &Window) -> bool {
102         false
103     }
104 
105     /// Called when processing `WM_KEYDOWN`, `WM_KEYUP`, `WM_SYSKEYDOWN` and `WM_SYSKEYUP`.
on_key(&mut self, _window: &Window, _key_down: bool, _w_param: WPARAM, _l_param: LPARAM)106     fn on_key(&mut self, _window: &Window, _key_down: bool, _w_param: WPARAM, _l_param: LPARAM) {}
107 
108     /// Called when processing `WM_WINDOWPOSCHANGING`.
on_window_pos_changing(&mut self, _window: &Window, _l_param: LPARAM)109     fn on_window_pos_changing(&mut self, _window: &Window, _l_param: LPARAM) {}
110 
111     /// Called when processing `WM_SIZING`.
on_window_size_changing(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM)112     fn on_window_size_changing(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM) {}
113 
114     /// Called when processing `WM_WINDOWPOSCHANGED`. It should return true if it is intended to
115     /// skip default processing, in which case `WM_SIZE` and `WM_MOVE` won't be sent to the window.
on_window_pos_changed(&mut self, _window: &Window, _l_param: LPARAM) -> bool116     fn on_window_pos_changed(&mut self, _window: &Window, _l_param: LPARAM) -> bool {
117         false
118     }
119 
120     /// Called when processing `WM_SIZE`.
on_window_size_changed(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM)121     fn on_window_size_changed(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM) {}
122 
123     /// Called when processing `WM_ENTERSIZEMOVE`.
on_enter_size_move(&mut self)124     fn on_enter_size_move(&mut self) {}
125 
126     /// Called when processing `WM_EXITSIZEMOVE`.
on_exit_size_move(&mut self, _window: &Window)127     fn on_exit_size_move(&mut self, _window: &Window) {}
128 
129     /// Called when processing `WM_DISPLAYCHANGE`.
on_display_change(&mut self, _window: &Window)130     fn on_display_change(&mut self, _window: &Window) {}
131 
132     /// Called when processing `WM_USER_HANDLE_SERVICE_MESSAGE_INTERNAL`.
133     #[cfg(feature = "kiwi")]
on_handle_service_message(&mut self, _window: &Window, _message: &ServiceSendToGpu)134     fn on_handle_service_message(&mut self, _window: &Window, _message: &ServiceSendToGpu) {}
135 
136     /// Called when processing `WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL`.
on_host_viewport_change(&mut self, _window: &Window, _l_param: LPARAM)137     fn on_host_viewport_change(&mut self, _window: &Window, _l_param: LPARAM) {}
138 
139     /// Called when processing `WM_CLOSE`. It should return true if the window should be destroyed
140     /// immediately.
on_close(&mut self) -> bool141     fn on_close(&mut self) -> bool {
142         true
143     }
144 
145     /// Called when processing `WM_DESTROY`.
on_destroy(&mut self)146     fn on_destroy(&mut self) {}
147 }
148 
149 /// This class drives the underlying `HandleWindowMessage` trait object to process window messages
150 /// retrieved from the message pump. Note that we rely on the owner of `WindowMessageProcessor`
151 /// object to drop it before the underlying window is completely gone.
152 pub(crate) struct WindowMessageProcessor<T: HandleWindowMessage> {
153     window: Window,
154     message_handler: Option<T>,
155 }
156 
157 impl<T: HandleWindowMessage> WindowMessageProcessor<T> {
158     /// # Safety
159     /// The owner of `WindowMessageProcessor` object is responsible for dropping it before we finish
160     /// processing `WM_NCDESTROY`, because the window handle will become invalid afterwards.
new(window: Window) -> Self161     pub unsafe fn new(window: Window) -> Self {
162         Self {
163             window,
164             message_handler: None,
165         }
166     }
167 
create_message_handler( &mut self, create_handler_func: CreateMessageHandlerFunction<T>, display_event_dispatcher: DisplayEventDispatcher, ) -> Result<()>168     pub fn create_message_handler(
169         &mut self,
170         create_handler_func: CreateMessageHandlerFunction<T>,
171         display_event_dispatcher: DisplayEventDispatcher,
172     ) -> Result<()> {
173         create_handler_func(&self.window, display_event_dispatcher)
174             .map(|handler| {
175                 self.message_handler.replace(handler);
176                 if let Some(handler) = &mut self.message_handler {
177                     handler.on_message_dispatcher_attached(&self.window);
178                 }
179             })
180             .context("When creating window message handler")
181     }
182 
183     #[cfg(feature = "kiwi")]
handle_service_message(&mut self, message: &ServiceSendToGpu)184     pub fn handle_service_message(&mut self, message: &ServiceSendToGpu) {
185         match &mut self.message_handler {
186             Some(handler) => handler.on_handle_service_message(&self.window, message),
187             None => error!(
188                 "Cannot handle {:?} because window message handler has not been created!",
189                 message
190             ),
191         }
192     }
193 
process_message(&mut self, packet: &MessagePacket) -> LRESULT194     pub fn process_message(&mut self, packet: &MessagePacket) -> LRESULT {
195         let MessagePacket {
196             msg,
197             w_param,
198             l_param,
199         } = *packet;
200 
201         // The handler may read window states so we should update them first.
202         self.window.update_states(msg, w_param);
203 
204         let handler = match &mut self.message_handler {
205             Some(handler) => handler,
206             None => {
207                 warn!(
208                     "Skipping processing {:?} because message handler has not been created!",
209                     packet
210                 );
211                 return self.window.default_process_message(packet);
212             }
213         };
214         match msg {
215             WM_ACTIVATE => {
216                 handler.on_activate(&self.window, w_param);
217                 0
218             }
219             WM_MOUSEACTIVATE => handler.on_mouse_activate(l_param) as LRESULT,
220             WM_SETFOCUS => {
221                 handler.on_set_focus();
222                 0
223             }
224             WM_INPUT => {
225                 handler.on_raw_input(&self.window, l_param);
226                 self.window.default_process_message(packet)
227             }
228             WM_MOUSEMOVE => {
229                 handler.on_mouse_move(w_param, l_param);
230                 0
231             }
232             WM_LBUTTONDOWN | WM_LBUTTONUP => {
233                 let is_down = msg == WM_LBUTTONDOWN;
234                 handler.on_mouse_button_left(&self.window, is_down, l_param);
235                 0
236             }
237             WM_RBUTTONDOWN | WM_RBUTTONUP => {
238                 handler.on_mouse_button_right(/* is_down= */ msg == WM_RBUTTONDOWN);
239                 0
240             }
241             WM_MOUSEWHEEL => {
242                 handler.on_mouse_wheel(w_param);
243                 0
244             }
245             WM_SETCURSOR => {
246                 if handler.on_set_cursor(&self.window) {
247                     return 0;
248                 }
249                 self.window.default_process_message(packet)
250             }
251             WM_KEYDOWN | WM_KEYUP | WM_SYSKEYDOWN | WM_SYSKEYUP => {
252                 let key_down = msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN;
253                 handler.on_key(&self.window, key_down, w_param, l_param);
254                 0
255             }
256             WM_WINDOWPOSCHANGING => {
257                 handler.on_window_pos_changing(&self.window, l_param);
258                 0
259             }
260             WM_SIZING => {
261                 handler.on_window_size_changing(&self.window, w_param, l_param);
262                 TRUE as LRESULT
263             }
264             WM_WINDOWPOSCHANGED => {
265                 if handler.on_window_pos_changed(&self.window, l_param) {
266                     return 0;
267                 }
268                 self.window.default_process_message(packet)
269             }
270             WM_SIZE => {
271                 handler.on_window_size_changed(&self.window, w_param, l_param);
272                 0
273             }
274             WM_ENTERSIZEMOVE => {
275                 handler.on_enter_size_move();
276                 0
277             }
278             WM_EXITSIZEMOVE => {
279                 handler.on_exit_size_move(&self.window);
280                 0
281             }
282             WM_DISPLAYCHANGE => {
283                 handler.on_display_change(&self.window);
284                 0
285             }
286             WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL => {
287                 handler.on_host_viewport_change(&self.window, l_param);
288                 0
289             }
290             WM_CLOSE => {
291                 if handler.on_close() {
292                     if let Err(e) = self.window.destroy() {
293                         error!("Failed to destroy window on WM_CLOSE: {:?}", e);
294                     }
295                 }
296                 0
297             }
298             WM_DESTROY => {
299                 handler.on_destroy();
300                 0
301             }
302             _ => self.window.default_process_message(packet),
303         }
304     }
305 
window(&self) -> &Window306     pub fn window(&self) -> &Window {
307         &self.window
308     }
309 }
310