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