Refactor Windows platform implementation (#11393)

张小白 created

This aligns the Windows platform implementation with a code style
similar to macOS platform, eliminating most of the `Cell`s and
`Mutex`es. This adjustment facilitates potential future porting to a
multi-threaded implementation if required.

Overall, this PR made the following changes: it segregated all member
variables in `WindowsPlatform` and `WindowsWindow`, grouping together
variables that remain constant throughout the entire app lifecycle,
while placing variables that may change during app runtime into
`RefCell`.

Edit: 
During the code refactoring process, a bug was also fixed.

**Before**: 
Close window when file has changed, nothing happen:


https://github.com/zed-industries/zed/assets/14981363/0bcda7c1-808c-4b36-8953-a3a3365a314e

**After**:
Now `should_close` callback is properly handled


https://github.com/zed-industries/zed/assets/14981363/c8887b72-9a0b-42ad-b9ab-7d0775d843f5


Release Notes:

- N/A

Change summary

crates/gpui/src/platform/windows.rs                 |    4 
crates/gpui/src/platform/windows/display.rs         |    2 
crates/gpui/src/platform/windows/events.rs          | 1274 +++++++++++++++
crates/gpui/src/platform/windows/platform.rs        |  278 +-
crates/gpui/src/platform/windows/system_settings.rs |   81 
crates/gpui/src/platform/windows/util.rs            |   17 
crates/gpui/src/platform/windows/window.rs          | 1262 +-------------
7 files changed, 1,628 insertions(+), 1,290 deletions(-)

Detailed changes

crates/gpui/src/platform/windows.rs 🔗

@@ -1,14 +1,18 @@
 mod direct_write;
 mod dispatcher;
 mod display;
+mod events;
 mod platform;
+mod system_settings;
 mod util;
 mod window;
 
 pub(crate) use direct_write::*;
 pub(crate) use dispatcher::*;
 pub(crate) use display::*;
+pub(crate) use events::*;
 pub(crate) use platform::*;
+pub(crate) use system_settings::*;
 pub(crate) use util::*;
 pub(crate) use window::*;
 

crates/gpui/src/platform/windows/display.rs 🔗

@@ -9,7 +9,7 @@ use windows::{
 
 use crate::{Bounds, DevicePixels, DisplayId, PlatformDisplay, Point, Size};
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub(crate) struct WindowsDisplay {
     pub handle: HMONITOR,
     pub display_id: DisplayId,

crates/gpui/src/platform/windows/events.rs 🔗

@@ -0,0 +1,1274 @@
+use std::rc::Rc;
+
+use ::util::ResultExt;
+use anyhow::Context;
+use windows::Win32::{
+    Foundation::*,
+    Graphics::Gdi::*,
+    System::SystemServices::*,
+    UI::{
+        HiDpi::*,
+        Input::{Ime::*, KeyboardAndMouse::*},
+        WindowsAndMessaging::*,
+    },
+};
+
+use crate::*;
+
+pub(crate) const CURSOR_STYLE_CHANGED: u32 = WM_USER + 1;
+pub(crate) const MOUSE_WHEEL_SETTINGS_CHANGED: u32 = WM_USER + 2;
+pub(crate) const MOUSE_WHEEL_SETTINGS_SCROLL_CHARS_CHANGED: isize = 1;
+pub(crate) const MOUSE_WHEEL_SETTINGS_SCROLL_LINES_CHANGED: isize = 2;
+pub(crate) const CLOSE_ONE_WINDOW: u32 = WM_USER + 3;
+const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;
+
+pub(crate) fn handle_msg(
+    handle: HWND,
+    msg: u32,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> LRESULT {
+    let handled = match msg {
+        WM_ACTIVATE => handle_activate_msg(handle, wparam, state_ptr),
+        WM_CREATE => handle_create_msg(handle, state_ptr),
+        WM_MOVE => handle_move_msg(handle, lparam, state_ptr),
+        WM_SIZE => handle_size_msg(lparam, state_ptr),
+        WM_ENTERSIZEMOVE | WM_ENTERMENULOOP => handle_size_move_loop(handle),
+        WM_EXITSIZEMOVE | WM_EXITMENULOOP => handle_size_move_loop_exit(handle),
+        WM_TIMER => handle_timer_msg(handle, wparam, state_ptr),
+        WM_NCCALCSIZE => handle_calc_client_size(handle, wparam, lparam, state_ptr),
+        WM_DPICHANGED => handle_dpi_changed_msg(handle, wparam, lparam, state_ptr),
+        WM_NCHITTEST => handle_hit_test_msg(handle, msg, wparam, lparam, state_ptr),
+        WM_PAINT => handle_paint_msg(handle, state_ptr),
+        WM_CLOSE => handle_close_msg(state_ptr),
+        WM_DESTROY => handle_destroy_msg(handle, state_ptr),
+        WM_MOUSEMOVE => handle_mouse_move_msg(lparam, wparam, state_ptr),
+        WM_NCMOUSEMOVE => handle_nc_mouse_move_msg(handle, lparam, state_ptr),
+        WM_NCLBUTTONDOWN => {
+            handle_nc_mouse_down_msg(handle, MouseButton::Left, wparam, lparam, state_ptr)
+        }
+        WM_NCRBUTTONDOWN => {
+            handle_nc_mouse_down_msg(handle, MouseButton::Right, wparam, lparam, state_ptr)
+        }
+        WM_NCMBUTTONDOWN => {
+            handle_nc_mouse_down_msg(handle, MouseButton::Middle, wparam, lparam, state_ptr)
+        }
+        WM_NCLBUTTONUP => {
+            handle_nc_mouse_up_msg(handle, MouseButton::Left, wparam, lparam, state_ptr)
+        }
+        WM_NCRBUTTONUP => {
+            handle_nc_mouse_up_msg(handle, MouseButton::Right, wparam, lparam, state_ptr)
+        }
+        WM_NCMBUTTONUP => {
+            handle_nc_mouse_up_msg(handle, MouseButton::Middle, wparam, lparam, state_ptr)
+        }
+        WM_LBUTTONDOWN => handle_mouse_down_msg(MouseButton::Left, lparam, state_ptr),
+        WM_RBUTTONDOWN => handle_mouse_down_msg(MouseButton::Right, lparam, state_ptr),
+        WM_MBUTTONDOWN => handle_mouse_down_msg(MouseButton::Middle, lparam, state_ptr),
+        WM_XBUTTONDOWN => handle_xbutton_msg(wparam, lparam, handle_mouse_down_msg, state_ptr),
+        WM_LBUTTONUP => handle_mouse_up_msg(MouseButton::Left, lparam, state_ptr),
+        WM_RBUTTONUP => handle_mouse_up_msg(MouseButton::Right, lparam, state_ptr),
+        WM_MBUTTONUP => handle_mouse_up_msg(MouseButton::Middle, lparam, state_ptr),
+        WM_XBUTTONUP => handle_xbutton_msg(wparam, lparam, handle_mouse_up_msg, state_ptr),
+        WM_MOUSEWHEEL => handle_mouse_wheel_msg(handle, wparam, lparam, state_ptr),
+        WM_MOUSEHWHEEL => handle_mouse_horizontal_wheel_msg(handle, wparam, lparam, state_ptr),
+        WM_SYSKEYDOWN => handle_syskeydown_msg(handle, wparam, lparam, state_ptr),
+        WM_SYSKEYUP => handle_syskeyup_msg(handle, wparam, state_ptr),
+        WM_KEYDOWN => handle_keydown_msg(handle, wparam, lparam, state_ptr),
+        WM_KEYUP => handle_keyup_msg(handle, wparam, state_ptr),
+        WM_CHAR => handle_char_msg(handle, wparam, lparam, state_ptr),
+        WM_IME_STARTCOMPOSITION => handle_ime_position(handle, state_ptr),
+        WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
+        WM_SETCURSOR => handle_set_cursor(lparam, state_ptr),
+        CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
+        MOUSE_WHEEL_SETTINGS_CHANGED => handle_mouse_wheel_settings_msg(wparam, lparam, state_ptr),
+        _ => None,
+    };
+    if let Some(n) = handled {
+        LRESULT(n)
+    } else {
+        unsafe { DefWindowProcW(handle, msg, wparam, lparam) }
+    }
+}
+
+fn handle_move_msg(
+    handle: HWND,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let x = lparam.signed_loword() as i32;
+    let y = lparam.signed_hiword() as i32;
+    let mut lock = state_ptr.state.borrow_mut();
+    lock.origin = point(x.into(), y.into());
+    let size = lock.physical_size;
+    let center_x = x + size.width.0 / 2;
+    let center_y = y + size.height.0 / 2;
+    let monitor_bounds = lock.display.bounds();
+    if center_x < monitor_bounds.left().0
+        || center_x > monitor_bounds.right().0
+        || center_y < monitor_bounds.top().0
+        || center_y > monitor_bounds.bottom().0
+    {
+        // center of the window may have moved to another monitor
+        let monitor = unsafe { MonitorFromWindow(handle, MONITOR_DEFAULTTONULL) };
+        if !monitor.is_invalid() && lock.display.handle != monitor {
+            // we will get the same monitor if we only have one
+            lock.display = WindowsDisplay::new_with_handle(monitor);
+        }
+    }
+    if let Some(mut callback) = lock.callbacks.moved.take() {
+        drop(lock);
+        callback();
+        state_ptr.state.borrow_mut().callbacks.moved = Some(callback);
+    }
+    Some(0)
+}
+
+fn handle_size_msg(lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    let width = lparam.loword().max(1) as i32;
+    let height = lparam.hiword().max(1) as i32;
+    let new_physical_size = size(width.into(), height.into());
+    let mut lock = state_ptr.state.borrow_mut();
+    let scale_factor = lock.scale_factor;
+    lock.physical_size = new_physical_size;
+    lock.renderer.update_drawable_size(Size {
+        width: width as f64,
+        height: height as f64,
+    });
+    if let Some(mut callback) = lock.callbacks.resize.take() {
+        drop(lock);
+        let logical_size = logical_size(new_physical_size, scale_factor);
+        callback(logical_size, scale_factor);
+        state_ptr.state.borrow_mut().callbacks.resize = Some(callback);
+    }
+    Some(0)
+}
+
+fn handle_size_move_loop(handle: HWND) -> Option<isize> {
+    unsafe {
+        let ret = SetTimer(handle, SIZE_MOVE_LOOP_TIMER_ID, USER_TIMER_MINIMUM, None);
+        if ret == 0 {
+            log::error!(
+                "unable to create timer: {}",
+                std::io::Error::last_os_error()
+            );
+        }
+    }
+    None
+}
+
+fn handle_size_move_loop_exit(handle: HWND) -> Option<isize> {
+    unsafe {
+        KillTimer(handle, SIZE_MOVE_LOOP_TIMER_ID).log_err();
+    }
+    None
+}
+
+fn handle_timer_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    if wparam.0 == SIZE_MOVE_LOOP_TIMER_ID {
+        for runnable in state_ptr.main_receiver.drain() {
+            runnable.run();
+        }
+        handle_paint_msg(handle, state_ptr)
+    } else {
+        None
+    }
+}
+
+fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    let mut paint_struct = PAINTSTRUCT::default();
+    let _hdc = unsafe { BeginPaint(handle, &mut paint_struct) };
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut request_frame) = lock.callbacks.request_frame.take() {
+        drop(lock);
+        request_frame();
+        state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame);
+    }
+    unsafe { EndPaint(handle, &paint_struct) };
+    Some(0)
+}
+
+fn handle_close_msg(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.should_close.take() {
+        drop(lock);
+        let should_close = callback();
+        state_ptr.state.borrow_mut().callbacks.should_close = Some(callback);
+        if should_close {
+            None
+        } else {
+            Some(0)
+        }
+    } else {
+        None
+    }
+}
+
+fn handle_destroy_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    let callback = {
+        let mut lock = state_ptr.state.borrow_mut();
+        lock.callbacks.close.take()
+    };
+    if let Some(callback) = callback {
+        callback();
+    }
+    unsafe {
+        PostMessageW(None, CLOSE_ONE_WINDOW, None, LPARAM(handle.0)).log_err();
+    }
+    Some(0)
+}
+
+fn handle_mouse_move_msg(
+    lparam: LPARAM,
+    wparam: WPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let scale_factor = lock.scale_factor;
+        drop(lock);
+        let pressed_button = match MODIFIERKEYS_FLAGS(wparam.loword() as u32) {
+            flags if flags.contains(MK_LBUTTON) => Some(MouseButton::Left),
+            flags if flags.contains(MK_RBUTTON) => Some(MouseButton::Right),
+            flags if flags.contains(MK_MBUTTON) => Some(MouseButton::Middle),
+            flags if flags.contains(MK_XBUTTON1) => {
+                Some(MouseButton::Navigate(NavigationDirection::Back))
+            }
+            flags if flags.contains(MK_XBUTTON2) => {
+                Some(MouseButton::Navigate(NavigationDirection::Forward))
+            }
+            _ => None,
+        };
+        let x = lparam.signed_loword() as f32;
+        let y = lparam.signed_hiword() as f32;
+        let event = MouseMoveEvent {
+            position: logical_point(x, y, scale_factor),
+            pressed_button,
+            modifiers: current_modifiers(),
+        };
+        let result = if callback(PlatformInput::MouseMove(event)).default_prevented {
+            Some(0)
+        } else {
+            Some(1)
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+        return result;
+    }
+    Some(1)
+}
+
+fn handle_syskeydown_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    // we need to call `DefWindowProcW`, or we will lose the system-wide `Alt+F4`, `Alt+{other keys}`
+    // shortcuts.
+    let Some(keystroke) = parse_syskeydown_msg_keystroke(wparam) else {
+        return None;
+    };
+    let mut lock = state_ptr.state.borrow_mut();
+    let Some(mut func) = lock.callbacks.input.take() else {
+        return None;
+    };
+    drop(lock);
+    let event = KeyDownEvent {
+        keystroke,
+        is_held: lparam.0 & (0x1 << 30) > 0,
+    };
+    let result = if func(PlatformInput::KeyDown(event)).default_prevented {
+        invalidate_client_area(handle);
+        Some(0)
+    } else {
+        None
+    };
+    state_ptr.state.borrow_mut().callbacks.input = Some(func);
+
+    result
+}
+
+fn handle_syskeyup_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    // we need to call `DefWindowProcW`, or we will lose the system-wide `Alt+F4`, `Alt+{other keys}`
+    // shortcuts.
+    let Some(keystroke) = parse_syskeydown_msg_keystroke(wparam) else {
+        return None;
+    };
+    let mut lock = state_ptr.state.borrow_mut();
+    let Some(mut func) = lock.callbacks.input.take() else {
+        return None;
+    };
+    drop(lock);
+    let event = KeyUpEvent { keystroke };
+    let result = if func(PlatformInput::KeyUp(event)).default_prevented {
+        invalidate_client_area(handle);
+        Some(0)
+    } else {
+        Some(1)
+    };
+    state_ptr.state.borrow_mut().callbacks.input = Some(func);
+
+    result
+}
+
+fn handle_keydown_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let Some(keystroke) = parse_keydown_msg_keystroke(wparam) else {
+        return Some(1);
+    };
+    let mut lock = state_ptr.state.borrow_mut();
+    let Some(mut func) = lock.callbacks.input.take() else {
+        return Some(1);
+    };
+    drop(lock);
+    let event = KeyDownEvent {
+        keystroke,
+        is_held: lparam.0 & (0x1 << 30) > 0,
+    };
+    let result = if func(PlatformInput::KeyDown(event)).default_prevented {
+        invalidate_client_area(handle);
+        Some(0)
+    } else {
+        Some(1)
+    };
+    state_ptr.state.borrow_mut().callbacks.input = Some(func);
+
+    result
+}
+
+fn handle_keyup_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let Some(keystroke) = parse_keydown_msg_keystroke(wparam) else {
+        return Some(1);
+    };
+    let mut lock = state_ptr.state.borrow_mut();
+    let Some(mut func) = lock.callbacks.input.take() else {
+        return Some(1);
+    };
+    drop(lock);
+    let event = KeyUpEvent { keystroke };
+    let result = if func(PlatformInput::KeyUp(event)).default_prevented {
+        invalidate_client_area(handle);
+        Some(0)
+    } else {
+        Some(1)
+    };
+    state_ptr.state.borrow_mut().callbacks.input = Some(func);
+
+    result
+}
+
+fn handle_char_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let Some(keystroke) = parse_char_msg_keystroke(wparam) else {
+        return Some(1);
+    };
+    let mut lock = state_ptr.state.borrow_mut();
+    let Some(mut func) = lock.callbacks.input.take() else {
+        return Some(1);
+    };
+    drop(lock);
+    let ime_key = keystroke.ime_key.clone();
+    let event = KeyDownEvent {
+        keystroke,
+        is_held: lparam.0 & (0x1 << 30) > 0,
+    };
+
+    let dispatch_event_result = func(PlatformInput::KeyDown(event));
+    let mut lock = state_ptr.state.borrow_mut();
+    lock.callbacks.input = Some(func);
+    if dispatch_event_result.default_prevented || !dispatch_event_result.propagate {
+        invalidate_client_area(handle);
+        return Some(0);
+    }
+    let Some(ime_char) = ime_key else {
+        return Some(1);
+    };
+    let Some(mut input_handler) = lock.input_handler.take() else {
+        return Some(1);
+    };
+    drop(lock);
+    input_handler.replace_text_in_range(None, &ime_char);
+    invalidate_client_area(handle);
+    state_ptr.state.borrow_mut().input_handler = Some(input_handler);
+
+    Some(0)
+}
+
+fn handle_mouse_down_msg(
+    button: MouseButton,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let x = lparam.signed_loword() as f32;
+        let y = lparam.signed_hiword() as f32;
+        let physical_point = point(DevicePixels(x as i32), DevicePixels(y as i32));
+        let click_count = lock.click_state.update(button, physical_point);
+        let scale_factor = lock.scale_factor;
+        drop(lock);
+
+        let event = MouseDownEvent {
+            button,
+            position: logical_point(x, y, scale_factor),
+            modifiers: current_modifiers(),
+            click_count,
+            first_mouse: false,
+        };
+        let result = if callback(PlatformInput::MouseDown(event)).default_prevented {
+            Some(0)
+        } else {
+            Some(1)
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+
+        result
+    } else {
+        Some(1)
+    }
+}
+
+fn handle_mouse_up_msg(
+    button: MouseButton,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let x = lparam.signed_loword() as f32;
+        let y = lparam.signed_hiword() as f32;
+        let click_count = lock.click_state.current_count;
+        let scale_factor = lock.scale_factor;
+        drop(lock);
+
+        let event = MouseUpEvent {
+            button,
+            position: logical_point(x, y, scale_factor),
+            modifiers: current_modifiers(),
+            click_count,
+        };
+        let result = if callback(PlatformInput::MouseUp(event)).default_prevented {
+            Some(0)
+        } else {
+            Some(1)
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+
+        result
+    } else {
+        Some(1)
+    }
+}
+
+fn handle_xbutton_msg(
+    wparam: WPARAM,
+    lparam: LPARAM,
+    handler: impl Fn(MouseButton, LPARAM, Rc<WindowsWindowStatePtr>) -> Option<isize>,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let nav_dir = match wparam.hiword() {
+        XBUTTON1 => NavigationDirection::Back,
+        XBUTTON2 => NavigationDirection::Forward,
+        _ => return Some(1),
+    };
+    handler(MouseButton::Navigate(nav_dir), lparam, state_ptr)
+}
+
+fn handle_mouse_wheel_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let scale_factor = lock.scale_factor;
+        let wheel_scroll_lines = lock.mouse_wheel_settings.wheel_scroll_lines;
+        drop(lock);
+        let wheel_distance =
+            (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32) * wheel_scroll_lines as f32;
+        let mut cursor_point = POINT {
+            x: lparam.signed_loword().into(),
+            y: lparam.signed_hiword().into(),
+        };
+        unsafe { ScreenToClient(handle, &mut cursor_point) };
+        let event = ScrollWheelEvent {
+            position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
+            delta: ScrollDelta::Lines(Point {
+                x: 0.0,
+                y: wheel_distance,
+            }),
+            modifiers: current_modifiers(),
+            touch_phase: TouchPhase::Moved,
+        };
+        let result = if callback(PlatformInput::ScrollWheel(event)).default_prevented {
+            Some(0)
+        } else {
+            Some(1)
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+
+        result
+    } else {
+        Some(1)
+    }
+}
+
+fn handle_mouse_horizontal_wheel_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let scale_factor = lock.scale_factor;
+        let wheel_scroll_chars = lock.mouse_wheel_settings.wheel_scroll_chars;
+        drop(lock);
+        let wheel_distance =
+            (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32) * wheel_scroll_chars as f32;
+        let mut cursor_point = POINT {
+            x: lparam.signed_loword().into(),
+            y: lparam.signed_hiword().into(),
+        };
+        unsafe { ScreenToClient(handle, &mut cursor_point) };
+        let event = ScrollWheelEvent {
+            position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
+            delta: ScrollDelta::Lines(Point {
+                x: wheel_distance,
+                y: 0.0,
+            }),
+            modifiers: current_modifiers(),
+            touch_phase: TouchPhase::Moved,
+        };
+        let result = if callback(PlatformInput::ScrollWheel(event)).default_prevented {
+            Some(0)
+        } else {
+            Some(1)
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+
+        result
+    } else {
+        Some(1)
+    }
+}
+
+fn handle_ime_position(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    unsafe {
+        let mut lock = state_ptr.state.borrow_mut();
+        let ctx = ImmGetContext(handle);
+        let Some(mut input_handler) = lock.input_handler.take() else {
+            return Some(1);
+        };
+        let scale_factor = lock.scale_factor;
+        drop(lock);
+
+        let caret_range = input_handler.selected_text_range().unwrap_or_default();
+        let caret_position = input_handler.bounds_for_range(caret_range).unwrap();
+        state_ptr.state.borrow_mut().input_handler = Some(input_handler);
+        let config = CANDIDATEFORM {
+            dwStyle: CFS_CANDIDATEPOS,
+            // logical to physical
+            ptCurrentPos: POINT {
+                x: (caret_position.origin.x.0 * scale_factor) as i32,
+                y: (caret_position.origin.y.0 * scale_factor) as i32
+                    + ((caret_position.size.height.0 * scale_factor) as i32 / 2),
+            },
+            ..Default::default()
+        };
+        ImmSetCandidateWindow(ctx, &config as _);
+        ImmReleaseContext(handle, ctx);
+        Some(0)
+    }
+}
+
+fn handle_ime_composition(
+    handle: HWND,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let mut ime_input = None;
+    if lparam.0 as u32 & GCS_COMPSTR.0 > 0 {
+        let Some((string, string_len)) = parse_ime_compostion_string(handle) else {
+            return None;
+        };
+        let mut lock = state_ptr.state.borrow_mut();
+        let Some(mut input_handler) = lock.input_handler.take() else {
+            return None;
+        };
+        drop(lock);
+        input_handler.replace_and_mark_text_in_range(None, string.as_str(), Some(0..string_len));
+        state_ptr.state.borrow_mut().input_handler = Some(input_handler);
+        ime_input = Some(string);
+    }
+    if lparam.0 as u32 & GCS_CURSORPOS.0 > 0 {
+        let Some(ref comp_string) = ime_input else {
+            return None;
+        };
+        let caret_pos = retrieve_composition_cursor_position(handle);
+        let mut lock = state_ptr.state.borrow_mut();
+        let Some(mut input_handler) = lock.input_handler.take() else {
+            return None;
+        };
+        drop(lock);
+        input_handler.replace_and_mark_text_in_range(None, comp_string, Some(0..caret_pos));
+        state_ptr.state.borrow_mut().input_handler = Some(input_handler);
+    }
+    if lparam.0 as u32 & GCS_RESULTSTR.0 > 0 {
+        let Some(comp_result) = parse_ime_compostion_result(handle) else {
+            return None;
+        };
+        let mut lock = state_ptr.state.borrow_mut();
+        let Some(mut input_handler) = lock.input_handler.take() else {
+            return Some(1);
+        };
+        drop(lock);
+        input_handler.replace_text_in_range(None, &comp_result);
+        state_ptr.state.borrow_mut().input_handler = Some(input_handler);
+        invalidate_client_area(handle);
+        return Some(0);
+    }
+    // currently, we don't care other stuff
+    None
+}
+
+/// SEE: https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize
+fn handle_calc_client_size(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    if !state_ptr.hide_title_bar || state_ptr.state.borrow().is_fullscreen() {
+        return None;
+    }
+
+    if wparam.0 == 0 {
+        return None;
+    }
+
+    let dpi = unsafe { GetDpiForWindow(handle) };
+
+    let frame_x = unsafe { GetSystemMetricsForDpi(SM_CXFRAME, dpi) };
+    let frame_y = unsafe { GetSystemMetricsForDpi(SM_CYFRAME, dpi) };
+    let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) };
+
+    // wparam is TRUE so lparam points to an NCCALCSIZE_PARAMS structure
+    let mut params = lparam.0 as *mut NCCALCSIZE_PARAMS;
+    let mut requested_client_rect = unsafe { &mut ((*params).rgrc) };
+
+    requested_client_rect[0].right -= frame_x + padding;
+    requested_client_rect[0].left += frame_x + padding;
+    requested_client_rect[0].bottom -= frame_y + padding;
+
+    Some(0)
+}
+
+fn handle_activate_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let activated = wparam.loword() > 0;
+    if state_ptr.hide_title_bar {
+        if let Some(titlebar_rect) = state_ptr.state.borrow().get_titlebar_rect().log_err() {
+            unsafe { InvalidateRect(handle, Some(&titlebar_rect), FALSE) };
+        }
+    }
+    let this = state_ptr.clone();
+    state_ptr
+        .executor
+        .spawn(async move {
+            let mut lock = this.state.borrow_mut();
+            if let Some(mut cb) = lock.callbacks.active_status_change.take() {
+                drop(lock);
+                cb(activated);
+                this.state.borrow_mut().callbacks.active_status_change = Some(cb);
+            }
+        })
+        .detach();
+
+    None
+}
+
+fn handle_create_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    let mut size_rect = RECT::default();
+    unsafe { GetWindowRect(handle, &mut size_rect).log_err() };
+
+    let width = size_rect.right - size_rect.left;
+    let height = size_rect.bottom - size_rect.top;
+
+    if state_ptr.hide_title_bar {
+        unsafe {
+            SetWindowPos(
+                handle,
+                None,
+                size_rect.left,
+                size_rect.top,
+                width,
+                height,
+                SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE,
+            )
+            .log_err()
+        };
+    }
+
+    Some(0)
+}
+
+fn handle_dpi_changed_msg(
+    handle: HWND,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    let new_dpi = wparam.loword() as f32;
+    state_ptr.state.borrow_mut().scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
+
+    let rect = unsafe { &*(lparam.0 as *const RECT) };
+    let width = rect.right - rect.left;
+    let height = rect.bottom - rect.top;
+    // this will emit `WM_SIZE` and `WM_MOVE` right here
+    // even before this function returns
+    // the new size is handled in `WM_SIZE`
+    unsafe {
+        SetWindowPos(
+            handle,
+            None,
+            rect.left,
+            rect.top,
+            width,
+            height,
+            SWP_NOZORDER | SWP_NOACTIVATE,
+        )
+        .context("unable to set window position after dpi has changed")
+        .log_err();
+    }
+    invalidate_client_area(handle);
+
+    Some(0)
+}
+
+fn handle_hit_test_msg(
+    handle: HWND,
+    msg: u32,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    if !state_ptr.hide_title_bar {
+        return None;
+    }
+
+    // default handler for resize areas
+    let hit = unsafe { DefWindowProcW(handle, msg, wparam, lparam) };
+    if matches!(
+        hit.0 as u32,
+        HTNOWHERE
+            | HTRIGHT
+            | HTLEFT
+            | HTTOPLEFT
+            | HTTOP
+            | HTTOPRIGHT
+            | HTBOTTOMRIGHT
+            | HTBOTTOM
+            | HTBOTTOMLEFT
+    ) {
+        return Some(hit.0);
+    }
+
+    if state_ptr.state.borrow().is_fullscreen() {
+        return Some(HTCLIENT as _);
+    }
+
+    let dpi = unsafe { GetDpiForWindow(handle) };
+    let frame_y = unsafe { GetSystemMetricsForDpi(SM_CYFRAME, dpi) };
+    let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) };
+
+    let mut cursor_point = POINT {
+        x: lparam.signed_loword().into(),
+        y: lparam.signed_hiword().into(),
+    };
+    unsafe { ScreenToClient(handle, &mut cursor_point) };
+    if cursor_point.y > 0 && cursor_point.y < frame_y + padding {
+        return Some(HTTOP as _);
+    }
+
+    let titlebar_rect = state_ptr.state.borrow().get_titlebar_rect();
+    if let Ok(titlebar_rect) = titlebar_rect {
+        if cursor_point.y < titlebar_rect.bottom {
+            let caption_btn_width = (state_ptr.state.borrow().caption_button_width().0
+                * state_ptr.state.borrow().scale_factor) as i32;
+            if cursor_point.x >= titlebar_rect.right - caption_btn_width {
+                return Some(HTCLOSE as _);
+            } else if cursor_point.x >= titlebar_rect.right - caption_btn_width * 2 {
+                return Some(HTMAXBUTTON as _);
+            } else if cursor_point.x >= titlebar_rect.right - caption_btn_width * 3 {
+                return Some(HTMINBUTTON as _);
+            }
+
+            return Some(HTCAPTION as _);
+        }
+    }
+
+    Some(HTCLIENT as _)
+}
+
+fn handle_nc_mouse_move_msg(
+    handle: HWND,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    if !state_ptr.hide_title_bar {
+        return None;
+    }
+
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let scale_factor = lock.scale_factor;
+        drop(lock);
+        let mut cursor_point = POINT {
+            x: lparam.signed_loword().into(),
+            y: lparam.signed_hiword().into(),
+        };
+        unsafe { ScreenToClient(handle, &mut cursor_point) };
+        let event = MouseMoveEvent {
+            position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
+            pressed_button: None,
+            modifiers: current_modifiers(),
+        };
+        let result = if callback(PlatformInput::MouseMove(event)).default_prevented {
+            Some(0)
+        } else {
+            Some(1)
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+
+        result
+    } else {
+        None
+    }
+}
+
+fn handle_nc_mouse_down_msg(
+    handle: HWND,
+    button: MouseButton,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    if !state_ptr.hide_title_bar {
+        return None;
+    }
+
+    let mut lock = state_ptr.state.borrow_mut();
+    let result = if let Some(mut callback) = lock.callbacks.input.take() {
+        let scale_factor = lock.scale_factor;
+        let mut cursor_point = POINT {
+            x: lparam.signed_loword().into(),
+            y: lparam.signed_hiword().into(),
+        };
+        unsafe { ScreenToClient(handle, &mut cursor_point) };
+        let physical_point = point(DevicePixels(cursor_point.x), DevicePixels(cursor_point.y));
+        let click_count = lock.click_state.update(button, physical_point);
+        drop(lock);
+        let event = MouseDownEvent {
+            button,
+            position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
+            modifiers: current_modifiers(),
+            click_count,
+            first_mouse: false,
+        };
+        let result = if callback(PlatformInput::MouseDown(event)).default_prevented {
+            Some(0)
+        } else {
+            None
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+
+        result
+    } else {
+        None
+    };
+
+    // Since these are handled in handle_nc_mouse_up_msg we must prevent the default window proc
+    result.or_else(|| matches!(wparam.0 as u32, HTMINBUTTON | HTMAXBUTTON | HTCLOSE).then_some(0))
+}
+
+fn handle_nc_mouse_up_msg(
+    handle: HWND,
+    button: MouseButton,
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    if !state_ptr.hide_title_bar {
+        return None;
+    }
+
+    let mut lock = state_ptr.state.borrow_mut();
+    if let Some(mut callback) = lock.callbacks.input.take() {
+        let scale_factor = lock.scale_factor;
+        drop(lock);
+        let mut cursor_point = POINT {
+            x: lparam.signed_loword().into(),
+            y: lparam.signed_hiword().into(),
+        };
+        unsafe { ScreenToClient(handle, &mut cursor_point) };
+        let event = MouseUpEvent {
+            button,
+            position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
+            modifiers: current_modifiers(),
+            click_count: 1,
+        };
+        let result = if callback(PlatformInput::MouseUp(event)).default_prevented {
+            Some(0)
+        } else {
+            None
+        };
+        state_ptr.state.borrow_mut().callbacks.input = Some(callback);
+        if result.is_some() {
+            return result;
+        }
+    } else {
+        drop(lock);
+    }
+
+    if button == MouseButton::Left {
+        match wparam.0 as u32 {
+            HTMINBUTTON => unsafe {
+                ShowWindowAsync(handle, SW_MINIMIZE);
+            },
+            HTMAXBUTTON => unsafe {
+                if state_ptr.state.borrow().is_maximized() {
+                    ShowWindowAsync(handle, SW_NORMAL);
+                } else {
+                    ShowWindowAsync(handle, SW_MAXIMIZE);
+                }
+            },
+            HTCLOSE => unsafe {
+                PostMessageW(handle, WM_CLOSE, WPARAM::default(), LPARAM::default()).log_err();
+            },
+            _ => return None,
+        };
+        return Some(0);
+    }
+
+    None
+}
+
+fn handle_cursor_changed(lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    state_ptr.state.borrow_mut().current_cursor = HCURSOR(lparam.0);
+    Some(0)
+}
+
+fn handle_set_cursor(lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
+    if matches!(
+        lparam.loword() as u32,
+        HTLEFT | HTRIGHT | HTTOP | HTTOPLEFT | HTTOPRIGHT | HTBOTTOM | HTBOTTOMLEFT | HTBOTTOMRIGHT
+    ) {
+        return None;
+    }
+    unsafe { SetCursor(state_ptr.state.borrow().current_cursor) };
+    Some(1)
+}
+
+fn handle_mouse_wheel_settings_msg(
+    wparam: WPARAM,
+    lparam: LPARAM,
+    state_ptr: Rc<WindowsWindowStatePtr>,
+) -> Option<isize> {
+    match lparam.0 {
+        1 => {
+            state_ptr
+                .state
+                .borrow_mut()
+                .mouse_wheel_settings
+                .wheel_scroll_chars = wparam.0 as u32
+        }
+        2 => {
+            state_ptr
+                .state
+                .borrow_mut()
+                .mouse_wheel_settings
+                .wheel_scroll_lines = wparam.0 as u32
+        }
+        _ => unreachable!(),
+    }
+    Some(0)
+}
+
+fn parse_syskeydown_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
+    let modifiers = current_modifiers();
+    if !modifiers.alt {
+        // on Windows, F10 can trigger this event, not just the alt key
+        // and we just don't care about F10
+        return None;
+    }
+
+    let vk_code = wparam.loword();
+    let basic_key = basic_vkcode_to_string(vk_code, modifiers);
+    if basic_key.is_some() {
+        return basic_key;
+    }
+
+    let key = match VIRTUAL_KEY(vk_code) {
+        VK_BACK => Some("backspace"),
+        VK_RETURN => Some("enter"),
+        VK_TAB => Some("tab"),
+        VK_UP => Some("up"),
+        VK_DOWN => Some("down"),
+        VK_RIGHT => Some("right"),
+        VK_LEFT => Some("left"),
+        VK_HOME => Some("home"),
+        VK_END => Some("end"),
+        VK_PRIOR => Some("pageup"),
+        VK_NEXT => Some("pagedown"),
+        VK_ESCAPE => Some("escape"),
+        VK_INSERT => Some("insert"),
+        _ => None,
+    };
+
+    if let Some(key) = key {
+        Some(Keystroke {
+            modifiers,
+            key: key.to_string(),
+            ime_key: None,
+        })
+    } else {
+        None
+    }
+}
+
+fn parse_keydown_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
+    let vk_code = wparam.loword();
+
+    let modifiers = current_modifiers();
+    if modifiers.control || modifiers.alt {
+        let basic_key = basic_vkcode_to_string(vk_code, modifiers);
+        if basic_key.is_some() {
+            return basic_key;
+        }
+    }
+
+    if vk_code >= VK_F1.0 && vk_code <= VK_F24.0 {
+        let offset = vk_code - VK_F1.0;
+        return Some(Keystroke {
+            modifiers,
+            key: format!("f{}", offset + 1),
+            ime_key: None,
+        });
+    }
+
+    let key = match VIRTUAL_KEY(vk_code) {
+        VK_BACK => Some("backspace"),
+        VK_RETURN => Some("enter"),
+        VK_TAB => Some("tab"),
+        VK_UP => Some("up"),
+        VK_DOWN => Some("down"),
+        VK_RIGHT => Some("right"),
+        VK_LEFT => Some("left"),
+        VK_HOME => Some("home"),
+        VK_END => Some("end"),
+        VK_PRIOR => Some("pageup"),
+        VK_NEXT => Some("pagedown"),
+        VK_ESCAPE => Some("escape"),
+        VK_INSERT => Some("insert"),
+        VK_DELETE => Some("delete"),
+        _ => None,
+    };
+
+    if let Some(key) = key {
+        Some(Keystroke {
+            modifiers,
+            key: key.to_string(),
+            ime_key: None,
+        })
+    } else {
+        None
+    }
+}
+
+fn parse_char_msg_keystroke(wparam: WPARAM) -> Option<Keystroke> {
+    let src = [wparam.0 as u16];
+    let Ok(first_char) = char::decode_utf16(src).collect::<Vec<_>>()[0] else {
+        return None;
+    };
+    if first_char.is_control() {
+        None
+    } else {
+        let mut modifiers = current_modifiers();
+        // for characters that use 'shift' to type it is expected that the
+        // shift is not reported if the uppercase/lowercase are the same and instead only the key is reported
+        if first_char.to_lowercase().to_string() == first_char.to_uppercase().to_string() {
+            modifiers.shift = false;
+        }
+        let key = match first_char {
+            ' ' => "space".to_string(),
+            first_char => first_char.to_lowercase().to_string(),
+        };
+        Some(Keystroke {
+            modifiers,
+            key,
+            ime_key: Some(first_char.to_string()),
+        })
+    }
+}
+
+/// mark window client rect to be re-drawn
+/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-invalidaterect
+pub(crate) fn invalidate_client_area(handle: HWND) {
+    unsafe { InvalidateRect(handle, None, FALSE) };
+}
+
+fn parse_ime_compostion_string(handle: HWND) -> Option<(String, usize)> {
+    unsafe {
+        let ctx = ImmGetContext(handle);
+        let string_len = ImmGetCompositionStringW(ctx, GCS_COMPSTR, None, 0);
+        let result = if string_len >= 0 {
+            let mut buffer = vec![0u8; string_len as usize + 2];
+            ImmGetCompositionStringW(
+                ctx,
+                GCS_COMPSTR,
+                Some(buffer.as_mut_ptr() as _),
+                string_len as _,
+            );
+            let wstring = std::slice::from_raw_parts::<u16>(
+                buffer.as_mut_ptr().cast::<u16>(),
+                string_len as usize / 2,
+            );
+            let string = String::from_utf16_lossy(wstring);
+            Some((string, string_len as usize / 2))
+        } else {
+            None
+        };
+        ImmReleaseContext(handle, ctx);
+        result
+    }
+}
+
+fn retrieve_composition_cursor_position(handle: HWND) -> usize {
+    unsafe {
+        let ctx = ImmGetContext(handle);
+        let ret = ImmGetCompositionStringW(ctx, GCS_CURSORPOS, None, 0);
+        ImmReleaseContext(handle, ctx);
+        ret as usize
+    }
+}
+
+fn parse_ime_compostion_result(handle: HWND) -> Option<String> {
+    unsafe {
+        let ctx = ImmGetContext(handle);
+        let string_len = ImmGetCompositionStringW(ctx, GCS_RESULTSTR, None, 0);
+        let result = if string_len >= 0 {
+            let mut buffer = vec![0u8; string_len as usize + 2];
+            ImmGetCompositionStringW(
+                ctx,
+                GCS_RESULTSTR,
+                Some(buffer.as_mut_ptr() as _),
+                string_len as _,
+            );
+            let wstring = std::slice::from_raw_parts::<u16>(
+                buffer.as_mut_ptr().cast::<u16>(),
+                string_len as usize / 2,
+            );
+            let string = String::from_utf16_lossy(wstring);
+            Some(string)
+        } else {
+            None
+        };
+        ImmReleaseContext(handle, ctx);
+        result
+    }
+}
+
+fn basic_vkcode_to_string(code: u16, modifiers: Modifiers) -> Option<Keystroke> {
+    match code {
+        // VK_0 - VK_9
+        48..=57 => Some(Keystroke {
+            modifiers,
+            key: format!("{}", code - VK_0.0),
+            ime_key: None,
+        }),
+        // VK_A - VK_Z
+        65..=90 => Some(Keystroke {
+            modifiers,
+            key: format!("{}", (b'a' + code as u8 - VK_A.0 as u8) as char),
+            ime_key: None,
+        }),
+        // VK_F1 - VK_F24
+        112..=135 => Some(Keystroke {
+            modifiers,
+            key: format!("f{}", code - VK_F1.0 + 1),
+            ime_key: None,
+        }),
+        // OEM3: `/~, OEM_MINUS: -/_, OEM_PLUS: =/+, ...
+        _ => {
+            if let Some(key) = oemkey_vkcode_to_string(code) {
+                Some(Keystroke {
+                    modifiers,
+                    key,
+                    ime_key: None,
+                })
+            } else {
+                None
+            }
+        }
+    }
+}
+
+fn oemkey_vkcode_to_string(code: u16) -> Option<String> {
+    match code {
+        186 => Some(";".to_string()), // VK_OEM_1
+        187 => Some("=".to_string()), // VK_OEM_PLUS
+        188 => Some(",".to_string()), // VK_OEM_COMMA
+        189 => Some("-".to_string()), // VK_OEM_MINUS
+        190 => Some(".".to_string()), // VK_OEM_PERIOD
+        // https://kbdlayout.info/features/virtualkeys/VK_ABNT_C1
+        191 | 193 => Some("/".to_string()), // VK_OEM_2 VK_ABNT_C1
+        192 => Some("`".to_string()),       // VK_OEM_3
+        219 => Some("[".to_string()),       // VK_OEM_4
+        220 => Some("\\".to_string()),      // VK_OEM_5
+        221 => Some("]".to_string()),       // VK_OEM_6
+        222 => Some("'".to_string()),       // VK_OEM_7
+        _ => None,
+    }
+}
+
+#[inline]
+fn is_virtual_key_pressed(vkey: VIRTUAL_KEY) -> bool {
+    unsafe { GetKeyState(vkey.0 as i32) < 0 }
+}
+
+#[inline]
+fn current_modifiers() -> Modifiers {
+    Modifiers {
+        control: is_virtual_key_pressed(VK_CONTROL),
+        alt: is_virtual_key_pressed(VK_MENU),
+        shift: is_virtual_key_pressed(VK_SHIFT),
+        platform: is_virtual_key_pressed(VK_LWIN) || is_virtual_key_pressed(VK_RWIN),
+        function: false,
+    }
+}

crates/gpui/src/platform/windows/platform.rs 🔗

@@ -3,8 +3,7 @@
 
 use std::{
     cell::{Cell, RefCell},
-    ffi::{c_uint, c_void, OsString},
-    iter::once,
+    ffi::{c_void, OsString},
     mem::transmute,
     os::windows::ffi::{OsStrExt, OsStringExt},
     path::{Path, PathBuf},
@@ -18,7 +17,7 @@ use async_task::Runnable;
 use copypasta::{ClipboardContext, ClipboardProvider};
 use futures::channel::oneshot::{self, Receiver};
 use itertools::Itertools;
-use parking_lot::{Mutex, RwLock};
+use parking_lot::RwLock;
 use semantic_version::SemanticVersion;
 use smallvec::SmallVec;
 use time::UtcOffset;
@@ -39,56 +38,26 @@ use windows::{
 use crate::*;
 
 pub(crate) struct WindowsPlatform {
-    inner: Rc<WindowsPlatformInner>,
-}
-
-/// Windows settings pulled from SystemParametersInfo
-/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow
-#[derive(Default, Debug)]
-pub(crate) struct WindowsPlatformSystemSettings {
-    /// SEE: SPI_GETWHEELSCROLLCHARS
-    pub(crate) wheel_scroll_chars: u32,
-
-    /// SEE: SPI_GETWHEELSCROLLLINES
-    pub(crate) wheel_scroll_lines: u32,
-}
-
-pub(crate) struct WindowsPlatformInner {
-    background_executor: BackgroundExecutor,
-    pub(crate) foreground_executor: ForegroundExecutor,
+    state: RefCell<WindowsPlatformState>,
+    raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
+    // The below members will never change throughout the entire lifecycle of the app.
+    icon: HICON,
     main_receiver: flume::Receiver<Runnable>,
+    background_executor: BackgroundExecutor,
+    foreground_executor: ForegroundExecutor,
     text_system: Arc<dyn PlatformTextSystem>,
-    callbacks: Mutex<Callbacks>,
-    pub raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
-    pub(crate) dispatch_event: OwnedHandle,
-    pub(crate) settings: RefCell<WindowsPlatformSystemSettings>,
-    pub icon: HICON,
-    // NOTE: standard cursor handles don't need to close.
-    pub(crate) current_cursor: Cell<HCURSOR>,
+    dispatch_event: OwnedHandle,
 }
 
-impl WindowsPlatformInner {
-    pub(crate) fn try_get_windows_inner_from_hwnd(
-        &self,
-        hwnd: HWND,
-    ) -> Option<Rc<WindowsWindowInner>> {
-        self.raw_window_handles
-            .read()
-            .iter()
-            .find(|entry| *entry == &hwnd)
-            .and_then(|hwnd| try_get_window_inner(*hwnd))
-    }
-
-    #[inline]
-    pub fn run_foreground_tasks(&self) {
-        for runnable in self.main_receiver.drain() {
-            runnable.run();
-        }
-    }
+pub(crate) struct WindowsPlatformState {
+    callbacks: PlatformCallbacks,
+    pub(crate) settings: WindowsPlatformSystemSettings,
+    // NOTE: standard cursor handles don't need to close.
+    pub(crate) current_cursor: HCURSOR,
 }
 
 #[derive(Default)]
-struct Callbacks {
+struct PlatformCallbacks {
     open_urls: Option<Box<dyn FnMut(Vec<String>)>>,
     quit: Option<Box<dyn FnMut()>>,
     reopen: Option<Box<dyn FnMut()>>,
@@ -97,53 +66,16 @@ struct Callbacks {
     validate_app_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
 }
 
-enum WindowsMessageWaitResult {
-    ForegroundExecution,
-    WindowsMessage(MSG),
-    Error,
-}
-
-impl WindowsPlatformSystemSettings {
+impl WindowsPlatformState {
     fn new() -> Self {
-        let mut settings = Self::default();
-        settings.update_all();
-        settings
-    }
-
-    pub(crate) fn update_all(&mut self) {
-        self.update_wheel_scroll_lines();
-        self.update_wheel_scroll_chars();
-    }
+        let callbacks = PlatformCallbacks::default();
+        let settings = WindowsPlatformSystemSettings::new();
+        let current_cursor = load_cursor(CursorStyle::Arrow);
 
-    pub(crate) fn update_wheel_scroll_lines(&mut self) {
-        let mut value = c_uint::default();
-        let result = unsafe {
-            SystemParametersInfoW(
-                SPI_GETWHEELSCROLLLINES,
-                0,
-                Some((&mut value) as *mut c_uint as *mut c_void),
-                SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS::default(),
-            )
-        };
-
-        if result.log_err() != None {
-            self.wheel_scroll_lines = value;
-        }
-    }
-
-    pub(crate) fn update_wheel_scroll_chars(&mut self) {
-        let mut value = c_uint::default();
-        let result = unsafe {
-            SystemParametersInfoW(
-                SPI_GETWHEELSCROLLCHARS,
-                0,
-                Some((&mut value) as *mut c_uint as *mut c_void),
-                SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS::default(),
-            )
-        };
-
-        if result.log_err() != None {
-            self.wheel_scroll_chars = value;
+        Self {
+            callbacks,
+            settings,
+            current_cursor,
         }
     }
 }
@@ -166,33 +98,31 @@ impl WindowsPlatform {
             log::info!("Using cosmic text system.");
             Arc::new(CosmicTextSystem::new()) as Arc<dyn PlatformTextSystem>
         };
-        let callbacks = Mutex::new(Callbacks::default());
-        let raw_window_handles = RwLock::new(SmallVec::new());
-        let settings = RefCell::new(WindowsPlatformSystemSettings::new());
         let icon = load_icon().unwrap_or_default();
-        let current_cursor = Cell::new(load_cursor(CursorStyle::Arrow));
-        let inner = Rc::new(WindowsPlatformInner {
+        let state = RefCell::new(WindowsPlatformState::new());
+        let raw_window_handles = RwLock::new(SmallVec::new());
+
+        Self {
+            state,
+            raw_window_handles,
+            icon,
+            main_receiver,
             background_executor,
             foreground_executor,
-            main_receiver,
             text_system,
-            callbacks,
-            raw_window_handles,
             dispatch_event,
-            settings,
-            icon,
-            current_cursor,
-        });
-        Self { inner }
+        }
     }
 
     #[inline]
     fn run_foreground_tasks(&self) {
-        self.inner.run_foreground_tasks();
+        for runnable in self.main_receiver.drain() {
+            runnable.run();
+        }
     }
 
     fn redraw_all(&self) {
-        for handle in self.inner.raw_window_handles.read().iter() {
+        for handle in self.raw_window_handles.read().iter() {
             unsafe {
                 RedrawWindow(
                     *handle,
@@ -203,24 +133,75 @@ impl WindowsPlatform {
             }
         }
     }
+
+    pub fn try_get_windows_inner_from_hwnd(&self, hwnd: HWND) -> Option<Rc<WindowsWindowStatePtr>> {
+        self.raw_window_handles
+            .read()
+            .iter()
+            .find(|entry| *entry == &hwnd)
+            .and_then(|hwnd| try_get_window_inner(*hwnd))
+    }
+
+    #[inline]
+    fn post_message(&self, message: u32, wparam: WPARAM, lparam: LPARAM) {
+        self.raw_window_handles
+            .read()
+            .iter()
+            .for_each(|handle| unsafe {
+                PostMessageW(*handle, message, wparam, lparam).log_err();
+            });
+    }
+
+    fn close_one_window(&self, target_window: HWND) -> bool {
+        let mut lock = self.raw_window_handles.write();
+        let index = lock
+            .iter()
+            .position(|handle| *handle == target_window)
+            .unwrap();
+        lock.remove(index);
+
+        lock.is_empty()
+    }
+
+    fn update_system_settings(&self) {
+        let mut lock = self.state.borrow_mut();
+        // mouse wheel
+        {
+            let (scroll_chars, scroll_lines) = lock.settings.mouse_wheel_settings.update();
+            if let Some(scroll_chars) = scroll_chars {
+                self.post_message(
+                    MOUSE_WHEEL_SETTINGS_CHANGED,
+                    WPARAM(scroll_chars as usize),
+                    LPARAM(MOUSE_WHEEL_SETTINGS_SCROLL_CHARS_CHANGED),
+                );
+            }
+            if let Some(scroll_lines) = scroll_lines {
+                self.post_message(
+                    MOUSE_WHEEL_SETTINGS_CHANGED,
+                    WPARAM(scroll_lines as usize),
+                    LPARAM(MOUSE_WHEEL_SETTINGS_SCROLL_LINES_CHANGED),
+                );
+            }
+        }
+    }
 }
 
 impl Platform for WindowsPlatform {
     fn background_executor(&self) -> BackgroundExecutor {
-        self.inner.background_executor.clone()
+        self.background_executor.clone()
     }
 
     fn foreground_executor(&self) -> ForegroundExecutor {
-        self.inner.foreground_executor.clone()
+        self.foreground_executor.clone()
     }
 
     fn text_system(&self) -> Arc<dyn PlatformTextSystem> {
-        self.inner.text_system.clone()
+        self.text_system.clone()
     }
 
     fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
         on_finish_launching();
-        let dispatch_event = self.inner.dispatch_event.to_raw();
+        let dispatch_event = self.dispatch_event.to_raw();
         let vsync_event = create_event().unwrap();
         let timer_stop_event = create_event().unwrap();
         let raw_timer_stop_event = timer_stop_event.to_raw();
@@ -248,16 +229,20 @@ impl Platform for WindowsPlatform {
                 WAIT_EVENT(2) => {
                     let mut msg = MSG::default();
                     unsafe {
-                        while PeekMessageW(&mut msg, HWND::default(), 0, 0, PM_REMOVE).as_bool() {
-                            if msg.message == WM_QUIT {
-                                break 'a;
-                            }
-                            if msg.message == WM_SETTINGCHANGE {
-                                self.inner.settings.borrow_mut().update_all();
-                                continue;
+                        while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
+                            match msg.message {
+                                WM_QUIT => break 'a,
+                                CLOSE_ONE_WINDOW => {
+                                    if self.close_one_window(HWND(msg.lParam.0)) {
+                                        break 'a;
+                                    }
+                                }
+                                WM_SETTINGCHANGE => self.update_system_settings(),
+                                _ => {
+                                    TranslateMessage(&msg);
+                                    DispatchMessageW(&msg);
+                                }
                             }
-                            TranslateMessage(&msg);
-                            DispatchMessageW(&msg);
                         }
                     }
 
@@ -272,9 +257,8 @@ impl Platform for WindowsPlatform {
         }
         end_vsync_timer(raw_timer_stop_event);
 
-        let mut callbacks = self.inner.callbacks.lock();
-        if let Some(callback) = callbacks.quit.as_mut() {
-            callback()
+        if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
+            callback();
         }
     }
 
@@ -340,17 +324,12 @@ impl Platform for WindowsPlatform {
     }
 
     fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
-        if let Some(display) = WindowsDisplay::primary_monitor() {
-            Some(Rc::new(display) as Rc<dyn PlatformDisplay>)
-        } else {
-            None
-        }
+        WindowsDisplay::primary_monitor().map(|display| Rc::new(display) as Rc<dyn PlatformDisplay>)
     }
 
     fn active_window(&self) -> Option<AnyWindowHandle> {
         let active_window_hwnd = unsafe { GetActiveWindow() };
-        self.inner
-            .try_get_windows_inner_from_hwnd(active_window_hwnd)
+        self.try_get_windows_inner_from_hwnd(active_window_hwnd)
             .map(|inner| inner.handle)
     }
 
@@ -359,7 +338,21 @@ impl Platform for WindowsPlatform {
         handle: AnyWindowHandle,
         options: WindowParams,
     ) -> Box<dyn PlatformWindow> {
-        Box::new(WindowsWindow::new(self.inner.clone(), handle, options))
+        let lock = self.state.borrow();
+        let window = WindowsWindow::new(
+            handle,
+            options,
+            self.icon,
+            self.foreground_executor.clone(),
+            self.main_receiver.clone(),
+            lock.settings.mouse_wheel_settings,
+            lock.current_cursor,
+        );
+        drop(lock);
+        let handle = window.get_raw_handle();
+        self.raw_window_handles.write().push(handle);
+
+        Box::new(window)
     }
 
     // todo(windows)
@@ -379,9 +372,8 @@ impl Platform for WindowsPlatform {
             .detach();
     }
 
-    // todo(windows)
     fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {
-        self.inner.callbacks.lock().open_urls = Some(callback);
+        self.state.borrow_mut().callbacks.open_urls = Some(callback);
     }
 
     fn prompt_for_paths(&self, options: PathPromptOptions) -> Receiver<Option<Vec<PathBuf>>> {
@@ -501,26 +493,26 @@ impl Platform for WindowsPlatform {
     }
 
     fn on_quit(&self, callback: Box<dyn FnMut()>) {
-        self.inner.callbacks.lock().quit = Some(callback);
+        self.state.borrow_mut().callbacks.quit = Some(callback);
     }
 
     fn on_reopen(&self, callback: Box<dyn FnMut()>) {
-        self.inner.callbacks.lock().reopen = Some(callback);
+        self.state.borrow_mut().callbacks.reopen = Some(callback);
     }
 
     // todo(windows)
     fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap) {}
 
     fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>) {
-        self.inner.callbacks.lock().app_menu_action = Some(callback);
+        self.state.borrow_mut().callbacks.app_menu_action = Some(callback);
     }
 
     fn on_will_open_app_menu(&self, callback: Box<dyn FnMut()>) {
-        self.inner.callbacks.lock().will_open_app_menu = Some(callback);
+        self.state.borrow_mut().callbacks.will_open_app_menu = Some(callback);
     }
 
     fn on_validate_app_menu_command(&self, callback: Box<dyn FnMut(&dyn Action) -> bool>) {
-        self.inner.callbacks.lock().validate_app_menu_command = Some(callback);
+        self.state.borrow_mut().callbacks.validate_app_menu_command = Some(callback);
     }
 
     fn os_name(&self) -> &'static str {
@@ -667,7 +659,9 @@ impl Platform for WindowsPlatform {
     }
 
     fn set_cursor_style(&self, style: CursorStyle) {
-        self.inner.current_cursor.set(load_cursor(style));
+        let hcursor = load_cursor(style);
+        self.post_message(CURSOR_STYLE_CHANGED, WPARAM(0), LPARAM(hcursor.0));
+        self.state.borrow_mut().current_cursor = hcursor;
     }
 
     // todo(windows)
@@ -699,10 +693,10 @@ impl Platform for WindowsPlatform {
 
     fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> Task<Result<()>> {
         let mut password = password.to_vec();
-        let mut username = username.encode_utf16().chain(once(0)).collect_vec();
+        let mut username = username.encode_utf16().chain(Some(0)).collect_vec();
         let mut target_name = windows_credentials_target_name(url)
             .encode_utf16()
-            .chain(once(0))
+            .chain(Some(0))
             .collect_vec();
         self.foreground_executor().spawn(async move {
             let credentials = CREDENTIALW {
@@ -724,7 +718,7 @@ impl Platform for WindowsPlatform {
     fn read_credentials(&self, url: &str) -> Task<Result<Option<(String, Vec<u8>)>>> {
         let mut target_name = windows_credentials_target_name(url)
             .encode_utf16()
-            .chain(once(0))
+            .chain(Some(0))
             .collect_vec();
         self.foreground_executor().spawn(async move {
             let mut credentials: *mut CREDENTIALW = std::ptr::null_mut();
@@ -757,7 +751,7 @@ impl Platform for WindowsPlatform {
     fn delete_credentials(&self, url: &str) -> Task<Result<()>> {
         let mut target_name = windows_credentials_target_name(url)
             .encode_utf16()
-            .chain(once(0))
+            .chain(Some(0))
             .collect_vec();
         self.foreground_executor().spawn(async move {
             unsafe { CredDeleteW(PCWSTR::from_raw(target_name.as_ptr()), CRED_TYPE_GENERIC, 0)? };

crates/gpui/src/platform/windows/system_settings.rs 🔗

@@ -0,0 +1,81 @@
+use std::ffi::{c_uint, c_void};
+
+use util::ResultExt;
+use windows::Win32::UI::WindowsAndMessaging::{
+    SystemParametersInfoW, SPI_GETWHEELSCROLLCHARS, SPI_GETWHEELSCROLLLINES,
+    SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS,
+};
+
+/// Windows settings pulled from SystemParametersInfo
+/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfow
+#[derive(Default, Debug)]
+pub(crate) struct WindowsPlatformSystemSettings {
+    pub(crate) mouse_wheel_settings: MouseWheelSettings,
+}
+
+#[derive(Default, Debug, Clone, Copy)]
+pub(crate) struct MouseWheelSettings {
+    /// SEE: SPI_GETWHEELSCROLLCHARS
+    pub(crate) wheel_scroll_chars: u32,
+    /// SEE: SPI_GETWHEELSCROLLLINES
+    pub(crate) wheel_scroll_lines: u32,
+}
+
+impl WindowsPlatformSystemSettings {
+    pub(crate) fn new() -> Self {
+        let mut settings = Self::default();
+        settings.init();
+        settings
+    }
+
+    fn init(&mut self) {
+        self.mouse_wheel_settings.update();
+    }
+}
+
+impl MouseWheelSettings {
+    pub(crate) fn update(&mut self) -> (Option<u32>, Option<u32>) {
+        (
+            self.update_wheel_scroll_chars(),
+            self.update_wheel_scroll_lines(),
+        )
+    }
+
+    fn update_wheel_scroll_chars(&mut self) -> Option<u32> {
+        let mut value = c_uint::default();
+        let result = unsafe {
+            SystemParametersInfoW(
+                SPI_GETWHEELSCROLLCHARS,
+                0,
+                Some((&mut value) as *mut c_uint as *mut c_void),
+                SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS::default(),
+            )
+        };
+
+        if result.log_err() != None && self.wheel_scroll_chars != value {
+            self.wheel_scroll_chars = value;
+            Some(value)
+        } else {
+            None
+        }
+    }
+
+    fn update_wheel_scroll_lines(&mut self) -> Option<u32> {
+        let mut value = c_uint::default();
+        let result = unsafe {
+            SystemParametersInfoW(
+                SPI_GETWHEELSCROLLLINES,
+                0,
+                Some((&mut value) as *mut c_uint as *mut c_void),
+                SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS::default(),
+            )
+        };
+
+        if result.log_err() != None && self.wheel_scroll_lines != value {
+            self.wheel_scroll_lines = value;
+            Some(value)
+        } else {
+            None
+        }
+    }
+}

crates/gpui/src/platform/windows/util.rs 🔗

@@ -74,6 +74,7 @@ pub(crate) unsafe fn set_window_long(
     }
 }
 
+#[derive(Debug, Clone)]
 pub(crate) struct OwnedHandle(HANDLE);
 
 impl OwnedHandle {
@@ -135,3 +136,19 @@ pub(crate) fn load_cursor(style: CursorStyle) -> HCURSOR {
         )
     })
 }
+
+#[inline]
+pub(crate) fn logical_size(physical_size: Size<DevicePixels>, scale_factor: f32) -> Size<Pixels> {
+    Size {
+        width: px(physical_size.width.0 as f32 / scale_factor),
+        height: px(physical_size.height.0 as f32 / scale_factor),
+    }
+}
+
+#[inline]
+pub(crate) fn logical_point(x: f32, y: f32, scale_factor: f32) -> Point<Pixels> {
+    Point {
+        x: px(x / scale_factor),
+        y: px(y / scale_factor),
+    }
+}

crates/gpui/src/platform/windows/window.rs 🔗

@@ -1,8 +1,7 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
 use std::{
-    cell::{Cell, RefCell},
-    iter::once,
+    cell::RefCell,
     num::NonZeroIsize,
     path::PathBuf,
     rc::{Rc, Weak},
@@ -13,197 +12,122 @@ use std::{
 
 use ::util::ResultExt;
 use anyhow::Context;
-use blade_graphics as gpu;
+use async_task::Runnable;
 use futures::channel::oneshot::{self, Receiver};
 use itertools::Itertools;
 use raw_window_handle as rwh;
 use smallvec::SmallVec;
-use std::result::Result;
 use windows::{
     core::*,
     Win32::{
         Foundation::*,
         Graphics::Gdi::*,
         System::{Com::*, LibraryLoader::*, Ole::*, SystemServices::*},
-        UI::{
-            Controls::*,
-            HiDpi::*,
-            Input::{Ime::*, KeyboardAndMouse::*},
-            Shell::*,
-            WindowsAndMessaging::*,
-        },
+        UI::{Controls::*, HiDpi::*, Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
     },
 };
 
-use crate::platform::blade::{BladeRenderer, BladeSurfaceConfig};
+use crate::platform::blade::BladeRenderer;
 use crate::*;
 
-pub(crate) struct WindowsWindowInner {
+pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
+
+pub struct WindowsWindowState {
+    pub origin: Point<DevicePixels>,
+    pub physical_size: Size<DevicePixels>,
+    pub scale_factor: f32,
+
+    pub callbacks: Callbacks,
+    pub input_handler: Option<PlatformInputHandler>,
+
+    pub renderer: BladeRenderer,
+
+    pub click_state: ClickState,
+    pub mouse_wheel_settings: MouseWheelSettings,
+    pub current_cursor: HCURSOR,
+
+    pub display: WindowsDisplay,
+    fullscreen: Option<StyleAndBounds>,
+    hwnd: HWND,
+}
+
+pub(crate) struct WindowsWindowStatePtr {
     hwnd: HWND,
-    origin: Cell<Point<DevicePixels>>,
-    physical_size: Cell<Size<DevicePixels>>,
-    scale_factor: Cell<f32>,
-    input_handler: Cell<Option<PlatformInputHandler>>,
-    renderer: RefCell<BladeRenderer>,
-    callbacks: RefCell<Callbacks>,
-    platform_inner: Rc<WindowsPlatformInner>,
+    pub(crate) state: RefCell<WindowsWindowState>,
     pub(crate) handle: AnyWindowHandle,
-    hide_title_bar: bool,
-    display: RefCell<Rc<WindowsDisplay>>,
-    click_state: RefCell<ClickState>,
-    fullscreen: Cell<Option<StyleAndBounds>>,
+    pub(crate) hide_title_bar: bool,
+    pub(crate) executor: ForegroundExecutor,
+    pub(crate) main_receiver: flume::Receiver<Runnable>,
 }
 
-impl WindowsWindowInner {
+impl WindowsWindowState {
     fn new(
         hwnd: HWND,
-        cs: &CREATESTRUCTW,
-        platform_inner: Rc<WindowsPlatformInner>,
-        handle: AnyWindowHandle,
-        hide_title_bar: bool,
-        display: Rc<WindowsDisplay>,
         transparent: bool,
+        cs: &CREATESTRUCTW,
+        mouse_wheel_settings: MouseWheelSettings,
+        current_cursor: HCURSOR,
+        display: WindowsDisplay,
     ) -> Self {
-        let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
-        let origin = Cell::new(Point {
-            x: DevicePixels(cs.x),
-            y: DevicePixels(cs.y),
-        });
-        let physical_size = Cell::new(Size {
-            width: DevicePixels(cs.cx),
-            height: DevicePixels(cs.cy),
-        });
-        let scale_factor = Cell::new(monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32);
-        let input_handler = Cell::new(None);
-        struct RawWindow {
-            hwnd: isize,
-        }
-        impl rwh::HasWindowHandle for RawWindow {
-            fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
-                Ok(unsafe {
-                    let hwnd = NonZeroIsize::new_unchecked(self.hwnd);
-                    let mut handle = rwh::Win32WindowHandle::new(hwnd);
-                    let hinstance = get_window_long(HWND(self.hwnd), GWLP_HINSTANCE);
-                    handle.hinstance = NonZeroIsize::new(hinstance);
-                    rwh::WindowHandle::borrow_raw(handle.into())
-                })
-            }
-        }
-        impl rwh::HasDisplayHandle for RawWindow {
-            fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
-                let handle = rwh::WindowsDisplayHandle::new();
-                Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
-            }
-        }
+        let origin = point(cs.x.into(), cs.y.into());
+        let physical_size = size(cs.cx.into(), cs.cy.into());
+        let scale_factor = {
+            let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
+            monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32
+        };
+        let renderer = windows_renderer::windows_renderer(hwnd, transparent);
+        let callbacks = Callbacks::default();
+        let input_handler = None;
+        let click_state = ClickState::new();
+        let fullscreen = None;
 
-        let raw = RawWindow { hwnd: hwnd.0 };
-        let gpu = Arc::new(
-            unsafe {
-                gpu::Context::init_windowed(
-                    &raw,
-                    gpu::ContextDesc {
-                        validation: false,
-                        capture: false,
-                        overlay: false,
-                    },
-                )
-            }
-            .unwrap(),
-        );
-        let config = BladeSurfaceConfig {
-            size: gpu::Extent::default(),
-            transparent,
-        };
-        let renderer = RefCell::new(BladeRenderer::new(gpu, config));
-        let callbacks = RefCell::new(Callbacks::default());
-        let display = RefCell::new(display);
-        let click_state = RefCell::new(ClickState::new());
-        let fullscreen = Cell::new(None);
         Self {
-            hwnd,
             origin,
             physical_size,
             scale_factor,
+            callbacks,
             input_handler,
             renderer,
-            callbacks,
-            platform_inner,
-            handle,
-            hide_title_bar,
-            display,
             click_state,
+            mouse_wheel_settings,
+            current_cursor,
+            display,
             fullscreen,
+            hwnd,
         }
     }
 
-    fn is_maximized(&self) -> bool {
-        !self.is_fullscreen() && unsafe { IsZoomed(self.hwnd) }.as_bool()
+    #[inline]
+    pub(crate) fn is_fullscreen(&self) -> bool {
+        self.fullscreen.is_some()
     }
 
-    fn is_minimized(&self) -> bool {
-        unsafe { IsIconic(self.hwnd) }.as_bool()
+    pub(crate) fn is_maximized(&self) -> bool {
+        !self.is_fullscreen() && unsafe { IsZoomed(self.hwnd) }.as_bool()
     }
 
-    fn is_fullscreen(&self) -> bool {
-        let fullscreen = self.fullscreen.take();
-        let is_fullscreen = fullscreen.is_some();
-        self.fullscreen.set(fullscreen);
-        is_fullscreen
-    }
-
-    async fn toggle_fullscreen(self: Rc<Self>) {
-        let StyleAndBounds {
-            style,
-            x,
-            y,
-            cx,
-            cy,
-        } = if let Some(state) = self.fullscreen.take() {
-            state
-        } else {
-            let style = WINDOW_STYLE(unsafe { get_window_long(self.hwnd, GWL_STYLE) } as _);
-            let mut rc = RECT::default();
-            unsafe { GetWindowRect(self.hwnd, &mut rc) }.log_err();
-            self.fullscreen.set(Some(StyleAndBounds {
-                style,
-                x: rc.left,
-                y: rc.top,
-                cx: rc.right - rc.left,
-                cy: rc.bottom - rc.top,
-            }));
-            let style = style
-                & !(WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CAPTION);
-            let bounds = self.display.borrow().clone().bounds();
-            StyleAndBounds {
-                style,
-                x: bounds.left().0,
-                y: bounds.top().0,
-                cx: bounds.size.width.0,
-                cy: bounds.size.height.0,
-            }
-        };
-        unsafe { set_window_long(self.hwnd, GWL_STYLE, style.0 as isize) };
-        unsafe {
-            SetWindowPos(
-                self.hwnd,
-                HWND::default(),
-                x,
-                y,
-                cx,
-                cy,
-                SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER,
-            )
+    fn bounds(&self) -> Bounds<DevicePixels> {
+        Bounds {
+            origin: self.origin,
+            size: self.physical_size,
         }
-        .log_err();
     }
 
-    pub(crate) fn title_bar_padding(&self) -> Pixels {
+    /// get the logical size of the app's drawable area.
+    ///
+    /// Currently, GPUI uses logical size of the app to handle mouse interactions (such as
+    /// whether the mouse collides with other elements of GPUI).
+    fn content_size(&self) -> Size<Pixels> {
+        logical_size(self.physical_size, self.scale_factor)
+    }
+
+    fn title_bar_padding(&self) -> Pixels {
         // using USER_DEFAULT_SCREEN_DPI because GPUI handles the scale with the scale factor
         let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, USER_DEFAULT_SCREEN_DPI) };
         px(padding as f32)
     }
 
-    pub(crate) fn title_bar_top_offset(&self) -> Pixels {
+    fn title_bar_top_offset(&self) -> Pixels {
         if self.is_maximized() {
             self.title_bar_padding() * 2
         } else {
@@ -211,7 +135,7 @@ impl WindowsWindowInner {
         }
     }
 
-    pub(crate) fn title_bar_height(&self) -> Pixels {
+    fn title_bar_height(&self) -> Pixels {
         // todo(windows) this is hard set to match the ui title bar
         //               in the future the ui title bar component will report the size
         px(32.) + self.title_bar_top_offset()
@@ -223,1032 +147,76 @@ impl WindowsWindowInner {
         px(36.)
     }
 
-    fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
+    pub(crate) fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
         let height = self.title_bar_height();
         let mut rect = RECT::default();
         unsafe { GetClientRect(self.hwnd, &mut rect) }?;
-        rect.bottom = rect.top + ((height.0 * self.scale_factor.get()).round() as i32);
+        rect.bottom = rect.top + ((height.0 * self.scale_factor).round() as i32);
         Ok(rect)
     }
+}
 
-    fn is_virtual_key_pressed(&self, vkey: VIRTUAL_KEY) -> bool {
-        unsafe { GetKeyState(vkey.0 as i32) < 0 }
-    }
-
-    fn current_modifiers(&self) -> Modifiers {
-        Modifiers {
-            control: self.is_virtual_key_pressed(VK_CONTROL),
-            alt: self.is_virtual_key_pressed(VK_MENU),
-            shift: self.is_virtual_key_pressed(VK_SHIFT),
-            platform: self.is_virtual_key_pressed(VK_LWIN) || self.is_virtual_key_pressed(VK_RWIN),
-            function: false,
-        }
-    }
-
-    /// mark window client rect to be re-drawn
-    /// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-invalidaterect
-    pub(crate) fn invalidate_client_area(&self) {
-        unsafe { InvalidateRect(self.hwnd, None, FALSE) };
-    }
-
-    fn handle_msg(&self, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
-        let handled = match msg {
-            WM_ACTIVATE => self.handle_activate_msg(wparam),
-            WM_CREATE => self.handle_create_msg(lparam),
-            WM_MOVE => self.handle_move_msg(lparam),
-            WM_SIZE => self.handle_size_msg(lparam),
-            WM_ENTERSIZEMOVE | WM_ENTERMENULOOP => self.handle_size_move_loop(),
-            WM_EXITSIZEMOVE | WM_EXITMENULOOP => self.handle_size_move_loop_exit(),
-            WM_TIMER => self.handle_timer_msg(wparam),
-            WM_NCCALCSIZE => self.handle_calc_client_size(wparam, lparam),
-            WM_DPICHANGED => self.handle_dpi_changed_msg(wparam, lparam),
-            WM_NCHITTEST => self.handle_hit_test_msg(msg, wparam, lparam),
-            WM_PAINT => self.handle_paint_msg(),
-            WM_CLOSE => self.handle_close_msg(),
-            WM_DESTROY => self.handle_destroy_msg(),
-            WM_MOUSEMOVE => self.handle_mouse_move_msg(lparam, wparam),
-            WM_NCMOUSEMOVE => self.handle_nc_mouse_move_msg(lparam),
-            WM_NCLBUTTONDOWN => self.handle_nc_mouse_down_msg(MouseButton::Left, wparam, lparam),
-            WM_NCRBUTTONDOWN => self.handle_nc_mouse_down_msg(MouseButton::Right, wparam, lparam),
-            WM_NCMBUTTONDOWN => self.handle_nc_mouse_down_msg(MouseButton::Middle, wparam, lparam),
-            WM_NCLBUTTONUP => self.handle_nc_mouse_up_msg(MouseButton::Left, wparam, lparam),
-            WM_NCRBUTTONUP => self.handle_nc_mouse_up_msg(MouseButton::Right, wparam, lparam),
-            WM_NCMBUTTONUP => self.handle_nc_mouse_up_msg(MouseButton::Middle, wparam, lparam),
-            WM_LBUTTONDOWN => self.handle_mouse_down_msg(MouseButton::Left, lparam),
-            WM_RBUTTONDOWN => self.handle_mouse_down_msg(MouseButton::Right, lparam),
-            WM_MBUTTONDOWN => self.handle_mouse_down_msg(MouseButton::Middle, lparam),
-            WM_XBUTTONDOWN => self.handle_xbutton_msg(wparam, lparam, Self::handle_mouse_down_msg),
-            WM_LBUTTONUP => self.handle_mouse_up_msg(MouseButton::Left, lparam),
-            WM_RBUTTONUP => self.handle_mouse_up_msg(MouseButton::Right, lparam),
-            WM_MBUTTONUP => self.handle_mouse_up_msg(MouseButton::Middle, lparam),
-            WM_XBUTTONUP => self.handle_xbutton_msg(wparam, lparam, Self::handle_mouse_up_msg),
-            WM_MOUSEWHEEL => self.handle_mouse_wheel_msg(wparam, lparam),
-            WM_MOUSEHWHEEL => self.handle_mouse_horizontal_wheel_msg(wparam, lparam),
-            WM_SYSKEYDOWN => self.handle_syskeydown_msg(wparam, lparam),
-            WM_SYSKEYUP => self.handle_syskeyup_msg(wparam),
-            WM_KEYDOWN => self.handle_keydown_msg(msg, wparam, lparam),
-            WM_KEYUP => self.handle_keyup_msg(msg, wparam),
-            WM_CHAR => self.handle_char_msg(msg, wparam, lparam),
-            WM_IME_STARTCOMPOSITION => self.handle_ime_position(),
-            WM_IME_COMPOSITION => self.handle_ime_composition(lparam),
-            WM_SETCURSOR => self.handle_set_cursor(lparam),
-            _ => None,
-        };
-        if let Some(n) = handled {
-            LRESULT(n)
-        } else {
-            unsafe { DefWindowProcW(self.hwnd, msg, wparam, lparam) }
-        }
-    }
-
-    fn handle_move_msg(&self, lparam: LPARAM) -> Option<isize> {
-        let x = lparam.signed_loword() as i32;
-        let y = lparam.signed_hiword() as i32;
-        self.origin.set(Point {
-            x: DevicePixels(x),
-            y: DevicePixels(y),
-        });
-        let size = self.physical_size.get();
-        let center_x = x + size.width.0 / 2;
-        let center_y = y + size.height.0 / 2;
-        let monitor_bounds = self.display.borrow().bounds();
-        if center_x < monitor_bounds.left().0
-            || center_x > monitor_bounds.right().0
-            || center_y < monitor_bounds.top().0
-            || center_y > monitor_bounds.bottom().0
-        {
-            // center of the window may have moved to another monitor
-            let monitor = unsafe { MonitorFromWindow(self.hwnd, MONITOR_DEFAULTTONULL) };
-            if !monitor.is_invalid() && self.display.borrow().handle != monitor {
-                // we will get the same monitor if we only have one
-                (*self.display.borrow_mut()) = Rc::new(WindowsDisplay::new_with_handle(monitor));
-            }
-        }
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.moved.as_mut() {
-            callback()
-        }
-        Some(0)
-    }
-
-    fn handle_size_msg(&self, lparam: LPARAM) -> Option<isize> {
-        let width = lparam.loword().max(1) as i32;
-        let height = lparam.hiword().max(1) as i32;
-        let scale_factor = self.scale_factor.get();
-        let new_physical_size = Size {
-            width: DevicePixels(width),
-            height: DevicePixels(height),
-        };
-        self.physical_size.set(new_physical_size);
-        self.renderer.borrow_mut().update_drawable_size(Size {
-            width: width as f64,
-            height: height as f64,
-        });
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.resize.as_mut() {
-            let logical_size = logical_size(new_physical_size, scale_factor);
-            callback(logical_size, scale_factor);
-        }
-        Some(0)
-    }
-
-    fn handle_size_move_loop(&self) -> Option<isize> {
-        unsafe {
-            let ret = SetTimer(self.hwnd, SIZE_MOVE_LOOP_TIMER_ID, USER_TIMER_MINIMUM, None);
-            if ret == 0 {
-                log::error!(
-                    "unable to create timer: {}",
-                    std::io::Error::last_os_error()
-                );
-            }
-        }
-        None
-    }
-
-    fn handle_size_move_loop_exit(&self) -> Option<isize> {
-        unsafe {
-            KillTimer(self.hwnd, SIZE_MOVE_LOOP_TIMER_ID).log_err();
-        }
-        None
-    }
-
-    fn handle_timer_msg(&self, wparam: WPARAM) -> Option<isize> {
-        if wparam.0 == SIZE_MOVE_LOOP_TIMER_ID {
-            self.platform_inner.run_foreground_tasks();
-            self.handle_paint_msg();
-            return Some(0);
-        }
-        None
-    }
-
-    fn handle_paint_msg(&self) -> Option<isize> {
-        let mut paint_struct = PAINTSTRUCT::default();
-        let _hdc = unsafe { BeginPaint(self.hwnd, &mut paint_struct) };
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(request_frame) = callbacks.request_frame.as_mut() {
-            request_frame();
-        }
-        unsafe { EndPaint(self.hwnd, &paint_struct) };
-        Some(0)
-    }
-
-    fn handle_close_msg(&self) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.should_close.as_mut() {
-            if callback() {
-                return Some(0);
-            }
-        }
-        None
-    }
-
-    fn handle_destroy_msg(&self) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.close.take() {
-            callback()
-        }
-        let index = self
-            .platform_inner
-            .raw_window_handles
-            .read()
-            .iter()
-            .position(|handle| *handle == self.hwnd)
-            .unwrap();
-        self.platform_inner.raw_window_handles.write().remove(index);
-        if self.platform_inner.raw_window_handles.read().is_empty() {
-            self.platform_inner
-                .foreground_executor
-                .spawn(async {
-                    unsafe { PostQuitMessage(0) };
-                })
-                .detach();
-        }
-        Some(1)
-    }
-
-    fn handle_mouse_move_msg(&self, lparam: LPARAM, wparam: WPARAM) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let pressed_button = match MODIFIERKEYS_FLAGS(wparam.loword() as u32) {
-                flags if flags.contains(MK_LBUTTON) => Some(MouseButton::Left),
-                flags if flags.contains(MK_RBUTTON) => Some(MouseButton::Right),
-                flags if flags.contains(MK_MBUTTON) => Some(MouseButton::Middle),
-                flags if flags.contains(MK_XBUTTON1) => {
-                    Some(MouseButton::Navigate(NavigationDirection::Back))
-                }
-                flags if flags.contains(MK_XBUTTON2) => {
-                    Some(MouseButton::Navigate(NavigationDirection::Forward))
-                }
-                _ => None,
-            };
-            let x = lparam.signed_loword() as f32;
-            let y = lparam.signed_hiword() as f32;
-            let scale_factor = self.scale_factor.get();
-            let event = MouseMoveEvent {
-                position: logical_point(x, y, scale_factor),
-                pressed_button,
-                modifiers: self.current_modifiers(),
-            };
-            if callback(PlatformInput::MouseMove(event)).default_prevented {
-                return Some(0);
-            }
-        }
-        Some(1)
-    }
-
-    fn parse_syskeydown_msg_keystroke(&self, wparam: WPARAM) -> Option<Keystroke> {
-        let modifiers = self.current_modifiers();
-        if !modifiers.alt {
-            // on Windows, F10 can trigger this event, not just the alt key
-            // and we just don't care about F10
-            return None;
-        }
-
-        let vk_code = wparam.loword();
-        let basic_key = basic_vkcode_to_string(vk_code, modifiers);
-        if basic_key.is_some() {
-            return basic_key;
-        }
-
-        let key = match VIRTUAL_KEY(vk_code) {
-            VK_BACK => Some("backspace"),
-            VK_RETURN => Some("enter"),
-            VK_TAB => Some("tab"),
-            VK_UP => Some("up"),
-            VK_DOWN => Some("down"),
-            VK_RIGHT => Some("right"),
-            VK_LEFT => Some("left"),
-            VK_HOME => Some("home"),
-            VK_END => Some("end"),
-            VK_PRIOR => Some("pageup"),
-            VK_NEXT => Some("pagedown"),
-            VK_ESCAPE => Some("escape"),
-            VK_INSERT => Some("insert"),
-            _ => None,
-        };
-
-        if let Some(key) = key {
-            Some(Keystroke {
-                modifiers,
-                key: key.to_string(),
-                ime_key: None,
-            })
-        } else {
-            None
-        }
-    }
-
-    fn parse_keydown_msg_keystroke(&self, wparam: WPARAM) -> Option<Keystroke> {
-        let vk_code = wparam.loword();
-
-        let modifiers = self.current_modifiers();
-        if modifiers.control || modifiers.alt {
-            let basic_key = basic_vkcode_to_string(vk_code, modifiers);
-            if basic_key.is_some() {
-                return basic_key;
-            }
-        }
-
-        if vk_code >= VK_F1.0 && vk_code <= VK_F24.0 {
-            let offset = vk_code - VK_F1.0;
-            return Some(Keystroke {
-                modifiers,
-                key: format!("f{}", offset + 1),
-                ime_key: None,
-            });
-        }
-
-        let key = match VIRTUAL_KEY(vk_code) {
-            VK_BACK => Some("backspace"),
-            VK_RETURN => Some("enter"),
-            VK_TAB => Some("tab"),
-            VK_UP => Some("up"),
-            VK_DOWN => Some("down"),
-            VK_RIGHT => Some("right"),
-            VK_LEFT => Some("left"),
-            VK_HOME => Some("home"),
-            VK_END => Some("end"),
-            VK_PRIOR => Some("pageup"),
-            VK_NEXT => Some("pagedown"),
-            VK_ESCAPE => Some("escape"),
-            VK_INSERT => Some("insert"),
-            VK_DELETE => Some("delete"),
-            _ => None,
-        };
-
-        if let Some(key) = key {
-            Some(Keystroke {
-                modifiers,
-                key: key.to_string(),
-                ime_key: None,
-            })
-        } else {
-            None
-        }
-    }
-
-    fn parse_char_msg_keystroke(&self, wparam: WPARAM) -> Option<Keystroke> {
-        let src = [wparam.0 as u16];
-        let Ok(first_char) = char::decode_utf16(src).collect::<Vec<_>>()[0] else {
-            return None;
-        };
-        if first_char.is_control() {
-            None
-        } else {
-            let mut modifiers = self.current_modifiers();
-            // for characters that use 'shift' to type it is expected that the
-            // shift is not reported if the uppercase/lowercase are the same and instead only the key is reported
-            if first_char.to_lowercase().to_string() == first_char.to_uppercase().to_string() {
-                modifiers.shift = false;
-            }
-            let key = match first_char {
-                ' ' => "space".to_string(),
-                first_char => first_char.to_lowercase().to_string(),
-            };
-            Some(Keystroke {
-                modifiers,
-                key,
-                ime_key: Some(first_char.to_string()),
-            })
-        }
-    }
-
-    fn handle_syskeydown_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        // we need to call `DefWindowProcW`, or we will lose the system-wide `Alt+F4`, `Alt+{other keys}`
-        // shortcuts.
-        let Some(keystroke) = self.parse_syskeydown_msg_keystroke(wparam) else {
-            return None;
-        };
-        let Some(ref mut func) = self.callbacks.borrow_mut().input else {
-            return None;
-        };
-        let event = KeyDownEvent {
-            keystroke,
-            is_held: lparam.0 & (0x1 << 30) > 0,
-        };
-        if func(PlatformInput::KeyDown(event)).default_prevented {
-            self.invalidate_client_area();
-            return Some(0);
-        }
-        None
-    }
-
-    fn handle_syskeyup_msg(&self, wparam: WPARAM) -> Option<isize> {
-        // we need to call `DefWindowProcW`, or we will lose the system-wide `Alt+F4`, `Alt+{other keys}`
-        // shortcuts.
-        let Some(keystroke) = self.parse_syskeydown_msg_keystroke(wparam) else {
-            return None;
-        };
-        let Some(ref mut func) = self.callbacks.borrow_mut().input else {
-            return None;
-        };
-        let event = KeyUpEvent { keystroke };
-        if func(PlatformInput::KeyUp(event)).default_prevented {
-            self.invalidate_client_area();
-            return Some(0);
-        }
-        None
-    }
-
-    fn handle_keydown_msg(&self, _msg: u32, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let Some(keystroke) = self.parse_keydown_msg_keystroke(wparam) else {
-            return Some(1);
-        };
-        let Some(ref mut func) = self.callbacks.borrow_mut().input else {
-            return Some(1);
-        };
-        let event = KeyDownEvent {
-            keystroke,
-            is_held: lparam.0 & (0x1 << 30) > 0,
-        };
-        if func(PlatformInput::KeyDown(event)).default_prevented {
-            self.invalidate_client_area();
-            return Some(0);
-        }
-        Some(1)
-    }
-
-    fn handle_keyup_msg(&self, _msg: u32, wparam: WPARAM) -> Option<isize> {
-        let Some(keystroke) = self.parse_keydown_msg_keystroke(wparam) else {
-            return Some(1);
-        };
-        let Some(ref mut func) = self.callbacks.borrow_mut().input else {
-            return Some(1);
-        };
-        let event = KeyUpEvent { keystroke };
-        if func(PlatformInput::KeyUp(event)).default_prevented {
-            self.invalidate_client_area();
-            return Some(0);
-        }
-        Some(1)
-    }
-
-    fn handle_char_msg(&self, _msg: u32, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let Some(keystroke) = self.parse_char_msg_keystroke(wparam) else {
-            return Some(1);
-        };
-        let mut callbacks = self.callbacks.borrow_mut();
-        let Some(ref mut func) = callbacks.input else {
-            return Some(1);
-        };
-        let ime_key = keystroke.ime_key.clone();
-        let event = KeyDownEvent {
-            keystroke,
-            is_held: lparam.0 & (0x1 << 30) > 0,
-        };
-
-        let dispatch_event_result = func(PlatformInput::KeyDown(event));
-        if dispatch_event_result.default_prevented || !dispatch_event_result.propagate {
-            self.invalidate_client_area();
-            return Some(0);
-        }
-        drop(callbacks);
-        let Some(ime_char) = ime_key else {
-            return Some(1);
-        };
-        let Some(mut input_handler) = self.input_handler.take() else {
-            return Some(1);
-        };
-        input_handler.replace_text_in_range(None, &ime_char);
-        self.input_handler.set(Some(input_handler));
-        self.invalidate_client_area();
-        Some(0)
-    }
-
-    fn handle_mouse_down_msg(&self, button: MouseButton, lparam: LPARAM) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let x = lparam.signed_loword() as f32;
-            let y = lparam.signed_hiword() as f32;
-            let physical_point = point(DevicePixels(x as i32), DevicePixels(y as i32));
-            let click_count = self.click_state.borrow_mut().update(button, physical_point);
-            let scale_factor = self.scale_factor.get();
-            let event = MouseDownEvent {
-                button,
-                position: logical_point(x, y, scale_factor),
-                modifiers: self.current_modifiers(),
-                click_count,
-                first_mouse: false,
-            };
-            if callback(PlatformInput::MouseDown(event)).default_prevented {
-                return Some(0);
-            }
-        }
-        Some(1)
-    }
-
-    fn handle_mouse_up_msg(&self, button: MouseButton, lparam: LPARAM) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let x = lparam.signed_loword() as f32;
-            let y = lparam.signed_hiword() as f32;
-            let click_count = self.click_state.borrow().current_count;
-            let scale_factor = self.scale_factor.get();
-            let event = MouseUpEvent {
-                button,
-                position: logical_point(x, y, scale_factor),
-                modifiers: self.current_modifiers(),
-                click_count,
-            };
-            if callback(PlatformInput::MouseUp(event)).default_prevented {
-                return Some(0);
-            }
-        }
-        Some(1)
-    }
-
-    fn handle_xbutton_msg(
-        &self,
-        wparam: WPARAM,
-        lparam: LPARAM,
-        handler: impl Fn(&Self, MouseButton, LPARAM) -> Option<isize>,
-    ) -> Option<isize> {
-        let nav_dir = match wparam.hiword() {
-            XBUTTON1 => NavigationDirection::Back,
-            XBUTTON2 => NavigationDirection::Forward,
-            _ => return Some(1),
-        };
-        handler(self, MouseButton::Navigate(nav_dir), lparam)
-    }
-
-    fn handle_mouse_wheel_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let wheel_distance = (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32)
-                * self.platform_inner.settings.borrow().wheel_scroll_lines as f32;
-            let mut cursor_point = POINT {
-                x: lparam.signed_loword().into(),
-                y: lparam.signed_hiword().into(),
-            };
-            unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
-            let scale_factor = self.scale_factor.get();
-            let event = crate::ScrollWheelEvent {
-                position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
-                delta: ScrollDelta::Lines(Point {
-                    x: 0.0,
-                    y: wheel_distance,
-                }),
-                modifiers: self.current_modifiers(),
-                touch_phase: TouchPhase::Moved,
-            };
-            callback(PlatformInput::ScrollWheel(event));
-            return Some(0);
-        }
-        Some(1)
-    }
-
-    fn handle_mouse_horizontal_wheel_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let wheel_distance = (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32)
-                * self.platform_inner.settings.borrow().wheel_scroll_chars as f32;
-            let mut cursor_point = POINT {
-                x: lparam.signed_loword().into(),
-                y: lparam.signed_hiword().into(),
-            };
-            unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
-            let scale_factor = self.scale_factor.get();
-            let event = crate::ScrollWheelEvent {
-                position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
-                delta: ScrollDelta::Lines(Point {
-                    x: wheel_distance,
-                    y: 0.0,
-                }),
-                modifiers: self.current_modifiers(),
-                touch_phase: TouchPhase::Moved,
-            };
-            if callback(PlatformInput::ScrollWheel(event)).default_prevented {
-                return Some(0);
-            }
-        }
-        Some(1)
-    }
-
-    fn handle_ime_position(&self) -> Option<isize> {
-        unsafe {
-            let ctx = ImmGetContext(self.hwnd);
-            let Some(mut input_handler) = self.input_handler.take() else {
-                return Some(1);
-            };
-            let caret_range = input_handler.selected_text_range().unwrap_or_default();
-            let caret_position = input_handler.bounds_for_range(caret_range).unwrap();
-            self.input_handler.set(Some(input_handler));
-            let scale_factor = self.scale_factor.get();
-            let config = CANDIDATEFORM {
-                dwStyle: CFS_CANDIDATEPOS,
-                // logical to physical
-                ptCurrentPos: POINT {
-                    x: (caret_position.origin.x.0 * scale_factor) as i32,
-                    y: (caret_position.origin.y.0 * scale_factor) as i32
-                        + ((caret_position.size.height.0 * scale_factor) as i32 / 2),
-                },
-                ..Default::default()
-            };
-            ImmSetCandidateWindow(ctx, &config as _);
-            ImmReleaseContext(self.hwnd, ctx);
-            Some(0)
-        }
-    }
-
-    fn parse_ime_compostion_string(&self) -> Option<(String, usize)> {
-        unsafe {
-            let ctx = ImmGetContext(self.hwnd);
-            let string_len = ImmGetCompositionStringW(ctx, GCS_COMPSTR, None, 0);
-            let result = if string_len >= 0 {
-                let mut buffer = vec![0u8; string_len as usize + 2];
-                ImmGetCompositionStringW(
-                    ctx,
-                    GCS_COMPSTR,
-                    Some(buffer.as_mut_ptr() as _),
-                    string_len as _,
-                );
-                let wstring = std::slice::from_raw_parts::<u16>(
-                    buffer.as_mut_ptr().cast::<u16>(),
-                    string_len as usize / 2,
-                );
-                let string = String::from_utf16_lossy(wstring);
-                Some((string, string_len as usize / 2))
-            } else {
-                None
-            };
-            ImmReleaseContext(self.hwnd, ctx);
-            result
-        }
-    }
-
-    fn retrieve_composition_cursor_position(&self) -> usize {
-        unsafe {
-            let ctx = ImmGetContext(self.hwnd);
-            let ret = ImmGetCompositionStringW(ctx, GCS_CURSORPOS, None, 0);
-            ImmReleaseContext(self.hwnd, ctx);
-            ret as usize
-        }
-    }
-
-    fn parse_ime_compostion_result(&self) -> Option<String> {
-        unsafe {
-            let ctx = ImmGetContext(self.hwnd);
-            let string_len = ImmGetCompositionStringW(ctx, GCS_RESULTSTR, None, 0);
-            let result = if string_len >= 0 {
-                let mut buffer = vec![0u8; string_len as usize + 2];
-                ImmGetCompositionStringW(
-                    ctx,
-                    GCS_RESULTSTR,
-                    Some(buffer.as_mut_ptr() as _),
-                    string_len as _,
-                );
-                let wstring = std::slice::from_raw_parts::<u16>(
-                    buffer.as_mut_ptr().cast::<u16>(),
-                    string_len as usize / 2,
-                );
-                let string = String::from_utf16_lossy(wstring);
-                Some(string)
-            } else {
-                None
-            };
-            ImmReleaseContext(self.hwnd, ctx);
-            result
-        }
-    }
-
-    fn handle_ime_composition(&self, lparam: LPARAM) -> Option<isize> {
-        let mut ime_input = None;
-        if lparam.0 as u32 & GCS_COMPSTR.0 > 0 {
-            let Some((string, string_len)) = self.parse_ime_compostion_string() else {
-                return None;
-            };
-            let Some(mut input_handler) = self.input_handler.take() else {
-                return None;
-            };
-            input_handler.replace_and_mark_text_in_range(
-                None,
-                string.as_str(),
-                Some(0..string_len),
-            );
-            self.input_handler.set(Some(input_handler));
-            ime_input = Some(string);
-        }
-        if lparam.0 as u32 & GCS_CURSORPOS.0 > 0 {
-            let Some(ref comp_string) = ime_input else {
-                return None;
-            };
-            let caret_pos = self.retrieve_composition_cursor_position();
-            let Some(mut input_handler) = self.input_handler.take() else {
-                return None;
-            };
-            input_handler.replace_and_mark_text_in_range(None, comp_string, Some(0..caret_pos));
-            self.input_handler.set(Some(input_handler));
-        }
-        if lparam.0 as u32 & GCS_RESULTSTR.0 > 0 {
-            let Some(comp_result) = self.parse_ime_compostion_result() else {
-                return None;
-            };
-            let Some(mut input_handler) = self.input_handler.take() else {
-                return Some(1);
-            };
-            input_handler.replace_text_in_range(None, &comp_result);
-            self.input_handler.set(Some(input_handler));
-            self.invalidate_client_area();
-            return Some(0);
-        }
-        // currently, we don't care other stuff
-        None
-    }
-
-    fn handle_drag_drop(&self, input: PlatformInput) {
-        let mut callbacks = self.callbacks.borrow_mut();
-        let Some(ref mut func) = callbacks.input else {
-            return;
-        };
-        func(input);
-    }
-
-    /// SEE: https://learn.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize
-    fn handle_calc_client_size(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        if !self.hide_title_bar || self.is_fullscreen() {
-            return None;
-        }
-
-        if wparam.0 == 0 {
-            return None;
-        }
-
-        let dpi = unsafe { GetDpiForWindow(self.hwnd) };
-
-        let frame_x = unsafe { GetSystemMetricsForDpi(SM_CXFRAME, dpi) };
-        let frame_y = unsafe { GetSystemMetricsForDpi(SM_CYFRAME, dpi) };
-        let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) };
-
-        // wparam is TRUE so lparam points to an NCCALCSIZE_PARAMS structure
-        let mut params = lparam.0 as *mut NCCALCSIZE_PARAMS;
-        let mut requested_client_rect = unsafe { &mut ((*params).rgrc) };
-
-        requested_client_rect[0].right -= frame_x + padding;
-        requested_client_rect[0].left += frame_x + padding;
-        requested_client_rect[0].bottom -= frame_y + padding;
-
-        Some(0)
-    }
-
-    fn handle_activate_msg(&self, wparam: WPARAM) -> Option<isize> {
-        if self.hide_title_bar {
-            if let Some(titlebar_rect) = self.get_titlebar_rect().log_err() {
-                unsafe { InvalidateRect(self.hwnd, Some(&titlebar_rect), FALSE) };
-            }
-        }
-        let activated = wparam.loword() > 0;
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(mut cb) = callbacks.active_status_change.as_mut() {
-            cb(activated);
-        }
-        None
-    }
-
-    fn handle_create_msg(&self, _lparam: LPARAM) -> Option<isize> {
-        let mut size_rect = RECT::default();
-        unsafe { GetWindowRect(self.hwnd, &mut size_rect).log_err() };
-
-        let width = size_rect.right - size_rect.left;
-        let height = size_rect.bottom - size_rect.top;
-
-        self.physical_size.set(Size {
-            width: DevicePixels(width),
-            height: DevicePixels(height),
-        });
-
-        if self.hide_title_bar {
-            // Inform the application of the frame change to force redrawing with the new
-            // client area that is extended into the title bar
-            unsafe {
-                SetWindowPos(
-                    self.hwnd,
-                    HWND::default(),
-                    size_rect.left,
-                    size_rect.top,
-                    width,
-                    height,
-                    SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE,
-                )
-                .log_err()
-            };
-        }
-
-        Some(0)
-    }
-
-    fn handle_dpi_changed_msg(&self, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        let new_dpi = wparam.loword() as f32;
-        let scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
-        self.scale_factor.set(scale_factor);
-        let rect = unsafe { &*(lparam.0 as *const RECT) };
-        let width = rect.right - rect.left;
-        let height = rect.bottom - rect.top;
-        // this will emit `WM_SIZE` and `WM_MOVE` right here
-        // even before this function returns
-        // the new size is handled in `WM_SIZE`
-        unsafe {
-            SetWindowPos(
-                self.hwnd,
-                None,
-                rect.left,
-                rect.top,
-                width,
-                height,
-                SWP_NOZORDER | SWP_NOACTIVATE,
-            )
-            .context("unable to set window position after dpi has changed")
-            .log_err();
-        }
-        self.invalidate_client_area();
-        Some(0)
-    }
-
-    fn handle_hit_test_msg(&self, msg: u32, wparam: WPARAM, lparam: LPARAM) -> Option<isize> {
-        if !self.hide_title_bar {
-            return None;
-        }
-
-        // default handler for resize areas
-        let hit = unsafe { DefWindowProcW(self.hwnd, msg, wparam, lparam) };
-        if matches!(
-            hit.0 as u32,
-            HTNOWHERE
-                | HTRIGHT
-                | HTLEFT
-                | HTTOPLEFT
-                | HTTOP
-                | HTTOPRIGHT
-                | HTBOTTOMRIGHT
-                | HTBOTTOM
-                | HTBOTTOMLEFT
-        ) {
-            return Some(hit.0);
-        }
-
-        if self.is_fullscreen() {
-            return Some(HTCLIENT as _);
-        }
-
-        let dpi = unsafe { GetDpiForWindow(self.hwnd) };
-        let frame_y = unsafe { GetSystemMetricsForDpi(SM_CYFRAME, dpi) };
-        let padding = unsafe { GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) };
-
-        let mut cursor_point = POINT {
-            x: lparam.signed_loword().into(),
-            y: lparam.signed_hiword().into(),
-        };
-        unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
-        if cursor_point.y > 0 && cursor_point.y < frame_y + padding {
-            return Some(HTTOP as _);
-        }
-
-        let titlebar_rect = self.get_titlebar_rect();
-        if let Ok(titlebar_rect) = titlebar_rect {
-            if cursor_point.y < titlebar_rect.bottom {
-                let caption_btn_width =
-                    (self.caption_button_width().0 * self.scale_factor.get()) as i32;
-                if cursor_point.x >= titlebar_rect.right - caption_btn_width {
-                    return Some(HTCLOSE as _);
-                } else if cursor_point.x >= titlebar_rect.right - caption_btn_width * 2 {
-                    return Some(HTMAXBUTTON as _);
-                } else if cursor_point.x >= titlebar_rect.right - caption_btn_width * 3 {
-                    return Some(HTMINBUTTON as _);
-                }
-
-                return Some(HTCAPTION as _);
-            }
-        }
-
-        Some(HTCLIENT as _)
-    }
-
-    fn handle_nc_mouse_move_msg(&self, lparam: LPARAM) -> Option<isize> {
-        if !self.hide_title_bar {
-            return None;
-        }
-
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let mut cursor_point = POINT {
-                x: lparam.signed_loword().into(),
-                y: lparam.signed_hiword().into(),
-            };
-            unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
-            let scale_factor = self.scale_factor.get();
-            let event = MouseMoveEvent {
-                position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
-                pressed_button: None,
-                modifiers: self.current_modifiers(),
-            };
-            if callback(PlatformInput::MouseMove(event)).default_prevented {
-                return Some(0);
-            }
-        }
-        None
-    }
-
-    fn handle_nc_mouse_down_msg(
-        &self,
-        button: MouseButton,
-        wparam: WPARAM,
-        lparam: LPARAM,
-    ) -> Option<isize> {
-        if !self.hide_title_bar {
-            return None;
-        }
-
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let mut cursor_point = POINT {
-                x: lparam.signed_loword().into(),
-                y: lparam.signed_hiword().into(),
-            };
-            unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
-            let physical_point = point(DevicePixels(cursor_point.x), DevicePixels(cursor_point.y));
-            let click_count = self.click_state.borrow_mut().update(button, physical_point);
-            let scale_factor = self.scale_factor.get();
-            let event = MouseDownEvent {
-                button,
-                position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
-                modifiers: self.current_modifiers(),
-                click_count,
-                first_mouse: false,
-            };
-            if callback(PlatformInput::MouseDown(event)).default_prevented {
-                return Some(0);
-            }
-        }
-
-        // Since these are handled in handle_nc_mouse_up_msg we must prevent the default window proc
-        matches!(wparam.0 as u32, HTMINBUTTON | HTMAXBUTTON | HTCLOSE).then_some(0)
-    }
-
-    fn handle_nc_mouse_up_msg(
-        &self,
-        button: MouseButton,
-        wparam: WPARAM,
-        lparam: LPARAM,
-    ) -> Option<isize> {
-        if !self.hide_title_bar {
-            return None;
-        }
-
-        let mut callbacks = self.callbacks.borrow_mut();
-        if let Some(callback) = callbacks.input.as_mut() {
-            let mut cursor_point = POINT {
-                x: lparam.signed_loword().into(),
-                y: lparam.signed_hiword().into(),
-            };
-            unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
-            let scale_factor = self.scale_factor.get();
-            let event = MouseUpEvent {
-                button,
-                position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
-                modifiers: self.current_modifiers(),
-                click_count: 1,
-            };
-            if callback(PlatformInput::MouseUp(event)).default_prevented {
-                return Some(0);
-            }
-        }
-        drop(callbacks);
-
-        if button == MouseButton::Left {
-            match wparam.0 as u32 {
-                HTMINBUTTON => unsafe {
-                    ShowWindowAsync(self.hwnd, SW_MINIMIZE);
-                },
-                HTMAXBUTTON => unsafe {
-                    if self.is_maximized() {
-                        ShowWindowAsync(self.hwnd, SW_NORMAL);
-                    } else {
-                        ShowWindowAsync(self.hwnd, SW_MAXIMIZE);
-                    }
-                },
-                HTCLOSE => unsafe {
-                    PostMessageW(self.hwnd, WM_CLOSE, WPARAM::default(), LPARAM::default())
-                        .log_err();
-                },
-                _ => return None,
-            };
-            return Some(0);
-        }
+impl WindowsWindowStatePtr {
+    fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Rc<Self> {
+        let state = RefCell::new(WindowsWindowState::new(
+            hwnd,
+            context.transparent,
+            cs,
+            context.mouse_wheel_settings,
+            context.current_cursor,
+            context.display,
+        ));
 
-        None
+        Rc::new(Self {
+            state,
+            hwnd,
+            handle: context.handle,
+            hide_title_bar: context.hide_title_bar,
+            executor: context.executor.clone(),
+            main_receiver: context.main_receiver.clone(),
+        })
     }
 
-    fn handle_set_cursor(&self, lparam: LPARAM) -> Option<isize> {
-        if matches!(
-            lparam.loword() as u32,
-            HTLEFT
-                | HTRIGHT
-                | HTTOP
-                | HTTOPLEFT
-                | HTTOPRIGHT
-                | HTBOTTOM
-                | HTBOTTOMLEFT
-                | HTBOTTOMRIGHT
-        ) {
-            return None;
-        }
-        unsafe { SetCursor(self.platform_inner.current_cursor.get()) };
-        Some(1)
+    fn is_minimized(&self) -> bool {
+        unsafe { IsIconic(self.hwnd) }.as_bool()
     }
 }
 
 #[derive(Default)]
-struct Callbacks {
-    request_frame: Option<Box<dyn FnMut()>>,
-    input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
-    active_status_change: Option<Box<dyn FnMut(bool)>>,
-    resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
-    moved: Option<Box<dyn FnMut()>>,
-    should_close: Option<Box<dyn FnMut() -> bool>>,
-    close: Option<Box<dyn FnOnce()>>,
-    appearance_changed: Option<Box<dyn FnMut()>>,
-}
-
-pub(crate) struct WindowsWindow {
-    inner: Rc<WindowsWindowInner>,
-    drag_drop_handler: IDropTarget,
+pub(crate) struct Callbacks {
+    pub(crate) request_frame: Option<Box<dyn FnMut()>>,
+    pub(crate) input: Option<Box<dyn FnMut(crate::PlatformInput) -> DispatchEventResult>>,
+    pub(crate) active_status_change: Option<Box<dyn FnMut(bool)>>,
+    pub(crate) resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
+    pub(crate) moved: Option<Box<dyn FnMut()>>,
+    pub(crate) should_close: Option<Box<dyn FnMut() -> bool>>,
+    pub(crate) close: Option<Box<dyn FnOnce()>>,
+    pub(crate) appearance_changed: Option<Box<dyn FnMut()>>,
 }
 
 struct WindowCreateContext {
-    inner: Option<Rc<WindowsWindowInner>>,
-    platform_inner: Rc<WindowsPlatformInner>,
+    inner: Option<Rc<WindowsWindowStatePtr>>,
     handle: AnyWindowHandle,
     hide_title_bar: bool,
-    display: Rc<WindowsDisplay>,
+    display: WindowsDisplay,
     transparent: bool,
+    executor: ForegroundExecutor,
+    main_receiver: flume::Receiver<Runnable>,
+    mouse_wheel_settings: MouseWheelSettings,
+    current_cursor: HCURSOR,
 }
 
 impl WindowsWindow {
     pub(crate) fn new(
-        platform_inner: Rc<WindowsPlatformInner>,
         handle: AnyWindowHandle,
         options: WindowParams,
+        icon: HICON,
+        executor: ForegroundExecutor,
+        main_receiver: flume::Receiver<Runnable>,
+        mouse_wheel_settings: MouseWheelSettings,
+        current_cursor: HCURSOR,
     ) -> Self {
-        let classname = register_wnd_class(platform_inner.icon);
+        let classname = register_wnd_class(icon);
         let hide_title_bar = options
             .titlebar
             .as_ref()