use std::rc::Rc; use ::util::ResultExt;use anyhow::Context as _;use windows::{ core::PCWSTR, Win32::{ Foundation::*, Graphics::Gdi::*, System::SystemServices::*, UI::{ Controls::*, HiDpi::*, Input::{Ime::*, KeyboardAndMouse::*}, WindowsAndMessaging::*, }, },}; use crate::*; pub(crate) const WM_GPUI_CURSOR_STYLE_CHANGED: u32 = WM_USER + 1;pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2;pub(crate) const WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3; const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 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(wparam, 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_DISPLAYCHANGE => handle_display_change_msg(handle, 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(handle, lparam, wparam, state_ptr), WM_MOUSELEAVE | WM_NCMOUSELEAVE => handle_mouse_leave_msg(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(handle, MouseButton::Left, lparam, state_ptr), WM_RBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Right, lparam, state_ptr), WM_MBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Middle, lparam, state_ptr), WM_XBUTTONDOWN => { handle_xbutton_msg(handle, wparam, lparam, handle_mouse_down_msg, state_ptr) } WM_LBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Left, lparam, state_ptr), WM_RBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Right, lparam, state_ptr), WM_MBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Middle, lparam, state_ptr), WM_XBUTTONUP => handle_xbutton_msg(handle, 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(wparam, lparam, state_ptr), WM_SYSKEYUP => handle_syskeyup_msg(wparam, state_ptr), WM_SYSCOMMAND => handle_system_command(wparam, state_ptr), WM_KEYDOWN => handle_keydown_msg(wparam, lparam, state_ptr), WM_KEYUP => handle_keyup_msg(wparam, state_ptr), WM_CHAR => handle_char_msg(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), WM_SETTINGCHANGE => handle_system_settings_changed(handle, lparam, state_ptr), WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(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 mut lock = state_ptr.state.borrow_mut(); let origin = logical_point( lparam.signed_loword() as f32, lparam.signed_hiword() as f32, lock.scale_factor, ); lock.origin = origin; let size = lock.logical_size; let center_x = origin.x.0 + size.width.0 / 2.; let center_y = origin.y.0 + 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) }; // minimize the window can trigger this event too, in this case, // monitor is invalid, we do nothing. 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( wparam: WPARAM, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>,) -> Option<isize> { let mut lock = state_ptr.state.borrow_mut(); // Don't resize the renderer when the window is minimized, but record that it was minimized so // that on restore the swap chain can be recreated via `update_drawable_size_even_if_unchanged`. if wparam.0 == SIZE_MINIMIZED as usize { lock.restore_from_minimized = lock.callbacks.request_frame.take(); return Some(0); } let width = lparam.loword().max(1) as i32; let height = lparam.hiword().max(1) as i32; let new_size = size(DevicePixels(width), DevicePixels(height)); let scale_factor = lock.scale_factor; if lock.restore_from_minimized.is_some() { lock.renderer .update_drawable_size_even_if_unchanged(new_size); lock.callbacks.request_frame = lock.restore_from_minimized.take(); } else { lock.renderer.update_drawable_size(new_size); } let new_size = new_size.to_pixels(scale_factor); lock.logical_size = new_size; if let Some(mut callback) = lock.callbacks.resize.take() { drop(lock); callback(new_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 lock = state_ptr.state.borrow_mut(); if let Some(mut request_frame) = lock.callbacks.request_frame.take() { drop(lock); request_frame(Default::default()); state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame); } unsafe { ValidateRect(handle, None).ok().log_err() }; 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 { PostThreadMessageW( state_ptr.main_thread_id_win32, WM_GPUI_CLOSE_ONE_WINDOW, WPARAM(state_ptr.validation_number), LPARAM(handle.0 as isize), ) .log_err(); } Some(0)} fn handle_mouse_move_msg( handle: HWND, lparam: LPARAM, wparam: WPARAM, state_ptr: Rc<WindowsWindowStatePtr>,) -> Option<isize> { start_tracking_mouse(handle, &state_ptr, TME_LEAVE); 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_mouse_leave_msg(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> { let mut lock = state_ptr.state.borrow_mut(); lock.hovered = false; if let Some(mut callback) = lock.callbacks.hovered_status_change.take() { drop(lock); callback(false); state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback); } Some(0)} fn handle_syskeydown_msg( 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 keystroke = parse_syskeydown_msg_keystroke(wparam)?; let mut func = state_ptr.state.borrow_mut().callbacks.input.take()?; let event = KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, }; let result = if !func(PlatformInput::KeyDown(event)).propagate { state_ptr.state.borrow_mut().system_key_handled = true; Some(0) } else { None }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result} fn handle_syskeyup_msg(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 keystroke = parse_syskeydown_msg_keystroke(wparam)?; let mut func = state_ptr.state.borrow_mut().callbacks.input.take()?; let event = KeyUpEvent { keystroke }; let result = if func(PlatformInput::KeyUp(event)).default_prevented { Some(0) } else { Some(1) }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result} fn handle_keydown_msg( wparam: WPARAM, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>,) -> Option<isize> { let Some(keystroke_or_modifier) = 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 = match keystroke_or_modifier { KeystrokeOrModifier::Keystroke(keystroke) => PlatformInput::KeyDown(KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, }), KeystrokeOrModifier::Modifier(modifiers) => { PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers }) } }; let result = if func(event).default_prevented { Some(0) } else { Some(1) }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result} fn handle_keyup_msg(wparam: WPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> { let Some(keystroke_or_modifier) = 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 = match keystroke_or_modifier { KeystrokeOrModifier::Keystroke(keystroke) => PlatformInput::KeyUp(KeyUpEvent { keystroke }), KeystrokeOrModifier::Modifier(modifiers) => { PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers }) } }; let result = if func(event).default_prevented { Some(0) } else { Some(1) }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result} fn handle_char_msg( 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 key_char = keystroke.key_char.clone(); let event = KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, }; let dispatch_event_result = func(PlatformInput::KeyDown(event)); state_ptr.state.borrow_mut().callbacks.input = Some(func); if dispatch_event_result.default_prevented || !dispatch_event_result.propagate { return Some(0); } let Some(ime_char) = key_char else { return Some(1); }; with_input_handler(&state_ptr, |input_handler| { input_handler.replace_text_in_range(None, &ime_char); }); Some(0)} fn handle_mouse_down_msg( handle: HWND, button: MouseButton, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>,) -> Option<isize> { unsafe { SetCapture(handle) }; 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( _handle: HWND, button: MouseButton, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>,) -> Option<isize> { unsafe { ReleaseCapture().log_err() }; 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,Lines 1–500 of 1565. Load more
use std::rc::Rc; use ::util::ResultExt; use anyhow::Context as _; use windows::{ core::PCWSTR, Win32::{ Foundation::*, Graphics::Gdi::*, System::SystemServices::*, UI::{ Controls::*, HiDpi::*, Input::{Ime::*, KeyboardAndMouse::*}, WindowsAndMessaging::*, }, }, }; use crate::*; pub(crate) const WM_GPUI_CURSOR_STYLE_CHANGED: u32 = WM_USER + 1; pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2; pub(crate) const WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3; const SIZE_MOVE_LOOP_TIMER_ID: usize = 1; const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 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(wparam, 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_DISPLAYCHANGE => handle_display_change_msg(handle, 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(handle, lparam, wparam, state_ptr), WM_MOUSELEAVE | WM_NCMOUSELEAVE => handle_mouse_leave_msg(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(handle, MouseButton::Left, lparam, state_ptr), WM_RBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Right, lparam, state_ptr), WM_MBUTTONDOWN => handle_mouse_down_msg(handle, MouseButton::Middle, lparam, state_ptr), WM_XBUTTONDOWN => { handle_xbutton_msg(handle, wparam, lparam, handle_mouse_down_msg, state_ptr) } WM_LBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Left, lparam, state_ptr), WM_RBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Right, lparam, state_ptr), WM_MBUTTONUP => handle_mouse_up_msg(handle, MouseButton::Middle, lparam, state_ptr), WM_XBUTTONUP => handle_xbutton_msg(handle, 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(wparam, lparam, state_ptr), WM_SYSKEYUP => handle_syskeyup_msg(wparam, state_ptr), WM_SYSCOMMAND => handle_system_command(wparam, state_ptr), WM_KEYDOWN => handle_keydown_msg(wparam, lparam, state_ptr), WM_KEYUP => handle_keyup_msg(wparam, state_ptr), WM_CHAR => handle_char_msg(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), WM_SETTINGCHANGE => handle_system_settings_changed(handle, lparam, state_ptr), WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(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 mut lock = state_ptr.state.borrow_mut(); let origin = logical_point( lparam.signed_loword() as f32, lparam.signed_hiword() as f32, lock.scale_factor, ); lock.origin = origin; let size = lock.logical_size; let center_x = origin.x.0 + size.width.0 / 2.; let center_y = origin.y.0 + 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) }; // minimize the window can trigger this event too, in this case, // monitor is invalid, we do nothing. 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( wparam: WPARAM, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>, ) -> Option<isize> { let mut lock = state_ptr.state.borrow_mut(); // Don't resize the renderer when the window is minimized, but record that it was minimized so // that on restore the swap chain can be recreated via `update_drawable_size_even_if_unchanged`. if wparam.0 == SIZE_MINIMIZED as usize { lock.restore_from_minimized = lock.callbacks.request_frame.take(); return Some(0); } let width = lparam.loword().max(1) as i32; let height = lparam.hiword().max(1) as i32; let new_size = size(DevicePixels(width), DevicePixels(height)); let scale_factor = lock.scale_factor; if lock.restore_from_minimized.is_some() { lock.renderer .update_drawable_size_even_if_unchanged(new_size); lock.callbacks.request_frame = lock.restore_from_minimized.take(); } else { lock.renderer.update_drawable_size(new_size); } let new_size = new_size.to_pixels(scale_factor); lock.logical_size = new_size; if let Some(mut callback) = lock.callbacks.resize.take() { drop(lock); callback(new_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 lock = state_ptr.state.borrow_mut(); if let Some(mut request_frame) = lock.callbacks.request_frame.take() { drop(lock); request_frame(Default::default()); state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame); } unsafe { ValidateRect(handle, None).ok().log_err() }; 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 { PostThreadMessageW( state_ptr.main_thread_id_win32, WM_GPUI_CLOSE_ONE_WINDOW, WPARAM(state_ptr.validation_number), LPARAM(handle.0 as isize), ) .log_err(); } Some(0) } fn handle_mouse_move_msg( handle: HWND, lparam: LPARAM, wparam: WPARAM, state_ptr: Rc<WindowsWindowStatePtr>, ) -> Option<isize> { start_tracking_mouse(handle, &state_ptr, TME_LEAVE); 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_mouse_leave_msg(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> { let mut lock = state_ptr.state.borrow_mut(); lock.hovered = false; if let Some(mut callback) = lock.callbacks.hovered_status_change.take() { drop(lock); callback(false); state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback); } Some(0) } fn handle_syskeydown_msg( 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 keystroke = parse_syskeydown_msg_keystroke(wparam)?; let mut func = state_ptr.state.borrow_mut().callbacks.input.take()?; let event = KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, }; let result = if !func(PlatformInput::KeyDown(event)).propagate { state_ptr.state.borrow_mut().system_key_handled = true; Some(0) } else { None }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result } fn handle_syskeyup_msg(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 keystroke = parse_syskeydown_msg_keystroke(wparam)?; let mut func = state_ptr.state.borrow_mut().callbacks.input.take()?; let event = KeyUpEvent { keystroke }; let result = if func(PlatformInput::KeyUp(event)).default_prevented { Some(0) } else { Some(1) }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result } fn handle_keydown_msg( wparam: WPARAM, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>, ) -> Option<isize> { let Some(keystroke_or_modifier) = 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 = match keystroke_or_modifier { KeystrokeOrModifier::Keystroke(keystroke) => PlatformInput::KeyDown(KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, }), KeystrokeOrModifier::Modifier(modifiers) => { PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers }) } }; let result = if func(event).default_prevented { Some(0) } else { Some(1) }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result } fn handle_keyup_msg(wparam: WPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> { let Some(keystroke_or_modifier) = 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 = match keystroke_or_modifier { KeystrokeOrModifier::Keystroke(keystroke) => PlatformInput::KeyUp(KeyUpEvent { keystroke }), KeystrokeOrModifier::Modifier(modifiers) => { PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers }) } }; let result = if func(event).default_prevented { Some(0) } else { Some(1) }; state_ptr.state.borrow_mut().callbacks.input = Some(func); result } fn handle_char_msg( 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 key_char = keystroke.key_char.clone(); let event = KeyDownEvent { keystroke, is_held: lparam.0 & (0x1 << 30) > 0, }; let dispatch_event_result = func(PlatformInput::KeyDown(event)); state_ptr.state.borrow_mut().callbacks.input = Some(func); if dispatch_event_result.default_prevented || !dispatch_event_result.propagate { return Some(0); } let Some(ime_char) = key_char else { return Some(1); }; with_input_handler(&state_ptr, |input_handler| { input_handler.replace_text_in_range(None, &ime_char); }); Some(0) } fn handle_mouse_down_msg( handle: HWND, button: MouseButton, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>, ) -> Option<isize> { unsafe { SetCapture(handle) }; 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( _handle: HWND, button: MouseButton, lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>, ) -> Option<isize> { unsafe { ReleaseCapture().log_err() }; 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,