1507 lines · 49.0 KB · Rust
RawDownload
use std::rc::Rc; use ::util::ResultExt;use anyhow::Context;use windows::Win32::{    Foundation::*,    Graphics::Gdi::*,    System::SystemServices::*,    UI::{        Controls::*,        HiDpi::*,        Input::{Ime::*, KeyboardAndMouse::*},        WindowsAndMessaging::*,    },}; use crate::*; pub(crate) const CURSOR_STYLE_CHANGED: u32 = WM_USER + 1;pub(crate) const CLOSE_ONE_WINDOW: u32 = WM_USER + 2; 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 => 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, state_ptr),        WM_DWMCOLORIZATIONCOLORCHANGED => handle_system_theme_changed(state_ptr),        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.is_minimized = Some(true);        return Some(0);    }    let may_have_been_minimized = lock.is_minimized.unwrap_or(true);    lock.is_minimized = Some(false);     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 may_have_been_minimized {        lock.renderer            .update_drawable_size_even_if_unchanged(new_size);    } 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 {        PostMessageW(            None,            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> {    let mut lock = state_ptr.state.borrow_mut();    if !lock.hovered {        lock.hovered = true;        unsafe {            TrackMouseEvent(&mut TRACKMOUSEEVENT {                cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,                dwFlags: TME_LEAVE,                hwndTrack: handle,                dwHoverTime: HOVER_DEFAULT,            })            .log_err()        };        if let Some(mut callback) = lock.callbacks.hovered_status_change.take() {            drop(lock);            callback(true);            state_ptr.state.borrow_mut().callbacks.hovered_status_change = Some(callback);        }    } else {        drop(lock);    }     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)    }} 

Lines 1–500 of 1507.