windows: Fix regression introduced by a prev PR (#13090)

Fix regression introduced by #12991 

### Before

The re-position and re-size of a window is broken.


https://github.com/zed-industries/zed/assets/14981363/d4fb9dce-707e-4ab1-9ff5-f355b7fdd8a8

### After



https://github.com/zed-industries/zed/assets/14981363/7fd232e6-ff6c-4b7f-ad32-c284acd4f6db




Release Notes:

- N/A
This commit is contained in:
张小白 2024-06-18 03:01:35 +08:00 committed by GitHub
parent bb75d87285
commit e19627d92f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 132 additions and 89 deletions

View File

@ -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<Pixels>,
physical_bounds: Bounds<DevicePixels>,
uuid: Uuid,
}
impl WindowsDisplay {
pub(crate) fn new(display_id: DisplayId) -> Option<Self> {
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<Pixels>) -> 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<DevicePixels> {
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<f32> {
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)
}

View File

@ -98,13 +98,16 @@ fn handle_move_msg(
lparam: LPARAM,
state_ptr: Rc<WindowsWindowStatePtr>,
) -> Option<isize> {
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<WindowsWindowStatePtr>) -> 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);

View File

@ -111,14 +111,6 @@ pub(crate) fn load_cursor(style: CursorStyle) -> HCURSOR {
})
}
#[inline]
pub(crate) fn logical_size(physical_size: Size<DevicePixels>, scale_factor: f32) -> Size<Pixels> {
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<Pixels> {
Point {

View File

@ -27,13 +27,13 @@ use windows::{
};
use crate::platform::blade::BladeRenderer;
use crate::{Pixels, *};
use crate::*;
pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
pub struct WindowsWindowState {
pub origin: Point<Pixels>,
pub physical_size: Size<Pixels>,
pub logical_size: Size<Pixels>,
pub fullscreen_restore_bounds: Bounds<Pixels>,
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<Pixels> {
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<Pixels> {
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 {