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 std::cell::RefCell; 6 use std::collections::HashMap; 7 use std::io::ErrorKind; 8 use std::marker::PhantomPinned; 9 use std::os::raw::c_void; 10 use std::pin::Pin; 11 use std::rc::Rc; 12 13 use anyhow::bail; 14 use anyhow::Context; 15 use anyhow::Result; 16 use base::error; 17 use base::info; 18 use base::Event; 19 use base::Tube; 20 use cros_tracing::trace_event; 21 use linux_input_sys::virtio_input_event; 22 #[cfg(feature = "kiwi")] 23 use vm_control::ServiceSendToGpu; 24 use win_util::win32_wide_string; 25 use winapi::shared::minwindef::LRESULT; 26 use winapi::shared::windef::HWND; 27 use winapi::um::winuser::DefWindowProcW; 28 use winapi::um::winuser::GetForegroundWindow; 29 use winapi::um::winuser::PostQuitMessage; 30 use winapi::um::winuser::RemovePropW; 31 use winapi::um::winuser::HRAWINPUT; 32 use winapi::um::winuser::WM_CLOSE; 33 use winapi::um::winuser::WM_INPUT; 34 use winapi::um::winuser::WM_NCDESTROY; 35 36 use super::keyboard_input_manager::KeyboardInputManager; 37 use super::window::BasicWindow; 38 use super::window::GuiWindow; 39 use super::window::MessageOnlyWindow; 40 use super::window::MessagePacket; 41 use super::window_message_processor::*; 42 use super::MouseMode; 43 use super::ObjectId; 44 use crate::EventDevice; 45 use crate::EventDeviceKind; 46 47 /// The pointer to dispatcher will be stored with HWND using `SetPropW()` with the following name. 48 pub(crate) const DISPATCHER_PROPERTY_NAME: &str = "PROP_WND_MSG_DISPATCHER"; 49 50 /// Tracks the ids of all event devices in one kind. For each kind, we either have one event device 51 /// shared by all scanouts (guest displays), or one per scanout. 52 enum EventDeviceIds { 53 GlobalDevice(ObjectId), 54 PerScanoutDevices(Vec<ObjectId>), 55 } 56 57 /// This class is used to dispatch input events from the display to the guest input device. It is 58 /// also used to receive events from the input device (e.g. guest) on behalf of the window so they 59 /// can be routed back to the window for processing. 60 #[derive(Clone)] 61 pub struct DisplayEventDispatcher { 62 event_devices: Rc<RefCell<HashMap<ObjectId, EventDevice>>>, 63 event_device_ids: Rc<RefCell<HashMap<EventDeviceKind, EventDeviceIds>>>, 64 } 65 66 impl DisplayEventDispatcher { new() -> Self67 pub fn new() -> Self { 68 Self { 69 event_devices: Default::default(), 70 event_device_ids: Default::default(), 71 } 72 } 73 dispatch( &self, window: &GuiWindow, events: &[virtio_input_event], device_kind: EventDeviceKind, )74 pub fn dispatch( 75 &self, 76 window: &GuiWindow, 77 events: &[virtio_input_event], 78 device_kind: EventDeviceKind, 79 ) { 80 if let Some(event_device_id) = self.find_event_device_id(device_kind, window.scanout_id()) { 81 if let Some(event_device) = self.event_devices.borrow_mut().get_mut(&event_device_id) { 82 if let Err(e) = event_device.send_report(events.iter().cloned()) { 83 error!("Failed to send events to event device: {}", e); 84 } 85 } 86 } 87 } 88 read_from_device( &self, event_device_id: ObjectId, ) -> Option<(EventDeviceKind, virtio_input_event)>89 pub fn read_from_device( 90 &self, 91 event_device_id: ObjectId, 92 ) -> Option<(EventDeviceKind, virtio_input_event)> { 93 if let Some(device) = self.event_devices.borrow_mut().get(&event_device_id) { 94 match device.recv_event_encoded() { 95 Ok(event) => return Some((device.kind(), event)), 96 Err(e) if e.kind() == ErrorKind::WouldBlock => return None, 97 Err(e) => error!( 98 "failed to read from event device {:?} (index: {}): {:?}", 99 device.kind(), 100 event_device_id, 101 e 102 ), 103 } 104 } else { 105 error!( 106 "notified to read from event device {:?} but do not have a device with that ID", 107 event_device_id 108 ); 109 } 110 None 111 } 112 import_event_device(&mut self, event_device_id: ObjectId, event_device: EventDevice)113 fn import_event_device(&mut self, event_device_id: ObjectId, event_device: EventDevice) { 114 info!("Importing {:?} (ID: {:?})", event_device, event_device_id); 115 let device_kind = event_device.kind(); 116 let same_kind_device_ids = match device_kind { 117 EventDeviceKind::Touchscreen => { 118 // Temporarily removing from `self.event_device_ids`. Will be reinserted after 119 // adding `event_device_id`. 120 let mut per_scanout_device_ids = self 121 .event_device_ids 122 .borrow_mut() 123 .remove(&device_kind) 124 .and_then(|imported_device_ids| match imported_device_ids { 125 EventDeviceIds::PerScanoutDevices(ids) => Some(ids), 126 _ => unreachable!(), 127 }) 128 .unwrap_or_default(); 129 per_scanout_device_ids.push(event_device_id); 130 EventDeviceIds::PerScanoutDevices(per_scanout_device_ids) 131 } 132 _ => EventDeviceIds::GlobalDevice(event_device_id), 133 }; 134 self.event_device_ids 135 .borrow_mut() 136 .insert(device_kind, same_kind_device_ids); 137 self.event_devices 138 .borrow_mut() 139 .insert(event_device_id, event_device); 140 } 141 find_event_device_id( &self, device_kind: EventDeviceKind, scanout_id: u32, ) -> Option<ObjectId>142 fn find_event_device_id( 143 &self, 144 device_kind: EventDeviceKind, 145 scanout_id: u32, 146 ) -> Option<ObjectId> { 147 self.event_device_ids 148 .borrow() 149 .get(&device_kind) 150 .and_then(|same_kind_device_ids| match same_kind_device_ids { 151 EventDeviceIds::GlobalDevice(event_device_id) => Some(*event_device_id), 152 EventDeviceIds::PerScanoutDevices(event_device_ids) => { 153 event_device_ids.get(scanout_id as usize).cloned() 154 } 155 }) 156 } 157 } 158 159 impl Default for DisplayEventDispatcher { default() -> Self160 fn default() -> Self { 161 Self::new() 162 } 163 } 164 165 /// This struct is used for dispatching window messages. Note that messages targeting the WndProc 166 /// thread itself shouldn't be posted using `PostThreadMessageW()`, but posted as window messages to 167 /// `message_router_window`, so that they won't get lost when the modal loop is running. 168 /// 169 /// This struct should be created before the WndProc thread enters the message loop. Once all 170 /// windows tracked by it are destroyed, it will signal exiting the message loop, and then it can be 171 /// dropped. 172 pub(crate) struct WindowMessageDispatcher { 173 message_router_window: Option<MessageOnlyWindow>, 174 vacant_gui_windows: HashMap<HWND, WindowResources>, 175 in_use_gui_windows: HashMap<HWND, WindowMessageProcessor>, 176 // We have a one-to-one mapping between virtio-gpu scanouts and GUI window surfaces. The index 177 // of the GUI window in this Vec will be the same as the associated scanout's id. 178 // These handles are only used for hashmap queries. Do not directly call Windows APIs on them. 179 gui_window_handles: Vec<HWND>, 180 keyboard_input_manager: KeyboardInputManager, 181 display_event_dispatcher: DisplayEventDispatcher, 182 gpu_main_display_tube: Option<Rc<Tube>>, 183 close_requested_event: Event, 184 // The dispatcher is pinned so that its address in the memory won't change, and it is always 185 // safe to use the pointer to it stored in the window. 186 _pinned_marker: PhantomPinned, 187 } 188 189 impl WindowMessageDispatcher { 190 /// This function should only be called once from the WndProc thread. It will take the ownership 191 /// of the `GuiWindow` objects, and drop them before the underlying windows are completely gone. 192 /// TODO(b/238680252): This should be good enough for supporting multi-windowing, but we should 193 /// revisit it if we also want to manage some child windows of the crosvm window. new( message_router_window: MessageOnlyWindow, gui_windows: Vec<GuiWindow>, gpu_main_display_tube: Option<Rc<Tube>>, close_requested_event: Event, ) -> Result<Pin<Box<Self>>>194 pub fn new( 195 message_router_window: MessageOnlyWindow, 196 gui_windows: Vec<GuiWindow>, 197 gpu_main_display_tube: Option<Rc<Tube>>, 198 close_requested_event: Event, 199 ) -> Result<Pin<Box<Self>>> { 200 static CONTEXT_MESSAGE: &str = "When creating WindowMessageDispatcher"; 201 let display_event_dispatcher = DisplayEventDispatcher::new(); 202 let gui_window_handles = gui_windows 203 .iter() 204 .map(|window| { 205 // SAFETY: 206 // Safe because we will only use these handles to query hashmaps. 207 unsafe { window.handle() } 208 }) 209 .collect(); 210 let mut dispatcher = Box::pin(Self { 211 message_router_window: Some(message_router_window), 212 vacant_gui_windows: Default::default(), // To be updated. 213 in_use_gui_windows: Default::default(), 214 gui_window_handles, 215 keyboard_input_manager: KeyboardInputManager::new(display_event_dispatcher.clone()), 216 display_event_dispatcher, 217 gpu_main_display_tube, 218 close_requested_event, 219 _pinned_marker: PhantomPinned, 220 }); 221 dispatcher 222 .as_mut() 223 .attach_thread_message_router() 224 .context(CONTEXT_MESSAGE)?; 225 dispatcher 226 .as_mut() 227 .create_window_resources(gui_windows) 228 .context(CONTEXT_MESSAGE)?; 229 Ok(dispatcher) 230 } 231 232 /// # Safety 233 /// The caller must not use the handle after the message loop terminates. message_router_handle(&self) -> Option<HWND>234 pub unsafe fn message_router_handle(&self) -> Option<HWND> { 235 self.message_router_window 236 .as_ref() 237 .map(|router| router.handle()) 238 } 239 240 #[cfg(feature = "kiwi")] process_service_message(self: Pin<&mut Self>, message: &ServiceSendToGpu)241 pub fn process_service_message(self: Pin<&mut Self>, message: &ServiceSendToGpu) { 242 if matches!(message, ServiceSendToGpu::Shutdown) { 243 info!("Processing ShutdownRequest from service"); 244 // Safe because we won't move the dispatcher out of the returned mutable reference. 245 unsafe { self.get_unchecked_mut().request_shutdown_gpu_display() }; 246 return; 247 } 248 249 // TODO(b/306024335): `ServiceSendToGpu` should specify the targeted display id. 250 // Safe because we won't move the dispatcher out of the returned mutable reference. 251 let primary_window_handle = self.primary_window_handle(); 252 match unsafe { 253 self.get_unchecked_mut() 254 .in_use_gui_windows 255 .get_mut(&primary_window_handle) 256 } { 257 Some(processor) => processor.handle_service_message(message), 258 None => error!("Cannot handle service message because primary window is not in-use!"), 259 } 260 } 261 262 /// Returns `Some` if the message is processed by the targeted window. dispatch_window_message( &mut self, hwnd: HWND, packet: &MessagePacket, ) -> Option<LRESULT>263 pub fn dispatch_window_message( 264 &mut self, 265 hwnd: HWND, 266 packet: &MessagePacket, 267 ) -> Option<LRESULT> { 268 // First, check if the message is targeting the wndproc thread itself. 269 if let Some(router) = &self.message_router_window { 270 if router.is_same_window(hwnd) { 271 return if packet.msg == WM_INPUT { 272 // The message router window is the sink for all WM_INPUT messages targeting 273 // this application. We would reroute WM_INPUT to the current foreground window. 274 // SAFETY: trivially safe 275 let foreground_hwnd = unsafe { GetForegroundWindow() }; 276 if let Some(processor) = self.in_use_gui_windows.get_mut(&foreground_hwnd) { 277 processor.process_general_message( 278 GeneralMessage::RawInputEvent(packet.l_param as HRAWINPUT), 279 &self.keyboard_input_manager, 280 ); 281 } 282 // Always do default processing "so the system can perform cleanup". 283 // https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-input#parameters 284 router.default_process_message(packet); 285 Some(0) 286 } else { 287 Some(self.process_simulated_thread_message(hwnd, packet)) 288 }; 289 } 290 } 291 292 // Second, check if this message indicates any lifetime events of GUI windows. 293 if let Some(ret) = self.handle_gui_window_lifetime_message(hwnd, packet) { 294 return Some(ret); 295 } 296 297 // Third, check if the message is targeting an in-use GUI window. 298 self.in_use_gui_windows 299 .get_mut(&hwnd) 300 .map(|processor| processor.process_window_message(packet, &self.keyboard_input_manager)) 301 } 302 303 // TODO(b/306407787): We won't need this once we have full support for multi-window. primary_window_handle(&self) -> HWND304 fn primary_window_handle(&self) -> HWND { 305 self.gui_window_handles[0] 306 } 307 attach_thread_message_router(self: Pin<&mut Self>) -> Result<()>308 fn attach_thread_message_router(self: Pin<&mut Self>) -> Result<()> { 309 let dispatcher_ptr = &*self as *const Self; 310 // SAFETY: 311 // Safe because we won't move the dispatcher out of it. 312 match unsafe { &self.get_unchecked_mut().message_router_window } { 313 // SAFETY: 314 // Safe because we guarantee the dispatcher outlives the thread message router. 315 Some(router) => unsafe { Self::store_pointer_in_window(dispatcher_ptr, router) }, 316 None => bail!("Thread message router not found, cannot associate with dispatcher!"), 317 } 318 } 319 create_window_resources(self: Pin<&mut Self>, windows: Vec<GuiWindow>) -> Result<()>320 fn create_window_resources(self: Pin<&mut Self>, windows: Vec<GuiWindow>) -> Result<()> { 321 // SAFETY: 322 // because we won't move the dispatcher out of it. 323 let pinned_dispatcher = unsafe { self.get_unchecked_mut() }; 324 for window in windows.into_iter() { 325 if !window.is_valid() { 326 // SAFETY: 327 // Safe because we are just logging the handle value. 328 bail!("Window {:p} is invalid!", unsafe { window.handle() }); 329 } 330 331 // SAFETY: 332 // because we guarantee the dispatcher outlives our GUI windows. 333 unsafe { Self::store_pointer_in_window(&*pinned_dispatcher, &window)? }; 334 335 pinned_dispatcher.vacant_gui_windows.insert( 336 // SAFETY: 337 // Safe because this handle is only used as the hashmap kay. 338 unsafe { window.handle() }, 339 // SAFETY: 340 // Safe the dispatcher will take care of the lifetime of the window. 341 unsafe { WindowResources::new(window) }, 342 ); 343 } 344 Ok(()) 345 } 346 347 /// Processes messages targeting the WndProc thread itself. Note that these messages are not 348 /// posted using `PostThreadMessageW()`, but posted to `message_router_window` as window 349 /// messages (hence "simulated"), so they won't get lost if the modal loop is running. process_simulated_thread_message( &mut self, message_router_hwnd: HWND, packet: &MessagePacket, ) -> LRESULT350 fn process_simulated_thread_message( 351 &mut self, 352 message_router_hwnd: HWND, 353 packet: &MessagePacket, 354 ) -> LRESULT { 355 let MessagePacket { 356 msg, 357 w_param, 358 l_param, 359 } = *packet; 360 match msg { 361 WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL => { 362 let _trace_event = 363 trace_event!(gpu_display, "WM_USER_HANDLE_DISPLAY_MESSAGE_INTERNAL"); 364 // SAFETY: 365 // Safe because the sender gives up the ownership and expects the receiver to 366 // destruct the message. 367 let message = unsafe { Box::from_raw(l_param as *mut DisplaySendToWndProc) }; 368 self.handle_display_message(*message); 369 } 370 WM_USER_SHUTDOWN_WNDPROC_THREAD_INTERNAL => { 371 let _trace_event = 372 trace_event!(gpu_display, "WM_USER_SHUTDOWN_WNDPROC_THREAD_INTERNAL"); 373 self.shutdown(); 374 } 375 _ => { 376 let _trace_event = 377 trace_event!(gpu_display, "WM_OTHER_MESSAGE_ROUTER_WINDOW_MESSAGE"); 378 // SAFETY: 379 // Safe because we are processing a message targeting the message router window. 380 return unsafe { DefWindowProcW(message_router_hwnd, msg, w_param, l_param) }; 381 } 382 } 383 0 384 } 385 handle_display_message(&mut self, message: DisplaySendToWndProc)386 fn handle_display_message(&mut self, message: DisplaySendToWndProc) { 387 match message { 388 DisplaySendToWndProc::CreateSurface { 389 scanout_id, 390 function, 391 callback, 392 } => { 393 callback(self.create_surface(scanout_id, function)); 394 } 395 DisplaySendToWndProc::ReleaseSurface { surface_id } => self.release_surface(surface_id), 396 DisplaySendToWndProc::ImportEventDevice { 397 event_device_id, 398 event_device, 399 } => { 400 self.display_event_dispatcher 401 .import_event_device(event_device_id, event_device); 402 } 403 DisplaySendToWndProc::HandleEventDevice(event_device_id) => { 404 self.handle_event_device(event_device_id) 405 } 406 DisplaySendToWndProc::SetMouseMode { 407 surface_id, 408 mouse_mode, 409 } => self.set_mouse_mode(surface_id, mouse_mode), 410 } 411 } 412 handle_event_device(&mut self, event_device_id: ObjectId)413 fn handle_event_device(&mut self, event_device_id: ObjectId) { 414 // TODO(b/306407787): Events should be routed to the correct window. 415 match self 416 .in_use_gui_windows 417 .get_mut(&self.primary_window_handle()) 418 { 419 Some(processor) => { 420 if let Some((event_device_kind, event)) = self 421 .display_event_dispatcher 422 .read_from_device(event_device_id) 423 { 424 processor.process_general_message( 425 GeneralMessage::GuestEvent { 426 event_device_kind, 427 event, 428 }, 429 &self.keyboard_input_manager, 430 ); 431 } 432 } 433 None => { 434 error!("Cannot handle event device because primary window is not in-use!") 435 } 436 } 437 } 438 set_mouse_mode(&mut self, surface_id: u32, mouse_mode: MouseMode)439 fn set_mouse_mode(&mut self, surface_id: u32, mouse_mode: MouseMode) { 440 match self 441 .in_use_gui_windows 442 .iter_mut() 443 .find(|(_, processor)| processor.surface_id() == surface_id) 444 { 445 Some(iter) => iter.1.process_general_message( 446 GeneralMessage::SetMouseMode(mouse_mode), 447 &self.keyboard_input_manager, 448 ), 449 None => error!( 450 "Can't set mouse mode for surface {} because it is not in-use!", 451 surface_id 452 ), 453 } 454 } 455 456 /// Returns true if the surface is created successfully. create_surface( &mut self, scanout_id: u32, create_surface_func: CreateSurfaceFunction, ) -> bool457 fn create_surface( 458 &mut self, 459 scanout_id: u32, 460 create_surface_func: CreateSurfaceFunction, 461 ) -> bool { 462 // virtio-gpu prefers to use the lowest available scanout id when creating a new surface, so 463 // here we implictly prefer the primary window (associated with scanout 0). 464 let hwnd = match self.gui_window_handles.get(scanout_id as usize) { 465 Some(hwnd) => *hwnd, 466 None => { 467 error!("Invalid scanout id {}!", scanout_id); 468 return false; 469 } 470 }; 471 let window_resources = match self.vacant_gui_windows.remove(&hwnd) { 472 Some(resources) => resources, 473 None => { 474 error!( 475 "GUI window associated with scanout {} is not vacant!", 476 scanout_id 477 ); 478 return false; 479 } 480 }; 481 let surface_resources = SurfaceResources { 482 display_event_dispatcher: self.display_event_dispatcher.clone(), 483 gpu_main_display_tube: self.gpu_main_display_tube.clone(), 484 }; 485 // SAFETY: 486 // Safe because the dispatcher will take care of the lifetime of the window. 487 match unsafe { 488 WindowMessageProcessor::new(create_surface_func, surface_resources, window_resources) 489 } { 490 Ok(processor) => { 491 self.in_use_gui_windows.insert(hwnd, processor); 492 self.in_use_gui_windows 493 .get_mut(&hwnd) 494 .expect("It is just inserted") 495 .process_general_message( 496 GeneralMessage::MessageDispatcherAttached, 497 &self.keyboard_input_manager, 498 ); 499 true 500 } 501 Err(e) => { 502 error!("Failed to create surface: {:?}", e); 503 false 504 } 505 } 506 } 507 release_surface(&mut self, surface_id: u32)508 fn release_surface(&mut self, surface_id: u32) { 509 match self 510 .in_use_gui_windows 511 .iter() 512 .find(|(_, processor)| processor.surface_id() == surface_id) 513 { 514 Some(iter) => { 515 self.try_release_surface_and_dissociate_gui_window(*iter.0); 516 } 517 None => error!( 518 "Can't release surface {} because there is no window associated with it!", 519 surface_id 520 ), 521 } 522 } 523 524 /// Returns true if `hwnd` points to an in-use GUI window. try_release_surface_and_dissociate_gui_window(&mut self, hwnd: HWND) -> bool525 fn try_release_surface_and_dissociate_gui_window(&mut self, hwnd: HWND) -> bool { 526 if let Some(processor) = self.in_use_gui_windows.remove(&hwnd) { 527 // SAFETY: 528 // Safe because the dispatcher will take care of the lifetime of the window. 529 self.vacant_gui_windows.insert(hwnd, unsafe { 530 processor.release_surface_and_take_window_resources() 531 }); 532 return true; 533 } 534 false 535 } 536 537 /// # Safety 538 /// The caller is responsible for keeping the pointer valid until it is removed from the window. store_pointer_in_window( pointer: *const Self, window: &dyn BasicWindow, ) -> Result<()>539 unsafe fn store_pointer_in_window( 540 pointer: *const Self, 541 window: &dyn BasicWindow, 542 ) -> Result<()> { 543 window 544 .set_property(DISPATCHER_PROPERTY_NAME, pointer as *mut c_void) 545 .context("When storing message dispatcher pointer") 546 } 547 548 /// Returns Some if this is a GUI window lifetime related message and if we have handled it. handle_gui_window_lifetime_message( &mut self, hwnd: HWND, packet: &MessagePacket, ) -> Option<LRESULT>549 fn handle_gui_window_lifetime_message( 550 &mut self, 551 hwnd: HWND, 552 packet: &MessagePacket, 553 ) -> Option<LRESULT> { 554 // Windows calls WndProc as a subroutine when we call `DestroyWindow()`. So, when handling 555 // WM_DESTROY/WM_NCDESTROY for one window, we would avoid calling `DestroyWindow()` on 556 // another window to avoid recursively mutably borrowing self. Instead, we do 557 // `DestroyWindow()` and clean up all associated resources on WM_CLOSE. The long-term fix is 558 // tracked by b/314379499. 559 match packet.msg { 560 WM_CLOSE => { 561 // If the window is in-use, return it to the vacant window pool. 562 // TODO(b/314309389): This only frees the `Surface` in WndProc thread, while the 563 // corresponding guest display isn't unplugged. We might need to figure out a way to 564 // inform `gpu_control_tube` to remove that display. 565 if self.try_release_surface_and_dissociate_gui_window(hwnd) { 566 // If the service isn't connnected (e.g. when debugging the emulator alone), we 567 // would request shutdown if no window is in-use anymore. 568 if self.gpu_main_display_tube.is_none() && self.in_use_gui_windows.is_empty() { 569 self.request_shutdown_gpu_display(); 570 } 571 return Some(0); 572 } 573 } 574 // Don't use any reference to `self` when handling WM_DESTROY/WM_NCDESTROY, since it is 575 // likely already mutably borrowed when handling WM_CLOSE on the same stack. 576 WM_NCDESTROY => { 577 info!("Window {:p} destroyed", hwnd); 578 // We don't care if removing the dispatcher pointer succeeds, since this window will 579 // be completely gone right after this function returns. 580 let property = win32_wide_string(DISPATCHER_PROPERTY_NAME); 581 // SAFETY: 582 // Safe because `hwnd` is valid, and `property` lives longer than the function call. 583 unsafe { RemovePropW(hwnd, property.as_ptr()) }; 584 return Some(0); 585 } 586 _ => (), 587 } 588 None 589 } 590 591 /// Signals GpuDisplay to close. This is not going to release any resources right away, but the 592 /// closure of GpuDisplay will trigger shutting down the entire VM, and all resources will be 593 /// released by then. request_shutdown_gpu_display(&self)594 fn request_shutdown_gpu_display(&self) { 595 if let Err(e) = self.close_requested_event.signal() { 596 error!("Failed to signal close requested event: {}", e); 597 } 598 } 599 600 /// Destroys all GUI windows and the message router window, and requests exiting message loop. shutdown(&mut self)601 fn shutdown(&mut self) { 602 info!("Shutting down all windows and message loop"); 603 604 // Destroy all GUI windows. 605 // Note that Windows calls WndProc as a subroutine when we call `DestroyWindow()`, we have 606 // to store window handles in a Vec and query the hashmaps every time rather than simply 607 // iterating through the hashmaps. 608 let in_use_handles: Vec<HWND> = self.in_use_gui_windows.keys().cloned().collect(); 609 for hwnd in in_use_handles.iter() { 610 if let Some(processor) = self.in_use_gui_windows.remove(hwnd) { 611 // SAFETY: 612 // Safe because we are dropping the `WindowResources` before the window is gone. 613 let resources = unsafe { processor.release_surface_and_take_window_resources() }; 614 if let Err(e) = resources.window().destroy() { 615 error!("Failed to destroy in-use GUI window: {:?}", e); 616 } 617 } 618 } 619 620 let vacant_handles: Vec<HWND> = self.vacant_gui_windows.keys().cloned().collect(); 621 for hwnd in vacant_handles.iter() { 622 if let Some(resources) = self.vacant_gui_windows.remove(hwnd) { 623 if let Err(e) = resources.window().destroy() { 624 error!("Failed to destroy vacant GUI window: {:?}", e); 625 } 626 } 627 } 628 629 // Destroy the message router window. 630 if let Some(window) = self.message_router_window.take() { 631 if let Err(e) = window.destroy() { 632 error!("Failed to destroy thread message router: {:?}", e); 633 } 634 } 635 636 // Exit the message loop. 637 // 638 // SAFETY: 639 // Safe because this function takes in no memory managed by us, and it always succeeds. 640 unsafe { 641 PostQuitMessage(0); 642 } 643 } 644 } 645