diff --git a/crates/gpui/src/platform/windows/display.rs b/crates/gpui/src/platform/windows/display.rs index e333269cdc..3bbbe36489 100644 --- a/crates/gpui/src/platform/windows/display.rs +++ b/crates/gpui/src/platform/windows/display.rs @@ -5,42 +5,55 @@ use util::ResultExt; use uuid::Uuid; use windows::{ core::*, - Win32::{Foundation::*, Graphics::Gdi::*}, + Win32::{ + Foundation::*, + Graphics::Gdi::*, + UI::{ + HiDpi::{GetDpiForMonitor, MDT_EFFECTIVE_DPI}, + WindowsAndMessaging::USER_DEFAULT_SCREEN_DPI, + }, + }, }; -use crate::{px, Bounds, DisplayId, Pixels, PlatformDisplay, Point, Size}; +use crate::{logical_point, point, size, Bounds, DevicePixels, DisplayId, Pixels, PlatformDisplay}; #[derive(Debug, Clone, Copy)] pub(crate) struct WindowsDisplay { pub handle: HMONITOR, pub display_id: DisplayId, + scale_factor: f32, bounds: Bounds, + physical_bounds: Bounds, uuid: Uuid, } impl WindowsDisplay { pub(crate) fn new(display_id: DisplayId) -> Option { - let Some(screen) = available_monitors().into_iter().nth(display_id.0 as _) else { - return None; - }; - let Ok(info) = get_monitor_info(screen).inspect_err(|e| log::error!("{}", e)) else { - return None; - }; - let size = info.monitorInfo.rcMonitor; + let screen = available_monitors().into_iter().nth(display_id.0 as _)?; + let info = get_monitor_info(screen).log_err()?; + let monitor_size = info.monitorInfo.rcMonitor; let uuid = generate_uuid(&info.szDevice); + let scale_factor = get_scale_factor_for_monitor(screen).log_err()?; + let physical_size = size( + (monitor_size.right - monitor_size.left).into(), + (monitor_size.bottom - monitor_size.top).into(), + ); Some(WindowsDisplay { handle: screen, display_id, + scale_factor, bounds: Bounds { - origin: Point { - x: px(size.left as f32), - y: px(size.top as f32), - }, - size: Size { - width: px((size.right - size.left) as f32), - height: px((size.bottom - size.top) as f32), - }, + origin: logical_point( + monitor_size.left as f32, + monitor_size.top as f32, + scale_factor, + ), + size: physical_size.to_pixels(scale_factor), + }, + physical_bounds: Bounds { + origin: point(monitor_size.left.into(), monitor_size.top.into()), + size: physical_size, }, uuid, }) @@ -48,25 +61,34 @@ impl WindowsDisplay { pub fn new_with_handle(monitor: HMONITOR) -> Self { let info = get_monitor_info(monitor).expect("unable to get monitor info"); - let size = info.monitorInfo.rcMonitor; + let monitor_size = info.monitorInfo.rcMonitor; let uuid = generate_uuid(&info.szDevice); let display_id = available_monitors() .iter() .position(|handle| handle.0 == monitor.0) .unwrap(); + let scale_factor = + get_scale_factor_for_monitor(monitor).expect("unable to get scale factor for monitor"); + let physical_size = size( + (monitor_size.right - monitor_size.left).into(), + (monitor_size.bottom - monitor_size.top).into(), + ); WindowsDisplay { handle: monitor, display_id: DisplayId(display_id as _), + scale_factor, bounds: Bounds { - origin: Point { - x: px(size.left as f32), - y: px(size.top as f32), - }, - size: Size { - width: px((size.right - size.left) as f32), - height: px((size.bottom - size.top) as f32), - }, + origin: logical_point( + monitor_size.left as f32, + monitor_size.top as f32, + scale_factor, + ), + size: physical_size.to_pixels(scale_factor), + }, + physical_bounds: Bounds { + origin: point(monitor_size.left.into(), monitor_size.top.into()), + size: physical_size, }, uuid, } @@ -74,21 +96,30 @@ impl WindowsDisplay { fn new_with_handle_and_id(handle: HMONITOR, display_id: DisplayId) -> Self { let info = get_monitor_info(handle).expect("unable to get monitor info"); - let size = info.monitorInfo.rcMonitor; + let monitor_size = info.monitorInfo.rcMonitor; let uuid = generate_uuid(&info.szDevice); + let scale_factor = + get_scale_factor_for_monitor(handle).expect("unable to get scale factor for monitor"); + let physical_size = size( + (monitor_size.right - monitor_size.left).into(), + (monitor_size.bottom - monitor_size.top).into(), + ); WindowsDisplay { handle, display_id, + scale_factor, bounds: Bounds { - origin: Point { - x: px(size.left as f32), - y: px(size.top as f32), - }, - size: Size { - width: px((size.right - size.left) as f32), - height: px((size.bottom - size.top) as f32), - }, + origin: logical_point( + monitor_size.left as f32, + monitor_size.top as f32, + scale_factor, + ), + size: physical_size.to_pixels(scale_factor), + }, + physical_bounds: Bounds { + origin: point(monitor_size.left.into(), monitor_size.top.into()), + size: physical_size, }, uuid, } @@ -112,8 +143,8 @@ impl WindowsDisplay { pub fn check_given_bounds(&self, bounds: Bounds) -> bool { let center = bounds.center(); let center = POINT { - x: center.x.0 as i32, - y: center.y.0 as i32, + x: (center.x.0 * self.scale_factor) as i32, + y: (center.y.0 * self.scale_factor) as i32, }; let monitor = unsafe { MonitorFromPoint(center, MONITOR_DEFAULTTONULL) }; if monitor.is_invalid() { @@ -156,6 +187,10 @@ impl WindowsDisplay { pub fn is_connected(hmonitor: HMONITOR) -> bool { available_monitors().iter().contains(&hmonitor) } + + pub fn physical_bounds(&self) -> Bounds { + self.physical_bounds + } } impl PlatformDisplay for WindowsDisplay { @@ -221,3 +256,11 @@ fn generate_uuid(device_name: &[u16]) -> Uuid { .collect_vec(); Uuid::new_v5(&Uuid::NAMESPACE_DNS, &name) } + +fn get_scale_factor_for_monitor(monitor: HMONITOR) -> Result { + let mut dpi_x = 0; + let mut dpi_y = 0; + unsafe { GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &mut dpi_x, &mut dpi_y) }?; + assert_eq!(dpi_x, dpi_y); + Ok(dpi_x as f32 / USER_DEFAULT_SCREEN_DPI as f32) +} diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 560f2d39aa..f849215dce 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -98,13 +98,16 @@ fn handle_move_msg( lparam: LPARAM, state_ptr: Rc, ) -> Option { - let x = lparam.signed_loword() as f32; - let y = lparam.signed_hiword() as f32; let mut lock = state_ptr.state.borrow_mut(); - lock.origin = point(px(x), px(y)); - let size = lock.physical_size; - let center_x = x + size.width.0 / 2.; - let center_y = y + size.height.0 / 2.; + 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 @@ -135,8 +138,8 @@ fn handle_size_msg(lparam: LPARAM, state_ptr: Rc) -> Opti let new_size = size(DevicePixels(width), DevicePixels(height)); let scale_factor = lock.scale_factor; lock.renderer.update_drawable_size(new_size); - let new_size = new_size.to_pixels(lock.scale_factor); - lock.physical_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); diff --git a/crates/gpui/src/platform/windows/util.rs b/crates/gpui/src/platform/windows/util.rs index 2c8ccf5e08..ba2d9ff7b2 100644 --- a/crates/gpui/src/platform/windows/util.rs +++ b/crates/gpui/src/platform/windows/util.rs @@ -111,14 +111,6 @@ pub(crate) fn load_cursor(style: CursorStyle) -> HCURSOR { }) } -#[inline] -pub(crate) fn logical_size(physical_size: Size, scale_factor: f32) -> Size { - Size { - width: px(physical_size.width.0 as f32 / scale_factor), - height: px(physical_size.height.0 as f32 / scale_factor), - } -} - #[inline] pub(crate) fn logical_point(x: f32, y: f32, scale_factor: f32) -> Point { Point { diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 40415e8f17..eedb32cc2e 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -27,13 +27,13 @@ use windows::{ }; use crate::platform::blade::BladeRenderer; -use crate::{Pixels, *}; +use crate::*; pub(crate) struct WindowsWindow(pub Rc); pub struct WindowsWindowState { pub origin: Point, - pub physical_size: Size, + pub logical_size: Size, pub fullscreen_restore_bounds: Bounds, pub scale_factor: f32, @@ -68,16 +68,19 @@ impl WindowsWindowState { current_cursor: HCURSOR, display: WindowsDisplay, ) -> Self { - let origin = point(px(cs.x as f32), px(cs.y as f32)); - let physical_size = size(px(cs.cx as f32), px(cs.cy as f32)); - let fullscreen_restore_bounds = Bounds { - origin, - size: physical_size, - }; let scale_factor = { let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32; monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32 }; + let origin = logical_point(cs.x as f32, cs.y as f32, scale_factor); + let logical_size = { + let physical_size = size(DevicePixels(cs.cx), DevicePixels(cs.cy)); + physical_size.to_pixels(scale_factor) + }; + let fullscreen_restore_bounds = Bounds { + origin, + size: logical_size, + }; let renderer = windows_renderer::windows_renderer(hwnd, transparent); let callbacks = Callbacks::default(); let input_handler = None; @@ -88,7 +91,7 @@ impl WindowsWindowState { Self { origin, - physical_size, + logical_size, fullscreen_restore_bounds, scale_factor, callbacks, @@ -116,7 +119,7 @@ impl WindowsWindowState { fn bounds(&self) -> Bounds { Bounds { origin: self.origin, - size: self.physical_size, + size: self.logical_size, } } @@ -129,15 +132,17 @@ impl WindowsWindowState { GetWindowPlacement(self.hwnd, &mut placement).log_err(); placement }; + let physical_size = size( + DevicePixels(placement.rcNormalPosition.right - placement.rcNormalPosition.left), + DevicePixels(placement.rcNormalPosition.bottom - placement.rcNormalPosition.top), + ); let bounds = Bounds { - origin: point( - px(placement.rcNormalPosition.left as f32), - px(placement.rcNormalPosition.top as f32), - ), - size: size( - px((placement.rcNormalPosition.right - placement.rcNormalPosition.left) as f32), - px((placement.rcNormalPosition.bottom - placement.rcNormalPosition.top) as f32), + origin: logical_point( + placement.rcNormalPosition.left as f32, + placement.rcNormalPosition.top as f32, + self.scale_factor, ), + size: physical_size.to_pixels(self.scale_factor), }; if self.is_fullscreen() { @@ -154,7 +159,7 @@ impl WindowsWindowState { /// Currently, GPUI uses logical size of the app to handle mouse interactions (such as /// whether the mouse collides with other elements of GPUI). fn content_size(&self) -> Size { - self.physical_size + self.logical_size } fn title_bar_padding(&self) -> Pixels { @@ -538,7 +543,7 @@ impl PlatformWindow for WindowsWindow { let mut lock = state_ptr.state.borrow_mut(); lock.fullscreen_restore_bounds = Bounds { origin: lock.origin, - size: lock.physical_size, + size: lock.logical_size, }; let StyleAndBounds { style, @@ -555,10 +560,10 @@ impl PlatformWindow for WindowsWindow { unsafe { GetWindowRect(state_ptr.hwnd, &mut rc) }.log_err(); let _ = lock.fullscreen.insert(StyleAndBounds { style, - x: px(rc.left as f32), - y: px(rc.top as f32), - cx: px((rc.right - rc.left) as f32), - cy: px((rc.bottom - rc.top) as f32), + x: rc.left, + y: rc.top, + cx: rc.right - rc.left, + cy: rc.bottom - rc.top, }); let style = style & !(WS_THICKFRAME @@ -566,13 +571,13 @@ impl PlatformWindow for WindowsWindow { | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_CAPTION); - let bounds = lock.display.bounds(); + let physical_bounds = lock.display.physical_bounds(); StyleAndBounds { style, - x: bounds.left(), - y: bounds.top(), - cx: bounds.size.width, - cy: bounds.size.height, + x: physical_bounds.left().0, + y: physical_bounds.top().0, + cx: physical_bounds.size.width.0, + cy: physical_bounds.size.height.0, } }; drop(lock); @@ -581,10 +586,10 @@ impl PlatformWindow for WindowsWindow { SetWindowPos( state_ptr.hwnd, HWND::default(), - x.0 as i32, - y.0 as i32, - cx.0 as i32, - cy.0 as i32, + x, + y, + cx, + cy, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER, ) } @@ -837,10 +842,10 @@ impl ClickState { struct StyleAndBounds { style: WINDOW_STYLE, - x: Pixels, - y: Pixels, - cx: Pixels, - cy: Pixels, + x: i32, + y: i32, + cx: i32, + cy: i32, } fn register_wnd_class(icon_handle: HICON) -> PCWSTR {