Move Windows backend to winit-win32

This commit is contained in:
Mads Marquart 2025-05-25 05:13:25 +02:00 committed by GitHub
parent b1f8d778a1
commit 3b986f5583
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 299 additions and 280 deletions

5
.github/CODEOWNERS vendored
View file

@ -21,9 +21,8 @@
/src/platform/web.rs @daxpedda
/src/platform_impl/web @daxpedda
# Windows
/src/platform/windows.rs @notgull
/src/platform_impl/windows @notgull
# Windows (Win32)
/winit-win32 @notgull
# Orbital (Redox OS)
/winit-orbital @jackpot51

View file

@ -190,6 +190,10 @@ jobs:
if: contains(matrix.platform.target, 'redox')
run: cargo test -p winit-orbital
- name: Test winit Win32
if: contains(matrix.platform.target, 'windows')
run: cargo $CMD test -p winit-win32 --target=${{ matrix.platform.target }}
# Test only on Linux x86_64, so we avoid spending unnecessary CI hours.
- name: Test dpi crate
if: >

View file

@ -15,6 +15,7 @@ winit = { path = "." }
winit-android = { version = "0.0.0", path = "winit-android" }
winit-core = { version = "0.0.0", path = "winit-core" }
winit-orbital = { version = "0.0.0", path = "winit-orbital" }
winit-win32 = { version = "0.0.0", path = "winit-win32" }
# Core dependencies.
bitflags = "2"
@ -339,36 +340,8 @@ objc2-ui-kit = { workspace = true, features = [
"UIWindow",
] }
# Windows
[target.'cfg(target_os = "windows")'.dependencies]
unicode-segmentation.workspace = true
windows-sys = { workspace = true, features = [
"Win32_Devices_HumanInterfaceDevice",
"Win32_Foundation",
"Win32_Globalization",
"Win32_Graphics_Dwm",
"Win32_Graphics_Gdi",
"Win32_Media",
"Win32_System_Com_StructuredStorage",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_Security",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
"Win32_UI_Accessibility",
"Win32_UI_Controls",
"Win32_UI_HiDpi",
"Win32_UI_Input_Ime",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Input_Pointer",
"Win32_UI_Input_Touch",
"Win32_UI_Shell",
"Win32_UI_TextServices",
"Win32_UI_WindowsAndMessaging",
] }
winit-win32.workspace = true
# Linux
[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies]

View file

@ -348,6 +348,30 @@ impl winit_android::EventLoopBuilderExtAndroid for EventLoopBuilder {
}
}
#[cfg(windows_platform)]
impl winit_win32::EventLoopBuilderExtWindows for EventLoopBuilder {
#[inline]
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
self.platform_specific.any_thread = any_thread;
self
}
#[inline]
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
self.platform_specific.dpi_aware = dpi_aware;
self
}
#[inline]
fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
where
F: FnMut(*const core::ffi::c_void) -> bool + 'static,
{
self.platform_specific.msg_hook = Some(Box::new(callback));
self
}
}
/// ```compile_error
/// use winit::event_loop::run_on_demand::EventLoopExtRunOnDemand;
/// use winit::event_loop::EventLoop;

View file

@ -17,7 +17,7 @@ pub mod wayland;
#[cfg(web_platform)]
pub mod web;
#[cfg(windows_platform)]
pub mod windows;
pub use winit_win32 as windows;
#[cfg(x11_platform)]
pub mod x11;

View file

@ -9,7 +9,7 @@ pub(crate) use winit_orbital as platform;
#[cfg(web_platform)]
mod web;
#[cfg(windows_platform)]
mod windows;
pub(crate) use winit_win32 as platform;
#[cfg(target_vendor = "apple")]
use self::apple as platform;
@ -19,8 +19,6 @@ use self::linux as platform;
pub use self::platform::*;
#[cfg(web_platform)]
use self::web as platform;
#[cfg(windows_platform)]
use self::windows as platform;
#[cfg(all(
not(ios_platform),

View file

@ -1,82 +0,0 @@
use windows_sys::Win32::Foundation::HWND;
use windows_sys::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
use winit_core::event::DeviceId;
pub(crate) use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
pub(crate) use self::icon::{RaiiIcon, SelectedCursor};
pub(crate) use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
pub(crate) use self::monitor::MonitorHandle;
pub(crate) use self::window::Window;
fn wrap_device_id(id: u32) -> DeviceId {
DeviceId::from_raw(id as i64)
}
#[inline(always)]
const fn get_xbutton_wparam(x: u32) -> u16 {
hiword(x)
}
#[inline(always)]
const fn get_x_lparam(x: u32) -> i16 {
loword(x) as _
}
#[inline(always)]
const fn get_y_lparam(x: u32) -> i16 {
hiword(x) as _
}
#[inline(always)]
pub(crate) const fn primarylangid(lgid: u16) -> u16 {
lgid & 0x3ff
}
#[inline(always)]
pub(crate) const fn loword(x: u32) -> u16 {
(x & 0xffff) as u16
}
#[inline(always)]
const fn hiword(x: u32) -> u16 {
((x >> 16) & 0xffff) as u16
}
#[inline(always)]
unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize {
#[cfg(target_pointer_width = "64")]
return unsafe { windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, nindex) };
#[cfg(target_pointer_width = "32")]
return unsafe {
windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, nindex) as isize
};
}
#[inline(always)]
unsafe fn set_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX, dwnewlong: isize) -> isize {
#[cfg(target_pointer_width = "64")]
return unsafe {
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, nindex, dwnewlong)
};
#[cfg(target_pointer_width = "32")]
return unsafe {
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(hwnd, nindex, dwnewlong as i32)
as isize
};
}
#[macro_use]
mod util;
mod dark_mode;
mod definitions;
mod dpi;
mod drop_handler;
mod event_loop;
mod icon;
mod ime;
mod keyboard;
mod keyboard_layout;
mod monitor;
pub(crate) mod raw_input;
mod window;
mod window_state;

59
winit-win32/Cargo.toml Normal file
View file

@ -0,0 +1,59 @@
[package]
description = "Winit's Win32/Windows backend"
documentation = "https://docs.rs/winit-win32"
edition.workspace = true
license.workspace = true
name = "winit-win32"
repository.workspace = true
rust-version.workspace = true
version = "0.0.0"
[features]
serde = ["dep:serde", "bitflags/serde", "smol_str/serde", "dpi/serde", "winit-core/serde"]
[dependencies]
bitflags.workspace = true
cursor-icon.workspace = true
dpi.workspace = true
rwh_06.workspace = true
serde = { workspace = true, optional = true }
smol_str.workspace = true
tracing.workspace = true
winit-core.workspace = true
# Platform-specific
unicode-segmentation.workspace = true
windows-sys = { workspace = true, features = [
"Win32_Devices_HumanInterfaceDevice",
"Win32_Foundation",
"Win32_Globalization",
"Win32_Graphics_Dwm",
"Win32_Graphics_Gdi",
"Win32_Media",
"Win32_System_Com_StructuredStorage",
"Win32_System_Com",
"Win32_System_LibraryLoader",
"Win32_System_Ole",
"Win32_Security",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
"Win32_UI_Accessibility",
"Win32_UI_Controls",
"Win32_UI_HiDpi",
"Win32_UI_Input_Ime",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Input_Pointer",
"Win32_UI_Input_Touch",
"Win32_UI_Shell",
"Win32_UI_TextServices",
"Win32_UI_WindowsAndMessaging",
] }
[dev-dependencies]
winit.workspace = true
[package.metadata.docs.rs]
all-features = true
targets = ["x86_64-pc-windows-msvc"]

1
winit-win32/README.md Symbolic link
View file

@ -0,0 +1 @@
../README.md

View file

@ -12,7 +12,7 @@ use windows_sys::Win32::UI::HiDpi::{
};
use windows_sys::Win32::UI::WindowsAndMessaging::IsProcessDPIAware;
use crate::platform_impl::platform::util::{
use crate::util::{
ENABLE_NON_CLIENT_DPI_SCALING, GET_DPI_FOR_MONITOR, GET_DPI_FOR_WINDOW, SET_PROCESS_DPI_AWARE,
SET_PROCESS_DPI_AWARENESS, SET_PROCESS_DPI_AWARENESS_CONTEXT,
};

View file

@ -14,7 +14,7 @@ use windows_sys::Win32::System::Ole::{CF_HDROP, DROPEFFECT_COPY, DROPEFFECT_NONE
use windows_sys::Win32::UI::Shell::{DragFinish, DragQueryFileW, HDROP};
use winit_core::event::WindowEvent;
use crate::platform_impl::platform::definitions::{
use crate::definitions::{
IDataObject, IDataObjectVtbl, IDropTarget, IDropTargetVtbl, IUnknown, IUnknownVtbl,
};

View file

@ -79,20 +79,18 @@ use winit_core::window::{Theme, Window as CoreWindow, WindowAttributes, WindowId
pub(super) use self::runner::{Event, EventLoopRunner};
use super::window::set_skip_taskbar;
use super::SelectedCursor;
use crate::platform_impl::platform::dark_mode::try_theme;
use crate::platform_impl::platform::dpi::{become_dpi_aware, dpi_to_scale_factor};
use crate::platform_impl::platform::drop_handler::FileDropHandler;
use crate::platform_impl::platform::icon::WinCursor;
use crate::platform_impl::platform::ime::ImeContext;
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
use crate::platform_impl::platform::keyboard_layout::LAYOUT_CACHE;
use crate::platform_impl::platform::monitor::{self, MonitorHandle};
use crate::platform_impl::platform::window::InitData;
use crate::platform_impl::platform::window_state::{
CursorFlags, ImeState, WindowFlags, WindowState,
};
use crate::platform_impl::platform::{raw_input, util, wrap_device_id};
use crate::platform_impl::Window;
use crate::dark_mode::try_theme;
use crate::dpi::{become_dpi_aware, dpi_to_scale_factor};
use crate::drop_handler::FileDropHandler;
use crate::icon::WinCursor;
use crate::ime::ImeContext;
use crate::keyboard::KeyEventBuilder;
use crate::keyboard_layout::LAYOUT_CACHE;
use crate::monitor::{self, MonitorHandle};
use crate::util::wrap_device_id;
use crate::window::{InitData, Window};
use crate::window_state::{CursorFlags, ImeState, WindowFlags, WindowState};
use crate::{raw_input, util};
pub(crate) struct WindowData {
pub window_state: Arc<Mutex<WindowState>>,
@ -150,10 +148,10 @@ impl fmt::Debug for EventLoop {
}
}
pub(crate) struct PlatformSpecificEventLoopAttributes {
pub(crate) any_thread: bool,
pub(crate) dpi_aware: bool,
pub(crate) msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
pub struct PlatformSpecificEventLoopAttributes {
pub any_thread: bool,
pub dpi_aware: bool,
pub msg_hook: Option<Box<dyn FnMut(*const c_void) -> bool + 'static>>,
}
impl fmt::Debug for PlatformSpecificEventLoopAttributes {
@ -194,7 +192,7 @@ impl std::hash::Hash for PlatformSpecificEventLoopAttributes {
}
impl EventLoop {
pub(crate) fn new(
pub fn new(
attributes: &mut PlatformSpecificEventLoopAttributes,
) -> Result<Self, EventLoopError> {
let thread_id = unsafe { GetCurrentThreadId() };
@ -880,7 +878,7 @@ fn create_event_target_window() -> HWND {
ptr::null(),
);
super::set_window_long(
util::set_window_long(
window,
GWL_STYLE,
// The window technically has to be visible to receive WM_PAINT messages (which are
@ -899,7 +897,7 @@ fn insert_event_target_window_data(
let userdata = ThreadMsgTargetData { event_loop_runner };
let input_ptr = Box::into_raw(Box::new(userdata));
unsafe { super::set_window_long(thread_msg_target, GWL_USERDATA, input_ptr as isize) };
unsafe { util::set_window_long(thread_msg_target, GWL_USERDATA, input_ptr as isize) };
}
/// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of
@ -977,7 +975,7 @@ pub(super) unsafe extern "system" fn public_window_callback(
wparam: WPARAM,
lparam: LPARAM,
) -> LRESULT {
let userdata = unsafe { super::get_window_long(window, GWL_USERDATA) };
let userdata = unsafe { util::get_window_long(window, GWL_USERDATA) };
let userdata_ptr = match (userdata, msg) {
(0, WM_NCCREATE) => {
@ -986,7 +984,7 @@ pub(super) unsafe extern "system" fn public_window_callback(
let result = match unsafe { initdata.on_nccreate(window) } {
Some(userdata) => unsafe {
super::set_window_long(window, GWL_USERDATA, userdata as _);
util::set_window_long(window, GWL_USERDATA, userdata as _);
DefWindowProcW(window, msg, wparam, lparam)
},
None => -1, // failed to create the window
@ -1176,7 +1174,7 @@ unsafe fn public_window_callback_inner(
},
WM_NCDESTROY => {
unsafe { super::set_window_long(window, GWL_USERDATA, 0) };
unsafe { util::set_window_long(window, GWL_USERDATA, 0) };
userdata.userdata_removed.set(true);
result = ProcResult::Value(0);
},
@ -1301,8 +1299,8 @@ unsafe fn public_window_callback_inner(
WM_SIZE => {
use winit_core::event::WindowEvent::SurfaceResized;
let w = super::loword(lparam as u32) as u32;
let h = super::hiword(lparam as u32) as u32;
let w = util::loword(lparam as u32) as u32;
let h = util::hiword(lparam as u32) as u32;
let physical_size = PhysicalSize::new(w, h);
@ -1533,8 +1531,8 @@ unsafe fn public_window_callback_inner(
use winit_core::event::WindowEvent::{PointerEntered, PointerLeft, PointerMoved};
use winit_core::event::{PointerKind, PointerSource};
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
let cursor_moved;
@ -1681,8 +1679,8 @@ unsafe fn public_window_callback_inner(
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1704,8 +1702,8 @@ unsafe fn public_window_callback_inner(
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1727,8 +1725,8 @@ unsafe fn public_window_callback_inner(
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1750,8 +1748,8 @@ unsafe fn public_window_callback_inner(
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1773,8 +1771,8 @@ unsafe fn public_window_callback_inner(
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1796,8 +1794,8 @@ unsafe fn public_window_callback_inner(
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1814,14 +1812,14 @@ unsafe fn public_window_callback_inner(
use winit_core::event::ElementState::Pressed;
use winit_core::event::MouseButton::{Back, Forward, Other};
use winit_core::event::WindowEvent::PointerButton;
let xbutton = super::get_xbutton_wparam(wparam as u32);
let xbutton = util::get_xbutton_wparam(wparam as u32);
unsafe { capture_mouse(window, &mut userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1843,14 +1841,14 @@ unsafe fn public_window_callback_inner(
use winit_core::event::ElementState::Released;
use winit_core::event::MouseButton::{Back, Forward, Other};
use winit_core::event::WindowEvent::PointerButton;
let xbutton = super::get_xbutton_wparam(wparam as u32);
let xbutton = util::get_xbutton_wparam(wparam as u32);
unsafe { release_mouse(userdata.window_state_lock()) };
update_modifiers(window, userdata);
let x = super::get_x_lparam(lparam as u32) as i32;
let y = super::get_y_lparam(lparam as u32) as i32;
let x = util::get_x_lparam(lparam as u32) as i32;
let y = util::get_y_lparam(lparam as u32) as i32;
let position = PhysicalPosition::new(x as f64, y as f64);
userdata.send_window_event(window, PointerButton {
@ -1884,7 +1882,7 @@ unsafe fn public_window_callback_inner(
use winit_core::event::ElementState::{Pressed, Released};
use winit_core::event::{PointerKind, PointerSource};
let pcount = super::loword(wparam as u32) as usize;
let pcount = util::loword(wparam as u32) as usize;
let mut inputs = Vec::with_capacity(pcount);
let htouch = lparam as *mut _;
if unsafe {
@ -1967,7 +1965,7 @@ unsafe fn public_window_callback_inner(
*util::SKIP_POINTER_FRAME_MESSAGES,
*util::GET_POINTER_DEVICE_RECTS,
) {
let pointer_id = super::loword(wparam as u32) as u32;
let pointer_id = util::loword(wparam as u32) as u32;
let mut entries_count = 0u32;
let mut pointers_count = 0u32;
if unsafe {
@ -2165,7 +2163,7 @@ unsafe fn public_window_callback_inner(
// The return value for the preceding `WM_NCHITTEST` message is conveniently
// provided through the low-order word of lParam. We use that here since
// `WM_MOUSEMOVE` seems to come after `WM_SETCURSOR` for a given cursor movement.
let in_client_area = super::loword(lparam as u32) as u32 == HTCLIENT;
let in_client_area = util::loword(lparam as u32) as u32 == HTCLIENT;
if in_client_area {
Some(window_state.mouse.selected_cursor.clone())
} else {
@ -2221,7 +2219,7 @@ unsafe fn public_window_callback_inner(
// "you only need to use either the X-axis or the Y-axis value when scaling your
// application since they are the same".
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn312083(v=vs.85).aspx
let new_dpi_x = super::loword(wparam as u32) as u32;
let new_dpi_x = util::loword(wparam as u32) as u32;
let new_scale_factor = dpi_to_scale_factor(new_dpi_x);
let old_scale_factor: f64;
@ -2474,7 +2472,7 @@ unsafe extern "system" fn thread_event_target_callback(
lparam: LPARAM,
) -> LRESULT {
let userdata_ptr =
unsafe { super::get_window_long(window, GWL_USERDATA) } as *mut ThreadMsgTargetData;
unsafe { util::get_window_long(window, GWL_USERDATA) } as *mut ThreadMsgTargetData;
if userdata_ptr.is_null() {
// `userdata_ptr` will always be null for the first `WM_GETMINMAXINFO`, as well as
// `WM_NCCREATE` and `WM_CREATE`.
@ -2493,7 +2491,7 @@ unsafe extern "system" fn thread_event_target_callback(
// the git blame and history would be preserved.
let callback = || match msg {
WM_NCDESTROY => {
unsafe { super::set_window_long(window, GWL_USERDATA, 0) };
unsafe { util::set_window_long(window, GWL_USERDATA, 0) };
userdata_removed = true;
0
},

View file

@ -14,8 +14,8 @@ use winit_core::event_loop::ActiveEventLoop as RootActiveEventLoop;
use winit_core::window::WindowId;
use super::{ActiveEventLoop, ControlFlow, EventLoopThreadExecutor};
use crate::platform_impl::platform::event_loop::{WindowData, GWL_USERDATA};
use crate::platform_impl::platform::get_window_long;
use crate::event_loop::{WindowData, GWL_USERDATA};
use crate::util::get_window_long;
type EventHandler = Cell<Option<&'static mut (dyn ApplicationHandler + 'static)>>;

View file

@ -18,7 +18,7 @@ use winit_core::error::RequestError;
use winit_core::icon::*;
use super::util;
use crate::platform::windows::WinIcon;
use crate::WinIcon;
pub(crate) const PIXEL_SIZE: usize = mem::size_of::<Pixel>();

View file

@ -12,7 +12,7 @@ use windows_sys::Win32::UI::Input::Ime::{
};
use windows_sys::Win32::UI::WindowsAndMessaging::{GetSystemMetrics, SM_IMMENABLED};
use crate::platform::windows::HWND;
use crate::HWND;
pub struct ImeContext {
hwnd: HWND,

View file

@ -29,11 +29,9 @@ use winit_core::keyboard::{
Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey,
};
use crate::platform_impl::platform::event_loop::ProcResult;
use crate::platform_impl::platform::keyboard_layout::{
Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE,
};
use crate::platform_impl::platform::{loword, primarylangid};
use crate::event_loop::ProcResult;
use crate::keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE};
use crate::util::{loword, primarylangid};
pub type ExScancode = u16;
@ -900,7 +898,7 @@ fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation {
}
}
pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
pub fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32> {
// See `scancode_to_physicalkey` for more info
let hkl = unsafe { GetKeyboardLayout(0) };
@ -1096,7 +1094,7 @@ pub(crate) fn physicalkey_to_scancode(physical_key: PhysicalKey) -> Option<u32>
}
}
pub(crate) fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
pub fn scancode_to_physicalkey(scancode: u32) -> PhysicalKey {
// See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
// and: https://www.w3.org/TR/uievents-code/
// and: The widget/NativeKeyToDOMCodeName.h file in the firefox source

View file

@ -42,7 +42,8 @@ use windows_sys::Win32::UI::Input::KeyboardAndMouse::{
};
use winit_core::keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey};
use crate::platform_impl::{loword, primarylangid, scancode_to_physicalkey};
use crate::keyboard::scancode_to_physicalkey;
use crate::util::{loword, primarylangid};
pub(crate) static LAYOUT_CACHE: LazyLock<Mutex<LayoutCache>> =
LazyLock::new(|| Mutex::new(LayoutCache::default()));

View file

@ -1,25 +1,44 @@
//! # Windows
//! # Winit Win32 / Windows backend
//!
//! The supported OS version is Windows 7 or higher, though Windows 10 is
//! tested regularly.
#![cfg(target_os = "windows")] // FIXME(madsmtm): Allow compiling on all platforms.
#[macro_use]
mod util;
mod dark_mode;
mod definitions;
mod dpi;
mod drop_handler;
mod event_loop;
mod icon;
mod ime;
mod keyboard;
mod keyboard_layout;
mod monitor;
mod raw_input;
mod window;
mod window_state;
use std::borrow::Borrow;
use std::ffi::c_void;
use std::ops::Deref;
use std::path::Path;
use std::sync::Arc;
use ::dpi::PhysicalSize;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(windows_platform)]
use windows_sys::Win32::Foundation::HANDLE;
use winit_core::window::PlatformWindowAttributes;
use winit_core::event::DeviceId;
use winit_core::icon::{BadIcon, Icon};
use winit_core::window::{PlatformWindowAttributes, Window as CoreWindow};
use crate::dpi::PhysicalSize;
use crate::event::DeviceId;
use crate::event_loop::EventLoopBuilder;
use crate::icon::{BadIcon, Icon};
use crate::platform_impl::RaiiIcon;
use crate::window::Window;
pub use self::event_loop::{EventLoop, PlatformSpecificEventLoopAttributes};
use self::icon::{RaiiIcon, SelectedCursor};
pub use self::keyboard::{physicalkey_to_scancode, scancode_to_physicalkey};
pub use self::monitor::{MonitorHandle, VideoModeHandle};
pub use self::window::Window;
/// Window Handle type used by Win32 API
pub type HWND = *mut c_void;
@ -121,24 +140,24 @@ pub enum CornerPreference {
///
/// See [`WindowBorrowExtWindows::any_thread`] for more information.
#[derive(Clone, Debug)]
pub struct AnyThread<W: Window>(W);
pub struct AnyThread<W: CoreWindow>(W);
impl<W: Window> AnyThread<W> {
impl<W: CoreWindow> AnyThread<W> {
/// Get a reference to the inner window.
#[inline]
pub fn get_ref(&self) -> &dyn Window {
pub fn get_ref(&self) -> &dyn CoreWindow {
&self.0
}
}
impl<W: Window> Deref for AnyThread<W> {
impl<W: CoreWindow> Deref for AnyThread<W> {
type Target = W;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<W: Window> rwh_06::HasWindowHandle for AnyThread<W> {
impl<W: CoreWindow> rwh_06::HasWindowHandle for AnyThread<W> {
fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
// SAFETY: The top level user has asserted this is only used safely.
unsafe { self.get_ref().window_handle_any_thread() }
@ -213,29 +232,6 @@ pub trait EventLoopBuilderExtWindows {
F: FnMut(*const c_void) -> bool + 'static;
}
impl EventLoopBuilderExtWindows for EventLoopBuilder {
#[inline]
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
self.platform_specific.any_thread = any_thread;
self
}
#[inline]
fn with_dpi_aware(&mut self, dpi_aware: bool) -> &mut Self {
self.platform_specific.dpi_aware = dpi_aware;
self
}
#[inline]
fn with_msg_hook<F>(&mut self, callback: F) -> &mut Self
where
F: FnMut(*const c_void) -> bool + 'static,
{
self.platform_specific.msg_hook = Some(Box::new(callback));
self
}
}
/// Additional methods on `Window` that are specific to Windows.
pub trait WindowExtWindows {
/// Enables or disables mouse and keyboard input to the specified window.
@ -344,40 +340,40 @@ pub trait WindowExtWindows {
) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError>;
}
impl WindowExtWindows for dyn Window + '_ {
impl WindowExtWindows for dyn CoreWindow + '_ {
#[inline]
fn set_enable(&self, enabled: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_enable(enabled)
}
#[inline]
fn set_taskbar_icon(&self, taskbar_icon: Option<Icon>) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_taskbar_icon(taskbar_icon)
}
#[inline]
fn set_skip_taskbar(&self, skip: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_skip_taskbar(skip)
}
#[inline]
fn set_undecorated_shadow(&self, shadow: bool) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_undecorated_shadow(shadow)
}
#[inline]
fn set_system_backdrop(&self, backdrop_type: BackdropType) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_system_backdrop(backdrop_type)
}
#[inline]
fn set_border_color(&self, color: Option<Color>) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_border_color(color.unwrap_or(Color::NONE))
}
@ -386,26 +382,26 @@ impl WindowExtWindows for dyn Window + '_ {
// The windows docs don't mention NONE as a valid options but it works in practice and is
// useful to circumvent the Windows option "Show accent color on title bars and
// window borders"
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_title_background_color(color.unwrap_or(Color::NONE))
}
#[inline]
fn set_title_text_color(&self, color: Color) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_title_text_color(color)
}
#[inline]
fn set_corner_preference(&self, preference: CornerPreference) {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
window.set_corner_preference(preference)
}
unsafe fn window_handle_any_thread(
&self,
) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
let window = self.cast_ref::<crate::platform_impl::Window>().unwrap();
let window = self.cast_ref::<Window>().unwrap();
unsafe {
let handle = window.rwh_06_no_thread_check()?;
@ -418,7 +414,7 @@ impl WindowExtWindows for dyn Window + '_ {
/// Additional methods for anything that dereference to [`Window`].
///
/// [`Window`]: crate::window::Window
pub trait WindowBorrowExtWindows: Borrow<dyn Window> + Sized {
pub trait WindowBorrowExtWindows: Borrow<dyn CoreWindow> + Sized {
/// Create an object that allows accessing the inner window handle in a thread-unsafe way.
///
/// It is possible to call [`window_handle_any_thread`] to get around Windows's thread
@ -439,13 +435,13 @@ pub trait WindowBorrowExtWindows: Borrow<dyn Window> + Sized {
/// [`window_handle_any_thread`]: WindowExtWindows::window_handle_any_thread
unsafe fn any_thread(self) -> AnyThread<Self>
where
Self: Window,
Self: CoreWindow,
{
AnyThread(self)
}
}
impl<W: Borrow<dyn Window> + Sized> WindowBorrowExtWindows for W {}
impl<W: Borrow<dyn CoreWindow> + Sized> WindowBorrowExtWindows for W {}
#[derive(Clone, Debug)]
pub struct WindowAttributesWindows {
@ -503,7 +499,7 @@ impl WindowAttributesWindows {
///
/// For more information, see <https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows>
///
/// [`WindowAttributes::with_parent_window`]: crate::window::WindowAttributes::with_parent_window
/// [`WindowAttributes::with_parent_window`]: winit_core::window::WindowAttributes::with_parent_window
pub fn with_owner_window(mut self, parent: HWND) -> Self {
self.owner = Some(parent);
self
@ -518,13 +514,8 @@ impl WindowAttributesWindows {
/// Note: Dark mode cannot be supported for win32 menus, it's simply not possible to change how
/// the menus look. If you use this, it is recommended that you combine it with
/// `with_theme(Some(Theme::Light))` to avoid a jarring effect.
#[rustfmt::skip]
///
#[cfg_attr(
windows_platform,
doc = "[`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu"
)]
#[cfg_attr(not(windows_platform), doc = "[`CreateMenu`]: #only-available-on-windows")]
/// [`CreateMenu`]: windows_sys::Win32::UI::WindowsAndMessaging::CreateMenu"
pub fn with_menu(mut self, menu: HMENU) -> Self {
self.menu = Some(menu);
self
@ -635,12 +626,11 @@ pub trait DeviceIdExtWindows {
fn persistent_identifier(&self) -> Option<String>;
}
#[cfg(windows_platform)]
impl DeviceIdExtWindows for DeviceId {
fn persistent_identifier(&self) -> Option<String> {
let raw_id = self.into_raw();
if raw_id != 0 {
crate::platform_impl::raw_input::get_raw_input_device_name(raw_id as HANDLE)
raw_input::get_raw_input_device_name(raw_id as HANDLE)
} else {
None
}

View file

@ -11,7 +11,7 @@ use winapi::{
um::winuser,
};
use crate::platform_impl::platform::{event_loop::ProcResult, keyboard::next_kbd_msg};
use crate::{event_loop::ProcResult, keyboard::next_kbd_msg};
pub struct MinimalIme {
// True if we're currently receiving messages belonging to a finished IME session.

View file

@ -14,8 +14,8 @@ use windows_sys::Win32::Graphics::Gdi::{
use winit_core::monitor::{MonitorHandleProvider, VideoMode};
use super::util::decode_wide;
use crate::platform_impl::platform::dpi::{dpi_to_scale_factor, get_monitor_dpi};
use crate::platform_impl::platform::util::has_flag;
use crate::dpi::{dpi_to_scale_factor, get_monitor_dpi};
use crate::util::has_flag;
#[derive(Clone)]
pub struct VideoModeHandle {

View file

@ -25,7 +25,7 @@ use winit_core::event_loop::DeviceEvents;
use winit_core::keyboard::{KeyCode, PhysicalKey};
use super::scancode_to_physicalkey;
use crate::platform_impl::platform::util;
use crate::util;
#[allow(dead_code)]
pub fn get_raw_input_device_list() -> Option<Vec<RAWINPUTDEVICELIST>> {

View file

@ -21,9 +21,16 @@ use windows_sys::Win32::UI::WindowsAndMessaging::{
GetWindowRect, IsIconic, ShowCursor, IDC_APPSTARTING, IDC_ARROW, IDC_CROSS, IDC_HAND, IDC_HELP,
IDC_IBEAM, IDC_NO, IDC_SIZEALL, IDC_SIZENESW, IDC_SIZENS, IDC_SIZENWSE, IDC_SIZEWE, IDC_WAIT,
SM_CXVIRTUALSCREEN, SM_CYVIRTUALSCREEN, SM_XVIRTUALSCREEN, SM_YVIRTUALSCREEN, SW_MAXIMIZE,
WINDOWPLACEMENT,
WINDOWPLACEMENT, WINDOW_LONG_PTR_INDEX,
};
use winit_core::cursor::CursorIcon;
use winit_core::event::DeviceId;
macro_rules! os_error {
($error:expr) => {{
winit_core::error::OsError::new(line!(), file!(), $error)
}};
}
pub fn encode_wide(string: impl AsRef<OsStr>) -> Vec<u16> {
string.as_ref().encode_wide().chain(once(0)).collect()
@ -204,11 +211,8 @@ pub(super) fn get_function_impl(library: &str, function: &str) -> Option<*const
macro_rules! get_function {
($lib:expr, $func:ident) => {
crate::platform_impl::platform::util::get_function_impl(
concat!($lib, '\0'),
concat!(stringify!($func), '\0'),
)
.map(|f| unsafe { std::mem::transmute::<*const _, $func>(f) })
crate::util::get_function_impl(concat!($lib, '\0'), concat!(stringify!($func), '\0'))
.map(|f| unsafe { std::mem::transmute::<*const _, $func>(f) })
};
}
@ -273,3 +277,64 @@ pub(crate) static GET_POINTER_DEVICE_RECTS: LazyLock<Option<GetPointerDeviceRect
LazyLock::new(|| get_function!("user32.dll", GetPointerDeviceRects));
pub(crate) static GET_POINTER_TOUCH_INFO: LazyLock<Option<GetPointerTouchInfo>> =
LazyLock::new(|| get_function!("user32.dll", GetPointerTouchInfo));
pub(crate) fn wrap_device_id(id: u32) -> DeviceId {
DeviceId::from_raw(id as i64)
}
#[inline(always)]
pub(crate) const fn get_xbutton_wparam(x: u32) -> u16 {
hiword(x)
}
#[inline(always)]
pub(crate) const fn get_x_lparam(x: u32) -> i16 {
loword(x) as _
}
#[inline(always)]
pub(crate) const fn get_y_lparam(x: u32) -> i16 {
hiword(x) as _
}
#[inline(always)]
pub(crate) const fn primarylangid(lgid: u16) -> u16 {
lgid & 0x3ff
}
#[inline(always)]
pub(crate) const fn loword(x: u32) -> u16 {
(x & 0xffff) as u16
}
#[inline(always)]
pub(crate) const fn hiword(x: u32) -> u16 {
((x >> 16) & 0xffff) as u16
}
#[inline(always)]
pub(crate) unsafe fn get_window_long(hwnd: HWND, nindex: WINDOW_LONG_PTR_INDEX) -> isize {
#[cfg(target_pointer_width = "64")]
return unsafe { windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongPtrW(hwnd, nindex) };
#[cfg(target_pointer_width = "32")]
return unsafe {
windows_sys::Win32::UI::WindowsAndMessaging::GetWindowLongW(hwnd, nindex) as isize
};
}
#[inline(always)]
pub(crate) unsafe fn set_window_long(
hwnd: HWND,
nindex: WINDOW_LONG_PTR_INDEX,
dwnewlong: isize,
) -> isize {
#[cfg(target_pointer_width = "64")]
return unsafe {
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongPtrW(hwnd, nindex, dwnewlong)
};
#[cfg(target_pointer_width = "32")]
return unsafe {
windows_sys::Win32::UI::WindowsAndMessaging::SetWindowLongW(hwnd, nindex, dwnewlong as i32)
as isize
};
}

View file

@ -1,5 +1,3 @@
#![cfg(windows_platform)]
use std::borrow::Cow;
use std::cell::Cell;
use std::ffi::c_void;
@ -57,29 +55,22 @@ use winit_core::window::{
WindowAttributes, WindowButtons, WindowId, WindowLevel,
};
use super::icon::WinCursor;
use super::MonitorHandle;
use crate::platform::windows::{
BackdropType, Color, CornerPreference, WinIcon, WindowAttributesWindows,
};
use crate::platform_impl::platform::dark_mode::try_theme;
use crate::platform_impl::platform::definitions::{
use crate::dark_mode::try_theme;
use crate::definitions::{
CLSID_TaskbarList, IID_ITaskbarList, IID_ITaskbarList2, ITaskbarList, ITaskbarList2,
};
use crate::platform_impl::platform::dpi::{
dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi,
use crate::dpi::{dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_dpi};
use crate::drop_handler::FileDropHandler;
use crate::event_loop::{self, ActiveEventLoop, Event, EventLoopRunner, DESTROY_MSG_ID};
use crate::icon::{IconType, WinCursor};
use crate::ime::ImeContext;
use crate::keyboard::KeyEventBuilder;
use crate::monitor::MonitorHandle;
use crate::window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState};
use crate::{
monitor, util, BackdropType, Color, CornerPreference, SelectedCursor, WinIcon,
WindowAttributesWindows,
};
use crate::platform_impl::platform::drop_handler::FileDropHandler;
use crate::platform_impl::platform::event_loop::{
self, ActiveEventLoop, Event, EventLoopRunner, DESTROY_MSG_ID,
};
use crate::platform_impl::platform::icon::IconType;
use crate::platform_impl::platform::ime::ImeContext;
use crate::platform_impl::platform::keyboard::KeyEventBuilder;
use crate::platform_impl::platform::window_state::{
CursorFlags, SavedWindow, WindowFlags, WindowState,
};
use crate::platform_impl::platform::{monitor, util, SelectedCursor};
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
@ -98,7 +89,7 @@ impl SyncWindowHandle {
/// The Win32 implementation of the main `Window` object.
#[derive(Debug)]
pub(crate) struct Window {
pub struct Window {
/// Main handle for the window.
window: SyncWindowHandle,
@ -130,14 +121,14 @@ impl Window {
self.window.hwnd()
}
pub unsafe fn rwh_06_no_thread_check(
pub(crate) unsafe fn rwh_06_no_thread_check(
&self,
) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
let mut window_handle = rwh_06::Win32WindowHandle::new(unsafe {
// SAFETY: Handle will never be zero.
std::num::NonZeroIsize::new_unchecked(self.window.hwnd() as isize)
});
let hinstance = unsafe { super::get_window_long(self.hwnd(), GWLP_HINSTANCE) };
let hinstance = unsafe { util::get_window_long(self.hwnd(), GWLP_HINSTANCE) };
window_handle.hinstance = std::num::NonZeroIsize::new(hinstance);
Ok(rwh_06::RawWindowHandle::Win32(window_handle))
}

View file

@ -21,7 +21,7 @@ use winit_core::keyboard::ModifiersState;
use winit_core::monitor::Fullscreen;
use winit_core::window::{Theme, WindowAttributes};
use crate::platform_impl::platform::{event_loop, util, SelectedCursor};
use crate::{event_loop, util, SelectedCursor};
/// Contains information about states and the window that the callback is going to use.
#[derive(Debug)]