xref: /aosp_15_r20/external/crosvm/gpu_display/src/gpu_display_win/window_message_dispatcher.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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