Rename struct Window to GuiWindow.

This is to differentiate it from another struct, MessageOnlyWindow.
The only change besides renaming is that the function
get_current_module_handle() is moved out of the impl block of GuiWindow
since it is used by both types of windows.

Bug: 279810202
Test: Ran GPG
Change-Id: Ica607d8e2e8f2e0f0525dd86765c345252042963
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4804698
Reviewed-by: Noah Gold <nkgold@google.com>
Commit-Queue: Kaiyi Li <kaiyili@google.com>
This commit is contained in:
Pujun Lun 2023-06-20 17:36:40 -07:00 committed by crosvm LUCI
parent 27fde06214
commit 081bca1c13
5 changed files with 81 additions and 77 deletions

View file

@ -8,7 +8,7 @@ use anyhow::Result;
use euclid::Size2D;
use metrics::sys::windows::Metrics;
use super::window::Window;
use super::window::GuiWindow;
use super::window_message_processor::HandleWindowMessage;
use super::window_message_processor::MessageHandlerResources;
use super::DisplayProperties;
@ -18,7 +18,7 @@ pub struct NoopSurface {}
impl NoopSurface {
pub fn create(
_window: &Window,
_window: &GuiWindow,
_virtual_display_size: &Size2D<i32, VirtualDisplaySpace>,
_metrics: Option<Weak<Metrics>>,
_display_properties: &DisplayProperties,

View file

@ -248,18 +248,18 @@ pub(crate) trait BasicWindow {
}
}
/// This class helps create and operate on a window using Windows APIs. The owner of `Window` object
/// is responsible for:
/// This class helps create and operate on a GUI window using Windows APIs. The owner of `GuiWindow`
/// object is responsible for:
/// (1) Calling `update_states()` when a new window message arrives.
/// (2) Dropping the `Window` object before the underlying window is completely gone.
pub struct Window {
/// (2) Dropping the `GuiWindow` object before the underlying window is completely gone.
pub struct GuiWindow {
hwnd: HWND,
size_move_loop_state: SizeMoveLoopState,
}
impl Window {
impl GuiWindow {
/// # Safety
/// The owner of `Window` object is responsible for dropping it before we finish processing
/// The owner of `GuiWindow` object is responsible for dropping it before we finish processing
/// `WM_NCDESTROY`, because the window handle will become invalid afterwards.
pub unsafe fn new(
wnd_proc: WNDPROC,
@ -272,7 +272,7 @@ impl Window {
info!("Creating GUI window");
static CONTEXT_MESSAGE: &str = "When creating Window";
let hinstance = Self::get_current_module_handle();
let hinstance = get_current_module_handle();
// If we fail to load any UI element below, use NULL to let the system use the default UI
// rather than crash.
let hicon = Self::load_custom_icon(hinstance, icon_resource_id).unwrap_or(null_mut());
@ -326,7 +326,7 @@ impl Window {
&self,
#[allow(unused)] projection_box: &Box2D<i32, HostWindowSpace>,
) {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
#[cfg(feature = "gfxstream")]
unsafe {
gfxstream_backend_setup_window(
@ -343,7 +343,7 @@ impl Window {
/// Calls `GetWindowLongPtrW()` internally.
pub fn get_attribute(&self, index: i32) -> Result<isize> {
// Safe because `Window` object won't outlive the HWND, and failures are handled below.
// Safe because `GuiWindow` object won't outlive the HWND, and failures are handled below.
unsafe {
// GetWindowLongPtrW() may return zero if we haven't set that attribute before, so we
// need to check if the error code is non-zero.
@ -358,7 +358,7 @@ impl Window {
/// Calls `SetWindowLongPtrW()` internally.
pub fn set_attribute(&self, index: i32, value: isize) -> Result<()> {
// Safe because `Window` object won't outlive the HWND, and failures are handled below.
// Safe because `GuiWindow` object won't outlive the HWND, and failures are handled below.
unsafe {
// SetWindowLongPtrW() may return zero if the previous value of that attribute was zero,
// so we need to check if the error code is non-zero.
@ -374,7 +374,7 @@ impl Window {
/// Calls `GetWindowRect()` internally.
pub fn get_window_rect(&self) -> Result<Rect> {
let mut rect: RECT = Default::default();
// Safe because `Window` object won't outlive the HWND, we know `rect` is valid, and
// Safe because `GuiWindow` object won't outlive the HWND, we know `rect` is valid, and
// failures are handled below.
unsafe {
if GetWindowRect(self.hwnd, &mut rect) == 0 {
@ -392,7 +392,7 @@ impl Window {
/// Calls `GetClientRect()` internally.
pub fn get_client_rect(&self) -> Result<Rect> {
let mut rect: RECT = Default::default();
// Safe because `Window` object won't outlive the HWND, we know `rect` is valid, and
// Safe because `GuiWindow` object won't outlive the HWND, we know `rect` is valid, and
// failures are handled below.
unsafe {
if GetClientRect(self.hwnd, &mut rect) == 0 {
@ -420,7 +420,7 @@ impl Window {
/// specified point to screen coordinates.
pub fn client_to_screen(&self, point: &Point) -> Result<Point> {
let mut point = point.to_sys_point();
// Safe because `Window` object won't outlive the HWND, we know `point` is valid, and
// Safe because `GuiWindow` object won't outlive the HWND, we know `point` is valid, and
// failures are handled below.
unsafe {
if ClientToScreen(self.hwnd, &mut point) == 0 {
@ -451,7 +451,7 @@ impl Window {
/// Calls `MonitorFromWindow()` internally. If the window is not on any active display monitor,
/// returns the handle to the closest one.
pub fn get_nearest_monitor_handle(&self) -> HMONITOR {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe { MonitorFromWindow(self.hwnd, MONITOR_DEFAULTTONEAREST) }
}
@ -464,13 +464,13 @@ impl Window {
/// Calls `MonitorFromWindow()` internally.
pub fn is_on_active_display(&self) -> bool {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe { !MonitorFromWindow(self.hwnd, MONITOR_DEFAULTTONULL).is_null() }
}
/// Calls `SetWindowPos()` internally.
pub fn set_pos(&self, window_rect: &Rect, flags: u32) -> Result<()> {
// Safe because `Window` object won't outlive the HWND, and failures are handled below.
// Safe because `GuiWindow` object won't outlive the HWND, and failures are handled below.
unsafe {
if SetWindowPos(
self.hwnd,
@ -502,7 +502,7 @@ impl Window {
/// Calls `ShowWindow()` internally. Note that it is more preferable to call `set_pos()` with
/// `SWP_SHOWWINDOW` since that would set the error code on failure.
pub fn show(&self) {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe {
ShowWindow(self.hwnd, SW_SHOW);
}
@ -510,7 +510,7 @@ impl Window {
/// Calls `ShowWindow()` internally to restore a minimized window.
pub fn restore(&self) {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe {
ShowWindow(self.hwnd, SW_RESTORE);
}
@ -520,14 +520,14 @@ impl Window {
/// is restored. For example, if we have switched from maximized to fullscreen, this function
/// would still return true.
pub fn was_maximized(&self) -> bool {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe { IsZoomed(self.hwnd) != 0 }
}
/// Calls `IsWindowVisible()` internally. We also require that the window size is nonzero to be
/// considered visible.
pub fn is_visible(&self) -> Result<bool> {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
if unsafe { IsWindowVisible(self.hwnd) } != 0 {
let window_rect = self
.get_window_rect()
@ -559,14 +559,14 @@ impl Window {
/// Calls `IsIconic()` internally.
pub fn is_minimized(&self) -> bool {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe { IsIconic(self.hwnd) != 0 }
}
/// Calls `SetForegroundWindow()` internally. `SetForegroundWindow()` may fail, for example,
/// when the taskbar is in the foreground, hence this is a best-effort call.
pub fn bring_to_foreground(&self) {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
if unsafe { SetForegroundWindow(self.hwnd) } == 0 {
info!("Cannot bring the window to foreground.");
}
@ -582,7 +582,7 @@ impl Window {
hRgnBlur: null_mut(),
fTransitionOnMaximized: FALSE,
};
// Safe because `Window` object won't outlive the HWND, we know `blur_behind` is valid,
// Safe because `GuiWindow` object won't outlive the HWND, we know `blur_behind` is valid,
// and failures are handled below.
let errno = unsafe { DwmEnableBlurBehindWindow(self.hwnd, &blur_behind) };
match errno {
@ -604,7 +604,7 @@ impl Window {
dw_ex_style: u32,
) -> Result<Rect> {
let mut window_rect: RECT = client_rect.to_sys_rect();
// Safe because `Window` object won't outlive the HWND, we know `window_rect` is valid,
// Safe because `GuiWindow` object won't outlive the HWND, we know `window_rect` is valid,
// and failures are handled below.
unsafe {
if AdjustWindowRectExForDpi(
@ -627,8 +627,8 @@ impl Window {
length: mem::size_of::<WINDOWPLACEMENT>().try_into().unwrap(),
..Default::default()
};
// Safe because `Window` object won't outlive the HWND, we know `window_placement` is valid,
// and failures are handled below.
// Safe because `GuiWindow` object won't outlive the HWND, we know `window_placement` is
// valid, and failures are handled below.
unsafe {
if GetWindowPlacement(self.hwnd, &mut window_placement) == 0 {
syscall_bail!("Failed to call GetWindowPlacement()");
@ -643,7 +643,7 @@ impl Window {
/// Calls `PostMessageW()` internally.
pub fn post_message(&self, msg: UINT, w_param: WPARAM, l_param: LPARAM) -> Result<()> {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe {
if PostMessageW(self.hwnd, msg, w_param, l_param) == 0 {
syscall_bail!("Failed to call PostMessageW()");
@ -654,24 +654,10 @@ impl Window {
/// Calls `DefWindowProcW()` internally.
pub fn default_process_message(&self, packet: &MessagePacket) -> LRESULT {
// Safe because `Window` object won't outlive the HWND.
// Safe because `GuiWindow` object won't outlive the HWND.
unsafe { DefWindowProcW(self.hwnd, packet.msg, packet.w_param, packet.l_param) }
}
/// Calls `GetModuleHandleW()` internally.
fn get_current_module_handle() -> HMODULE {
// Safe because we handle failures below.
let hmodule = unsafe { GetModuleHandleW(null_mut()) };
if hmodule.is_null() {
// If it fails, we are in a very broken state and it doesn't make sense to keep running.
panic!(
"Failed to call GetModuleHandleW() for the current module (Error code {})",
unsafe { GetLastError() }
);
}
hmodule
}
/// Calls `LoadIconW()` internally.
fn load_custom_icon(hinstance: HINSTANCE, resource_id: WORD) -> Result<HICON> {
// Safe because we handle failures below.
@ -709,7 +695,7 @@ impl Window {
}
}
impl Drop for Window {
impl Drop for GuiWindow {
fn drop(&mut self) {
// Safe because it is called from the same thread the created the window.
if unsafe { IsWindow(self.hwnd) } == 0 {
@ -718,10 +704,10 @@ impl Drop for Window {
}
}
impl BasicWindow for Window {
impl BasicWindow for GuiWindow {
/// # Safety
/// The returned handle should be used carefully, since it may have become invalid if it
/// outlives the `Window` object.
/// outlives the `GuiWindow` object.
unsafe fn handle(&self) -> HWND {
self.hwnd
}
@ -742,7 +728,7 @@ impl MessageOnlyWindow {
info!("Creating message-only window");
static CONTEXT_MESSAGE: &str = "When creating MessageOnlyWindow";
let hinstance = Window::get_current_module_handle();
let hinstance = get_current_module_handle();
register_window_class(
wnd_proc,
hinstance,
@ -839,6 +825,20 @@ fn create_sys_window(
Ok(hwnd)
}
/// Calls `GetModuleHandleW()` internally.
fn get_current_module_handle() -> HMODULE {
// Safe because we handle failures below.
let hmodule = unsafe { GetModuleHandleW(null_mut()) };
if hmodule.is_null() {
// If it fails, we are in a very broken state and it doesn't make sense to keep running.
panic!(
"Failed to call GetModuleHandleW() for the current module (Error code {})",
unsafe { GetLastError() }
);
}
hmodule
}
/// If the resolution/orientation of the monitor changes, or if the monitor is unplugged, this must
/// be recreated with a valid HMONITOR.
pub struct MonitorInfo {

View file

@ -25,9 +25,9 @@ use winapi::shared::windef::HWND;
use winapi::um::winuser::*;
use super::window::BasicWindow;
use super::window::GuiWindow;
use super::window::MessageOnlyWindow;
use super::window::MessagePacket;
use super::window::Window;
use super::window_message_processor::*;
use super::ObjectId;
use crate::EventDevice;
@ -116,12 +116,12 @@ pub(crate) struct WindowMessageDispatcher<T: HandleWindowMessage> {
impl<T: HandleWindowMessage> WindowMessageDispatcher<T> {
/// This function should only be called once from the WndProc thread. It will take the ownership
/// of the `Window` object, and drop it before the underlying window is completely gone.
/// of the `GuiWindow` object, and drop it before the underlying window is completely gone.
/// TODO(b/238680252): This should be good enough for supporting multi-windowing, but we should
/// revisit it if we also want to manage some child windows of the crosvm window.
pub fn create(
message_router_window: MessageOnlyWindow,
gui_window: Window,
gui_window: GuiWindow,
gpu_main_display_tube: Option<Rc<Tube>>,
) -> Result<Pin<Box<Self>>> {
static CONTEXT_MESSAGE: &str = "When creating WindowMessageDispatcher";
@ -214,7 +214,7 @@ impl<T: HandleWindowMessage> WindowMessageDispatcher<T> {
}
}
fn create_message_processor(self: Pin<&mut Self>, window: Window) -> Result<()> {
fn create_message_processor(self: Pin<&mut Self>, window: GuiWindow) -> Result<()> {
if !window.is_valid() {
bail!("Window handle is invalid!");
}

View file

@ -22,8 +22,8 @@ use winapi::shared::minwindef::WPARAM;
use winapi::um::winuser::*;
use super::window::BasicWindow;
use super::window::GuiWindow;
use super::window::MessagePacket;
use super::window::Window;
use super::window_message_dispatcher::DisplayEventDispatcher;
use super::ObjectId;
use crate::EventDevice;
@ -60,7 +60,7 @@ pub struct MessageHandlerResources {
}
pub type CreateMessageHandlerFunction<T> =
Box<dyn FnOnce(&Window, MessageHandlerResources) -> Result<T>>;
Box<dyn FnOnce(&GuiWindow, MessageHandlerResources) -> Result<T>>;
/// Called after the handler creation finishes. The argument indicates whether that was successful.
pub type CreateMessageHandlerCallback = Box<dyn FnOnce(bool)>;
@ -84,10 +84,10 @@ pub enum DisplaySendToWndProc<T: HandleWindowMessage> {
pub trait HandleWindowMessage {
/// Called once when it is safe to assume all future messages targeting this window will be
/// dispatched to this handler.
fn on_message_dispatcher_attached(&mut self, _window: &Window) {}
fn on_message_dispatcher_attached(&mut self, _window: &GuiWindow) {}
/// Called when processing `WM_ACTIVATE`.
fn on_activate(&mut self, _window: &Window, _w_param: WPARAM) {}
fn on_activate(&mut self, _window: &GuiWindow, _w_param: WPARAM) {}
/// Called when processing `WM_MOUSEACTIVATE`. See possible return values:
/// https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mouseactivate#return-value
@ -99,68 +99,70 @@ pub trait HandleWindowMessage {
fn on_set_focus(&mut self) {}
/// Called when processing `WM_INPUT`.
fn on_raw_input(&mut self, _window: &Window, _l_param: LPARAM) {}
fn on_raw_input(&mut self, _window: &GuiWindow, _l_param: LPARAM) {}
/// Called when processing `WM_MOUSEMOVE`.
fn on_mouse_move(&mut self, _w_param: WPARAM, _l_param: LPARAM) {}
/// Called when processing `WM_LBUTTONDOWN` and `WM_LBUTTONUP`.
fn on_mouse_button_left(&mut self, _window: &Window, _is_down: bool, _l_param: LPARAM) {}
fn on_mouse_button_left(&mut self, _window: &GuiWindow, _is_down: bool, _l_param: LPARAM) {}
/// Called when processing `WM_RBUTTONDOWN` and `WM_RBUTTONUP`.
fn on_mouse_button_right(&mut self, _is_down: bool) {}
/// Called when processing `WM_MOUSEWHEEL`.
fn on_mouse_wheel(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM) {}
fn on_mouse_wheel(&mut self, _window: &GuiWindow, _w_param: WPARAM, _l_param: LPARAM) {}
/// Called when processing `WM_SETCURSOR`. It should return true if the cursor has been handled
/// and the default processing should be skipped.
fn on_set_cursor(&mut self, _window: &Window) -> bool {
fn on_set_cursor(&mut self, _window: &GuiWindow) -> bool {
false
}
/// Called when processing `WM_KEYDOWN`, `WM_KEYUP`, `WM_SYSKEYDOWN` and `WM_SYSKEYUP`.
fn on_key(&mut self, _window: &Window, _key_down: bool, _w_param: WPARAM, _l_param: LPARAM) {}
fn on_key(&mut self, _window: &GuiWindow, _key_down: bool, _w_param: WPARAM, _l_param: LPARAM) {
}
/// Called when processing `WM_WINDOWPOSCHANGING`.
fn on_window_pos_changing(&mut self, _window: &Window, _l_param: LPARAM) {}
fn on_window_pos_changing(&mut self, _window: &GuiWindow, _l_param: LPARAM) {}
/// Called when processing `WM_SIZING`.
fn on_window_size_changing(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM) {}
fn on_window_size_changing(&mut self, _window: &GuiWindow, _w_param: WPARAM, _l_param: LPARAM) {
}
/// Called when processing `WM_WINDOWPOSCHANGED`. It should return true if it is intended to
/// skip default processing, in which case `WM_SIZE` and `WM_MOVE` won't be sent to the window.
fn on_window_pos_changed(&mut self, _window: &Window, _l_param: LPARAM) -> bool {
fn on_window_pos_changed(&mut self, _window: &GuiWindow, _l_param: LPARAM) -> bool {
false
}
/// Called when processing `WM_SIZE`.
fn on_window_size_changed(&mut self, _window: &Window, _w_param: WPARAM, _l_param: LPARAM) {}
fn on_window_size_changed(&mut self, _window: &GuiWindow, _w_param: WPARAM, _l_param: LPARAM) {}
/// Called when processing `WM_ENTERSIZEMOVE`.
fn on_enter_size_move(&mut self) {}
/// Called when processing `WM_EXITSIZEMOVE`.
fn on_exit_size_move(&mut self, _window: &Window) {}
fn on_exit_size_move(&mut self, _window: &GuiWindow) {}
/// Called when processing `WM_DISPLAYCHANGE`.
fn on_display_change(&mut self, _window: &Window) {}
fn on_display_change(&mut self, _window: &GuiWindow) {}
/// Called when processing requests from the service.
#[cfg(feature = "kiwi")]
fn on_handle_service_message(&mut self, _window: &Window, _message: &ServiceSendToGpu) {}
fn on_handle_service_message(&mut self, _window: &GuiWindow, _message: &ServiceSendToGpu) {}
/// Called when processing inbound events from event devices.
fn on_handle_event_device(
&mut self,
_window: &Window,
_window: &GuiWindow,
_event_device_kind: EventDeviceKind,
_event: virtio_input_event,
) {
}
/// Called when processing `WM_USER_HOST_VIEWPORT_CHANGE_INTERNAL`.
fn on_host_viewport_change(&mut self, _window: &Window, _l_param: LPARAM) {}
fn on_host_viewport_change(&mut self, _window: &GuiWindow, _l_param: LPARAM) {}
/// Called when processing `WM_CLOSE`. It should return true if the window should be destroyed
/// immediately.
@ -176,7 +178,7 @@ pub trait HandleWindowMessage {
/// retrieved from the message pump. Note that we rely on the owner of `WindowMessageProcessor`
/// object to drop it before the underlying window is completely gone.
pub(crate) struct WindowMessageProcessor<T: HandleWindowMessage> {
window: Window,
window: GuiWindow,
message_handler: Option<T>,
}
@ -184,7 +186,7 @@ impl<T: HandleWindowMessage> WindowMessageProcessor<T> {
/// # Safety
/// The owner of `WindowMessageProcessor` object is responsible for dropping it before we finish
/// processing `WM_NCDESTROY`, because the window handle will become invalid afterwards.
pub unsafe fn new(window: Window) -> Self {
pub unsafe fn new(window: GuiWindow) -> Self {
Self {
window,
message_handler: None,
@ -375,7 +377,7 @@ impl<T: HandleWindowMessage> WindowMessageProcessor<T> {
}
}
pub fn window(&self) -> &Window {
pub fn window(&self) -> &GuiWindow {
&self.window
}
}

View file

@ -45,9 +45,9 @@ use winapi::um::winbase::WAIT_OBJECT_0;
use winapi::um::winnt::MAXIMUM_WAIT_OBJECTS;
use winapi::um::winuser::*;
use super::window::GuiWindow;
use super::window::MessageOnlyWindow;
use super::window::MessagePacket;
use super::window::Window;
use super::window_message_dispatcher::WindowMessageDispatcher;
use super::window_message_dispatcher::DISPATCHER_PROPERTY_NAME;
use super::window_message_processor::*;
@ -249,7 +249,7 @@ impl<T: HandleWindowMessage> WindowProcedureThread<T> {
) {
let gpu_main_display_tube = gpu_main_display_tube.map(Rc::new);
// Safe because the dispatcher will take care of the lifetime of the `MessageOnlyWindow` and
// `Window` objects.
// `GuiWindow` objects.
match unsafe { Self::create_windows() }.and_then(|(message_router_window, gui_window)| {
WindowMessageDispatcher::<T>::create(
message_router_window,
@ -287,9 +287,11 @@ impl<T: HandleWindowMessage> WindowProcedureThread<T> {
}
fn run_message_loop_body(
#[cfg_attr(not(feature = "kiwi"), allow(unused_variables, unused_mut))]
mut message_dispatcher: Pin<Box<WindowMessageDispatcher<T>>>,
gpu_main_display_tube: Option<Rc<Tube>>,
) -> MessageLoopState {
#[cfg_attr(not(feature = "kiwi"), allow(unused_mut))]
let mut msg_wait_ctx = MsgWaitContext::new();
if let Some(tube) = &gpu_main_display_tube {
if let Err(e) = msg_wait_ctx.add(tube.get_read_notifier(), Token::ServiceMessage) {
@ -442,7 +444,7 @@ impl<T: HandleWindowMessage> WindowProcedureThread<T> {
/// # Safety
/// The owner of the returned window objects is responsible for dropping them before we finish
/// processing `WM_NCDESTROY`, because the window handle will become invalid afterwards.
unsafe fn create_windows() -> Result<(MessageOnlyWindow, Window)> {
unsafe fn create_windows() -> Result<(MessageOnlyWindow, GuiWindow)> {
let message_router_window = MessageOnlyWindow::new(
Some(Self::wnd_proc),
/* class_name */ "THREAD_MESSAGE_ROUTER",
@ -452,7 +454,7 @@ impl<T: HandleWindowMessage> WindowProcedureThread<T> {
// window may use the background brush to clear the gfxstream window client area when
// drawing occurs. This caused the screen flickering issue during resizing.
// See b/197786842 for details.
let gui_window = Window::new(
let gui_window = GuiWindow::new(
Some(Self::wnd_proc),
/* class_name */ "CROSVM",
/* title */ "crosvm",