WIP - Make EL2 DPI changes and implement on Windows (#895)

* Modify DPI API publicly and on Windows

* Add generic Position and make dpi creation functions const

* Make examples work

* Fix fullscreen windows not appearing

* Replace Logical coordinates in window events with Physical coordinates

* Update HiDpiFactorChanged

* Document to_static
This commit is contained in:
Osspial 2019-06-19 16:49:43 -04:00
parent 2da24089de
commit f379d069b9
16 changed files with 427 additions and 369 deletions

View file

@ -141,7 +141,3 @@ pub unsafe fn hwnd_dpi(hwnd: HWND) -> u32 {
}
}
}
pub fn hwnd_scale_factor(hwnd: HWND) -> f64 {
dpi_to_scale_factor(unsafe { hwnd_dpi(hwnd) })
}

View file

@ -31,7 +31,7 @@ pub struct FileDropHandlerData {
pub interface: IDropTarget,
refcount: AtomicUsize,
window: HWND,
send_event: Box<dyn Fn(Event<()>)>,
send_event: Box<dyn Fn(Event<'static, ()>)>,
cursor_effect: DWORD,
hovered_is_valid: bool, /* If the currently hovered item is not valid there must not be any `HoveredFileCancelled` emitted */
}
@ -42,7 +42,7 @@ pub struct FileDropHandler {
#[allow(non_snake_case)]
impl FileDropHandler {
pub fn new(window: HWND, send_event: Box<dyn Fn(Event<()>)>) -> FileDropHandler {
pub fn new(window: HWND, send_event: Box<dyn Fn(Event<'static, ()>)>) -> FileDropHandler {
let data = Box::new(FileDropHandlerData {
interface: IDropTarget {
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
@ -227,7 +227,7 @@ impl FileDropHandler {
}
impl FileDropHandlerData {
fn send_event(&self, event: Event<()>) {
fn send_event(&self, event: Event<'static, ()>) {
(self.send_event)(event);
}
}

View file

@ -29,7 +29,6 @@ use std::{
use winapi::shared::basetsd::{DWORD_PTR, UINT_PTR};
use winapi::{
ctypes::c_int,
shared::{
minwindef::{BOOL, DWORD, HIWORD, INT, LOWORD, LPARAM, LRESULT, UINT, WPARAM},
windef::{HWND, POINT, RECT},
@ -37,20 +36,20 @@ use winapi::{
},
um::{
commctrl, libloaderapi, ole2, processthreadsapi, winbase,
winnt::{HANDLE, LONG, LPCSTR, SHORT},
winnt::{HANDLE, LPCSTR, SHORT},
winuser,
},
};
use self::runner::{ELRShared, EventLoopRunnerShared};
use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
dpi::{PhysicalPosition, PhysicalSize},
event::{DeviceEvent, Event, Force, KeyboardInput, Touch, TouchPhase, WindowEvent},
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
platform_impl::platform::{
dark_mode::try_dark_mode,
dpi::{
become_dpi_aware, dpi_to_scale_factor, enable_non_client_dpi_scaling, hwnd_scale_factor,
become_dpi_aware, dpi_to_scale_factor, enable_non_client_dpi_scaling,
},
drop_handler::FileDropHandler,
event::{
@ -97,26 +96,30 @@ lazy_static! {
get_function!("user32.dll", GetPointerPenInfo);
}
pub(crate) struct SubclassInput<T> {
pub(crate) struct SubclassInput<T: 'static> {
pub window_state: Arc<Mutex<WindowState>>,
pub event_loop_runner: EventLoopRunnerShared<T>,
pub file_drop_handler: FileDropHandler,
}
impl<T> SubclassInput<T> {
unsafe fn send_event(&self, event: Event<T>) {
unsafe fn send_event(&self, event: Event<'static, T>) {
self.event_loop_runner.send_event(event);
}
unsafe fn send_event_unbuffered<'e>(&self, event: Event<'e, T>) -> Result<(), Event<'e, T>> {
self.event_loop_runner.send_event_unbuffered(event)
}
}
struct ThreadMsgTargetSubclassInput<T> {
struct ThreadMsgTargetSubclassInput<T: 'static> {
event_loop_runner: EventLoopRunnerShared<T>,
user_event_receiver: Receiver<T>,
modifiers_state: ModifiersStateSide,
}
impl<T> ThreadMsgTargetSubclassInput<T> {
unsafe fn send_event(&self, event: Event<T>) {
unsafe fn send_event(&self, event: Event<'static, T>) {
self.event_loop_runner.send_event(event);
}
}
@ -126,7 +129,7 @@ pub struct EventLoop<T: 'static> {
window_target: RootELW<T>,
}
pub struct EventLoopWindowTarget<T> {
pub struct EventLoopWindowTarget<T: 'static> {
thread_id: DWORD,
thread_msg_target: HWND,
pub(crate) runner_shared: EventLoopRunnerShared<T>,
@ -191,7 +194,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run<F>(mut self, event_handler: F) -> !
where
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
{
self.run_return(event_handler);
::std::process::exit(0);
@ -199,7 +202,7 @@ impl<T: 'static> EventLoop<T> {
pub fn run_return<F>(&mut self, mut event_handler: F)
where
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
{
let event_loop_windows_ref = &self.window_target;
@ -465,13 +468,6 @@ lazy_static! {
winuser::RegisterWindowMessageA("Winit::DestroyMsg\0".as_ptr() as LPCSTR)
}
};
// Message sent by a `Window` after creation if it has a DPI != 96.
// WPARAM is the the DPI (u32). LOWORD of LPARAM is width, and HIWORD is height.
pub static ref INITIAL_DPI_MSG_ID: u32 = {
unsafe {
winuser::RegisterWindowMessageA("Winit::InitialDpiMsg\0".as_ptr() as LPCSTR)
}
};
// WPARAM is a bool specifying the `WindowFlags::MARKER_RETAIN_STATE_ON_SIZE` flag. See the
// documentation in the `window_state` module for more information.
pub static ref SET_RETAIN_STATE_ON_SIZE_MSG_ID: u32 = unsafe {
@ -597,7 +593,7 @@ fn normalize_pointer_pressure(pressure: u32) -> Option<Force> {
//
// Returning 0 tells the Win32 API that the message has been processed.
// FIXME: detect WM_DWMCOMPOSITIONCHANGED and call DwmEnableBlurBehindWindow if necessary
unsafe extern "system" fn public_window_callback<T>(
unsafe extern "system" fn public_window_callback<T: 'static>(
window: HWND,
msg: UINT,
wparam: WPARAM,
@ -713,12 +709,11 @@ unsafe extern "system" fn public_window_callback<T>(
let windowpos = lparam as *const winuser::WINDOWPOS;
if (*windowpos).flags & winuser::SWP_NOMOVE != winuser::SWP_NOMOVE {
let dpi_factor = hwnd_scale_factor(window);
let logical_position =
LogicalPosition::from_physical(((*windowpos).x, (*windowpos).y), dpi_factor);
let physical_position =
PhysicalPosition::new((*windowpos).x as f64, (*windowpos).y as f64);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: Moved(logical_position),
event: Moved(physical_position),
});
}
@ -731,11 +726,10 @@ unsafe extern "system" fn public_window_callback<T>(
let w = LOWORD(lparam as DWORD) as u32;
let h = HIWORD(lparam as DWORD) as u32;
let dpi_factor = hwnd_scale_factor(window);
let logical_size = LogicalSize::from_physical((w, h), dpi_factor);
let physical_size = PhysicalSize::new(w, h);
let event = Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: Resized(logical_size),
event: Resized(physical_size),
};
{
@ -840,8 +834,7 @@ unsafe extern "system" fn public_window_callback<T>(
let x = windowsx::GET_X_LPARAM(lparam) as f64;
let y = windowsx::GET_Y_LPARAM(lparam) as f64;
let dpi_factor = hwnd_scale_factor(window);
let position = LogicalPosition::from_physical((x, y), dpi_factor);
let position = PhysicalPosition::new(x, y);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
@ -1130,7 +1123,6 @@ unsafe extern "system" fn public_window_callback<T>(
mem::size_of::<winuser::TOUCHINPUT>() as INT,
) > 0
{
let dpi_factor = hwnd_scale_factor(window);
for input in &inputs {
let mut location = POINT {
x: input.x / 100,
@ -1143,7 +1135,7 @@ unsafe extern "system" fn public_window_callback<T>(
let x = location.x as f64 + (input.x % 100) as f64 / 100f64;
let y = location.y as f64 + (input.y % 100) as f64 / 100f64;
let location = LogicalPosition::from_physical((x, y), dpi_factor);
let location = PhysicalPosition::new(x, y);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
@ -1204,7 +1196,6 @@ unsafe extern "system" fn public_window_callback<T>(
return 0;
}
let dpi_factor = hwnd_scale_factor(window);
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getpointerframeinfohistory
// The information retrieved appears in reverse chronological order, with the most recent entry in the first
// row of the returned array
@ -1282,7 +1273,7 @@ unsafe extern "system" fn public_window_callback<T>(
let x = location.x as f64 + x.fract();
let y = location.y as f64 + y.fract();
let location = LogicalPosition::from_physical((x, y), dpi_factor);
let location = PhysicalPosition::new(x, y);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: WindowEvent::Touch(Touch {
@ -1446,27 +1437,66 @@ unsafe extern "system" fn public_window_callback<T>(
new_dpi_factor != old_dpi_factor && window_state.fullscreen.is_none()
};
// This prevents us from re-applying DPI adjustment to the restored size after exiting
// fullscreen (the restored size is already DPI adjusted).
if allow_resize {
// Resize window to the size suggested by Windows.
let rect = &*(lparam as *const RECT);
let style = winuser::GetWindowLongW(window, winuser::GWL_STYLE) as _;
let style_ex = winuser::GetWindowLongW(window, winuser::GWL_EXSTYLE) as _;
let b_menu = !winuser::GetMenu(window).is_null() as BOOL;
// New size as suggested by Windows.
let rect = *(lparam as *const RECT);
// The window rect provided is the window's outer size, not it's inner size. However,
// win32 doesn't provide an `UnadjustWindowRectEx` function to get the client rect from
// the outer rect, so we instead adjust the window rect to get the decoration margins
// and remove them from the outer size.
let margins_horizontal: u32;
let margins_vertical: u32;
{
let mut adjusted_rect = rect;
winuser::AdjustWindowRectExForDpi(
&mut adjusted_rect,
style,
b_menu,
style_ex,
new_dpi_x,
);
let margin_left = rect.left - adjusted_rect.left;
let margin_right = adjusted_rect.right - rect.right;
let margin_top = rect.top - adjusted_rect.top;
let margin_bottom = adjusted_rect.bottom - rect.bottom;
margins_horizontal = (margin_left + margin_right) as u32;
margins_vertical = (margin_bottom + margin_top) as u32;
}
let physical_inner_rect = PhysicalSize::new(
(rect.right - rect.left) as u32 - margins_horizontal,
(rect.bottom - rect.top) as u32 - margins_vertical,
);
// `allow_resize` prevents us from re-applying DPI adjustment to the restored size after
// exiting fullscreen (the restored size is already DPI adjusted).
let mut new_inner_rect_opt = Some(physical_inner_rect).filter(|_| allow_resize);
let _ = subclass_input.send_event_unbuffered(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: HiDpiFactorChanged {
hidpi_factor: new_dpi_factor,
new_inner_size: &mut new_inner_rect_opt,
},
});
if let Some(new_inner_rect) = new_inner_rect_opt {
winuser::SetWindowPos(
window,
ptr::null_mut(),
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
(new_inner_rect.width + margins_horizontal) as _,
(new_inner_rect.height + margins_vertical) as _,
winuser::SWP_NOZORDER | winuser::SWP_NOACTIVATE,
);
}
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: HiDpiFactorChanged(new_dpi_factor),
});
0
}
@ -1502,44 +1532,6 @@ unsafe extern "system" fn public_window_callback<T>(
f.set(WindowFlags::MARKER_RETAIN_STATE_ON_SIZE, wparam != 0)
});
0
} else if msg == *INITIAL_DPI_MSG_ID {
use crate::event::WindowEvent::HiDpiFactorChanged;
let scale_factor = dpi_to_scale_factor(wparam as u32);
subclass_input.send_event(Event::WindowEvent {
window_id: RootWindowId(WindowId(window)),
event: HiDpiFactorChanged(scale_factor),
});
// Automatically resize for actual DPI
let width = LOWORD(lparam as DWORD) as u32;
let height = HIWORD(lparam as DWORD) as u32;
let (adjusted_width, adjusted_height): (u32, u32) =
PhysicalSize::from_logical((width, height), scale_factor).into();
// We're not done yet! `SetWindowPos` needs the window size, not the client area size.
let mut rect = RECT {
top: 0,
left: 0,
bottom: adjusted_height as LONG,
right: adjusted_width as LONG,
};
let dw_style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD;
let b_menu = !winuser::GetMenu(window).is_null() as BOOL;
let dw_style_ex = winuser::GetWindowLongA(window, winuser::GWL_EXSTYLE) as DWORD;
winuser::AdjustWindowRectEx(&mut rect, dw_style, b_menu, dw_style_ex);
let outer_x = (rect.right - rect.left).abs() as c_int;
let outer_y = (rect.top - rect.bottom).abs() as c_int;
winuser::SetWindowPos(
window,
ptr::null_mut(),
0,
0,
outer_x,
outer_y,
winuser::SWP_NOMOVE
| winuser::SWP_NOREPOSITION
| winuser::SWP_NOZORDER
| winuser::SWP_NOACTIVATE,
);
0
} else {
commctrl::DefSubclassProc(window, msg, wparam, lparam)
}
@ -1547,7 +1539,7 @@ unsafe extern "system" fn public_window_callback<T>(
}
}
unsafe extern "system" fn thread_event_target_callback<T>(
unsafe extern "system" fn thread_event_target_callback<T: 'static>(
window: HWND,
msg: UINT,
wparam: WPARAM,

View file

@ -10,17 +10,17 @@ use crate::{
};
pub(crate) type EventLoopRunnerShared<T> = Rc<ELRShared<T>>;
pub(crate) struct ELRShared<T> {
pub(crate) struct ELRShared<T: 'static> {
runner: RefCell<Option<EventLoopRunner<T>>>,
buffer: RefCell<VecDeque<Event<T>>>,
buffer: RefCell<VecDeque<Event<'static, T>>>,
redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>,
}
struct EventLoopRunner<T> {
struct EventLoopRunner<T: 'static> {
control_flow: ControlFlow,
runner_state: RunnerState,
modal_redraw_window: HWND,
in_modal_loop: bool,
event_handler: Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
event_handler: Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>,
panic_error: Option<PanicError>,
redraw_buffer: Rc<RefCell<VecDeque<WindowId>>>,
}
@ -37,7 +37,7 @@ impl<T> ELRShared<T> {
pub(crate) unsafe fn set_runner<F>(&self, event_loop: &EventLoop<T>, f: F)
where
F: FnMut(Event<T>, &mut ControlFlow),
F: FnMut(Event<'_, T>, &mut ControlFlow),
{
let mut runner = EventLoopRunner::new(event_loop, self.redraw_buffer.clone(), f);
{
@ -66,7 +66,18 @@ impl<T> ELRShared<T> {
}
}
pub(crate) unsafe fn send_event(&self, event: Event<T>) {
pub(crate) unsafe fn send_event(&self, event: Event<'static, T>) {
if let Err(event) = self.send_event_unbuffered(event) {
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.buffer_event(event);
}
}
pub(crate) unsafe fn send_event_unbuffered<'e>(
&self,
event: Event<'e, T>,
) -> Result<(), Event<'e, T>> {
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
if let Some(ref mut runner) = *runner_ref {
runner.process_event(event);
@ -84,16 +95,14 @@ impl<T> ELRShared<T> {
}
}
return;
return Ok(());
}
}
// If the runner is already borrowed, we're in the middle of an event loop invocation. Add
// the event to a buffer to be processed later.
self.buffer_event(event);
Err(event)
}
pub(crate) unsafe fn call_event_handler(&self, event: Event<T>) {
pub(crate) unsafe fn call_event_handler(&self, event: Event<'static, T>) {
if let Ok(mut runner_ref) = self.runner.try_borrow_mut() {
if let Some(ref mut runner) = *runner_ref {
runner.call_event_handler(event);
@ -143,7 +152,7 @@ impl<T> ELRShared<T> {
}
}
fn buffer_event(&self, event: Event<T>) {
fn buffer_event(&self, event: Event<'static, T>) {
match event {
Event::RedrawRequested(window_id) => {
self.redraw_buffer.borrow_mut().push_back(window_id)
@ -176,7 +185,7 @@ impl<T> EventLoopRunner<T> {
f: F,
) -> EventLoopRunner<T>
where
F: FnMut(Event<T>, &mut ControlFlow),
F: FnMut(Event<'_, T>, &mut ControlFlow),
{
EventLoopRunner {
control_flow: ControlFlow::default(),
@ -184,8 +193,8 @@ impl<T> EventLoopRunner<T> {
in_modal_loop: false,
modal_redraw_window: event_loop.window_target.p.thread_msg_target,
event_handler: mem::transmute::<
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>,
Box<dyn FnMut(Event<'_, T>, &mut ControlFlow)>,
>(Box::new(f)),
panic_error: None,
redraw_buffer,
@ -251,7 +260,7 @@ impl<T> EventLoopRunner<T> {
};
}
fn process_event(&mut self, event: Event<T>) {
fn process_event(&mut self, event: Event<'_, T>) {
// If we're in the modal loop, we need to have some mechanism for finding when the event
// queue has been cleared so we can call `events_cleared`. Windows doesn't give any utilities
// for doing this, but it DOES guarantee that WM_PAINT will only occur after input events have
@ -390,7 +399,7 @@ impl<T> EventLoopRunner<T> {
}
}
fn call_event_handler(&mut self, event: Event<T>) {
fn call_event_handler(&mut self, event: Event<'_, T>) {
if self.panic_error.is_none() {
let EventLoopRunner {
ref mut panic_error,

View file

@ -168,14 +168,6 @@ impl MonitorHandle {
MonitorHandle(hmonitor)
}
pub(crate) fn contains_point(&self, point: &POINT) -> bool {
let monitor_info = get_monitor_info(self.0).unwrap();
point.x >= monitor_info.rcMonitor.left
&& point.x <= monitor_info.rcMonitor.right
&& point.y >= monitor_info.rcMonitor.top
&& point.y <= monitor_info.rcMonitor.bottom
}
#[inline]
pub fn name(&self) -> Option<String> {
let monitor_info = get_monitor_info(self.0).unwrap();
@ -196,8 +188,8 @@ impl MonitorHandle {
pub fn size(&self) -> PhysicalSize {
let monitor_info = get_monitor_info(self.0).unwrap();
PhysicalSize {
width: (monitor_info.rcMonitor.right - monitor_info.rcMonitor.left) as f64,
height: (monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top) as f64,
width: (monitor_info.rcMonitor.right - monitor_info.rcMonitor.left) as u32,
height: (monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top) as u32,
}
}

View file

@ -11,7 +11,7 @@ use winapi::{
ctypes::wchar_t,
shared::{
minwindef::{BOOL, DWORD},
windef::{HWND, POINT, RECT},
windef::{HWND, RECT},
},
um::{
libloaderapi::{GetProcAddress, LoadLibraryA},
@ -85,10 +85,6 @@ fn win_to_err<F: FnOnce() -> BOOL>(f: F) -> Result<(), io::Error> {
}
}
pub fn get_cursor_pos() -> Option<POINT> {
unsafe { status_map(|cursor_pos| winuser::GetCursorPos(cursor_pos)) }
}
pub fn get_window_rect(hwnd: HWND) -> Option<RECT> {
unsafe { status_map(|rect| winuser::GetWindowRect(hwnd, rect)) }
}

View file

@ -14,7 +14,7 @@ use std::{
use winapi::{
ctypes::c_int,
shared::{
minwindef::{DWORD, HINSTANCE, LPARAM, UINT, WORD, WPARAM},
minwindef::{DWORD, HINSTANCE, UINT},
windef::{HWND, POINT, RECT},
},
um::{
@ -30,14 +30,16 @@ use winapi::{
};
use crate::{
dpi::{LogicalPosition, LogicalSize, PhysicalSize},
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error::{ExternalError, NotSupportedError, OsError as RootOsError},
monitor::MonitorHandle as RootMonitorHandle,
platform_impl::platform::{
dark_mode::try_dark_mode,
dpi::{dpi_to_scale_factor, hwnd_dpi},
drop_handler::FileDropHandler,
event_loop::{self, EventLoopWindowTarget, DESTROY_MSG_ID, INITIAL_DPI_MSG_ID},
event_loop::{
self, EventLoopWindowTarget, DESTROY_MSG_ID,
},
icon::{self, IconType, WinIcon},
monitor, util,
window_state::{CursorFlags, SavedWindow, WindowFlags, WindowState},
@ -125,8 +127,8 @@ impl Window {
#[inline]
pub fn set_visible(&self, visible: bool) {
let window_state = Arc::clone(&self.window_state);
let window = self.window.clone();
let window_state = Arc::clone(&self.window_state);
self.thread_executor.execute_in_thread(move || {
WindowState::set_window_flags(window_state.lock(), window.0, |f| {
f.set(WindowFlags::VISIBLE, visible)
@ -146,41 +148,34 @@ impl Window {
}
}
pub(crate) fn outer_position_physical(&self) -> (i32, i32) {
#[inline]
pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
util::get_window_rect(self.window.0)
.map(|rect| (rect.left as i32, rect.top as i32))
.unwrap()
.map(|rect| Ok(PhysicalPosition::new(rect.left as f64, rect.top as f64)))
.expect("Unexpected GetWindowRect failure; please report this error to https://github.com/rust-windowing/winit")
}
#[inline]
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
let physical_position = self.outer_position_physical();
let dpi_factor = self.hidpi_factor();
Ok(LogicalPosition::from_physical(
physical_position,
dpi_factor,
))
}
pub(crate) fn inner_position_physical(&self) -> (i32, i32) {
pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
let mut position: POINT = unsafe { mem::zeroed() };
if unsafe { winuser::ClientToScreen(self.window.0, &mut position) } == 0 {
panic!("Unexpected ClientToScreen failure: please report this error to https://github.com/rust-windowing/winit")
}
(position.x, position.y)
Ok(PhysicalPosition::new(position.x as f64, position.y as f64))
}
#[inline]
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
let physical_position = self.inner_position_physical();
let dpi_factor = self.hidpi_factor();
Ok(LogicalPosition::from_physical(
physical_position,
dpi_factor,
))
}
pub fn set_outer_position(&self, position: Position) {
let (x, y): (i32, i32) = position.to_physical(self.hidpi_factor()).into();
let window_state = Arc::clone(&self.window_state);
let window = self.window.clone();
self.thread_executor.execute_in_thread(move || {
WindowState::set_window_flags(window_state.lock(), window.0, |f| {
f.set(WindowFlags::MAXIMIZED, false)
});
});
pub(crate) fn set_position_physical(&self, x: i32, y: i32) {
unsafe {
winuser::SetWindowPos(
self.window.0,
@ -199,43 +194,22 @@ impl Window {
}
#[inline]
pub fn set_outer_position(&self, logical_position: LogicalPosition) {
let dpi_factor = self.hidpi_factor();
let (x, y) = logical_position.to_physical(dpi_factor).into();
let window_state = Arc::clone(&self.window_state);
let window = self.window.clone();
self.thread_executor.execute_in_thread(move || {
WindowState::set_window_flags(window_state.lock(), window.0, |f| {
f.set(WindowFlags::MAXIMIZED, false)
});
});
self.set_position_physical(x, y);
}
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
pub fn inner_size(&self) -> PhysicalSize {
let mut rect: RECT = unsafe { mem::zeroed() };
if unsafe { winuser::GetClientRect(self.window.0, &mut rect) } == 0 {
panic!("Unexpected GetClientRect failure: please report this error to https://github.com/rust-windowing/winit")
}
(
PhysicalSize::new(
(rect.right - rect.left) as u32,
(rect.bottom - rect.top) as u32,
)
}
#[inline]
pub fn inner_size(&self) -> LogicalSize {
let physical_size = self.inner_size_physical();
let dpi_factor = self.hidpi_factor();
LogicalSize::from_physical(physical_size, dpi_factor)
}
pub(crate) fn outer_size_physical(&self) -> (u32, u32) {
pub fn outer_size(&self) -> PhysicalSize {
util::get_window_rect(self.window.0)
.map(|rect| {
(
PhysicalSize::new(
(rect.right - rect.left) as u32,
(rect.bottom - rect.top) as u32,
)
@ -243,13 +217,6 @@ impl Window {
.unwrap()
}
#[inline]
pub fn outer_size(&self) -> LogicalSize {
let physical_size = self.outer_size_physical();
let dpi_factor = self.hidpi_factor();
LogicalSize::from_physical(physical_size, dpi_factor)
}
pub(crate) fn set_inner_size_physical(&self, x: u32, y: u32) {
unsafe {
let rect = util::adjust_window_rect(
@ -283,9 +250,9 @@ impl Window {
}
#[inline]
pub fn set_inner_size(&self, logical_size: LogicalSize) {
pub fn set_inner_size(&self, size: Size) {
let dpi_factor = self.hidpi_factor();
let (width, height) = logical_size.to_physical(dpi_factor).into();
let (width, height) = size.to_physical(dpi_factor).into();
let window_state = Arc::clone(&self.window_state);
let window = self.window.clone();
@ -298,36 +265,20 @@ impl Window {
self.set_inner_size_physical(width, height);
}
pub(crate) fn set_min_inner_size_physical(&self, dimensions: Option<(u32, u32)>) {
self.window_state.lock().min_size = dimensions.map(Into::into);
#[inline]
pub fn set_min_inner_size(&self, size: Option<Size>) {
self.window_state.lock().min_size = size;
// Make windows re-check the window size bounds.
let (width, height) = self.inner_size_physical();
self.set_inner_size_physical(width, height);
let size = self.inner_size();
self.set_inner_size(size.into());
}
#[inline]
pub fn set_min_inner_size(&self, logical_size: Option<LogicalSize>) {
let physical_size = logical_size.map(|logical_size| {
let dpi_factor = self.hidpi_factor();
logical_size.to_physical(dpi_factor).into()
});
self.set_min_inner_size_physical(physical_size);
}
pub fn set_max_inner_size_physical(&self, dimensions: Option<(u32, u32)>) {
self.window_state.lock().max_size = dimensions.map(Into::into);
pub fn set_max_inner_size(&self, size: Option<Size>) {
self.window_state.lock().max_size = size;
// Make windows re-check the window size bounds.
let (width, height) = self.inner_size_physical();
self.set_inner_size_physical(width, height);
}
#[inline]
pub fn set_max_inner_size(&self, logical_size: Option<LogicalSize>) {
let physical_size = logical_size.map(|logical_size| {
let dpi_factor = self.hidpi_factor();
logical_size.to_physical(dpi_factor).into()
});
self.set_max_inner_size_physical(physical_size);
let size = self.inner_size();
self.set_inner_size(size.into());
}
#[inline]
@ -411,7 +362,11 @@ impl Window {
self.window_state.lock().dpi_factor
}
fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> {
#[inline]
pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
let dpi_factor = self.hidpi_factor();
let (x, y) = position.to_physical(dpi_factor).into();
let mut point = POINT { x, y };
unsafe {
if winuser::ClientToScreen(self.window.0, &mut point) == 0 {
@ -424,16 +379,6 @@ impl Window {
Ok(())
}
#[inline]
pub fn set_cursor_position(
&self,
logical_position: LogicalPosition,
) -> Result<(), ExternalError> {
let dpi_factor = self.hidpi_factor();
let (x, y) = logical_position.to_physical(dpi_factor).into();
self.set_cursor_position_physical(x, y)
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId(self.window.0)
@ -691,7 +636,7 @@ impl Window {
}
#[inline]
pub fn set_ime_position(&self, _logical_spot: LogicalPosition) {
pub fn set_ime_position(&self, _position: Position) {
unimplemented!();
}
@ -770,41 +715,6 @@ unsafe fn init<T: 'static>(
// registering the window class
let class_name = register_window_class(&window_icon, &taskbar_icon);
let guessed_dpi_factor = {
let monitors = monitor::available_monitors();
let dpi_factor = if !monitors.is_empty() {
let mut dpi_factor = Some(monitors[0].hidpi_factor());
for monitor in &monitors {
if Some(monitor.hidpi_factor()) != dpi_factor {
dpi_factor = None;
}
}
dpi_factor
} else {
return Err(os_error!(io::Error::new(
io::ErrorKind::NotFound,
"No monitors were detected."
)));
};
dpi_factor.unwrap_or_else(|| {
util::get_cursor_pos()
.and_then(|cursor_pos| {
let mut dpi_factor = None;
for monitor in &monitors {
if monitor.contains_point(&cursor_pos) {
dpi_factor = Some(monitor.hidpi_factor());
break;
}
}
dpi_factor
})
.unwrap_or(1.0)
})
};
info!("Guessed window DPI factor: {}", guessed_dpi_factor);
let dimensions = attributes.inner_size.unwrap_or_else(|| (1024, 768).into());
let mut window_flags = WindowFlags::empty();
window_flags.set(WindowFlags::DECORATIONS, attributes.decorations);
window_flags.set(WindowFlags::ALWAYS_ON_TOP, attributes.always_on_top);
@ -853,20 +763,6 @@ unsafe fn init<T: 'static>(
let dpi = hwnd_dpi(real_window.0);
let dpi_factor = dpi_to_scale_factor(dpi);
if dpi_factor != guessed_dpi_factor {
let (width, height): (u32, u32) = dimensions.into();
let mut packed_dimensions = 0;
// MAKELPARAM isn't provided by winapi yet.
let ptr = &mut packed_dimensions as *mut LPARAM as *mut WORD;
*ptr.offset(0) = width as WORD;
*ptr.offset(1) = height as WORD;
winuser::PostMessageW(
real_window.0,
*INITIAL_DPI_MSG_ID,
dpi as WPARAM,
packed_dimensions,
);
}
// making the window transparent
if attributes.transparent && !pl_attribs.no_redirection_bitmap {
@ -900,7 +796,6 @@ unsafe fn init<T: 'static>(
}
}
window_flags.set(WindowFlags::VISIBLE, attributes.visible);
window_flags.set(WindowFlags::MAXIMIZED, attributes.maximized);
// If the system theme is dark, we need to set the window theme now
@ -927,15 +822,17 @@ unsafe fn init<T: 'static>(
thread_executor: event_loop.create_thread_executor(),
};
let dimensions = attributes
.inner_size
.unwrap_or_else(|| PhysicalSize::new(1024, 768).into());
win.set_inner_size(dimensions);
win.set_visible(attributes.visible);
if let Some(_) = attributes.fullscreen {
win.set_fullscreen(attributes.fullscreen);
force_window_active(win.window.0);
}
if let Some(dimensions) = attributes.inner_size {
win.set_inner_size(dimensions);
}
Ok(win)
}

View file

@ -1,5 +1,5 @@
use crate::{
dpi::LogicalSize,
dpi::Size,
platform_impl::platform::{event_loop, icon::WinIcon, util},
window::{CursorIcon, Fullscreen, WindowAttributes},
};
@ -19,8 +19,8 @@ pub struct WindowState {
pub mouse: MouseProperties,
/// Used by `WM_GETMINMAXINFO`.
pub min_size: Option<LogicalSize>,
pub max_size: Option<LogicalSize>,
pub min_size: Option<Size>,
pub max_size: Option<Size>,
pub window_icon: Option<WinIcon>,
pub taskbar_icon: Option<WinIcon>,