windows: Return client size and position from window_bounds
(#14228)
This is a follow up of #14218 , since we open the window based on the size of the client area, `window_bounds` should also return the size of the client area to maintain consistency. Release Notes: - N/A
This commit is contained in:
parent
85d77a3eec
commit
0a718c65e2
2 changed files with 94 additions and 43 deletions
|
@ -82,7 +82,7 @@ pub(crate) fn handle_msg(
|
|||
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(state_ptr),
|
||||
WM_SETTINGCHANGE => handle_system_settings_changed(handle, state_ptr),
|
||||
CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
||||
_ => None,
|
||||
};
|
||||
|
@ -732,7 +732,10 @@ fn handle_dpi_changed_msg(
|
|||
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||
) -> Option<isize> {
|
||||
let new_dpi = wparam.loword() as f32;
|
||||
state_ptr.state.borrow_mut().scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
|
||||
let mut lock = state_ptr.state.borrow_mut();
|
||||
lock.scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
|
||||
lock.border_offset.udpate(handle).log_err();
|
||||
drop(lock);
|
||||
|
||||
let rect = unsafe { &*(lparam.0 as *const RECT) };
|
||||
let width = rect.right - rect.left;
|
||||
|
@ -1050,12 +1053,17 @@ fn handle_set_cursor(lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Op
|
|||
Some(1)
|
||||
}
|
||||
|
||||
fn handle_system_settings_changed(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
||||
fn handle_system_settings_changed(
|
||||
handle: HWND,
|
||||
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||
) -> Option<isize> {
|
||||
let mut lock = state_ptr.state.borrow_mut();
|
||||
// mouse wheel
|
||||
lock.system_settings.mouse_wheel_settings.update();
|
||||
// mouse double click
|
||||
lock.click_state.system_update();
|
||||
// window border offset
|
||||
lock.border_offset.udpate(handle).log_err();
|
||||
Some(0)
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ pub struct WindowsWindowState {
|
|||
pub origin: Point<Pixels>,
|
||||
pub logical_size: Size<Pixels>,
|
||||
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
||||
pub border_offset: WindowBorderOffset,
|
||||
pub scale_factor: f32,
|
||||
|
||||
pub callbacks: Callbacks,
|
||||
|
@ -82,6 +83,7 @@ impl WindowsWindowState {
|
|||
origin,
|
||||
size: logical_size,
|
||||
};
|
||||
let border_offset = WindowBorderOffset::default();
|
||||
let renderer = windows_renderer::windows_renderer(hwnd, transparent);
|
||||
let callbacks = Callbacks::default();
|
||||
let input_handler = None;
|
||||
|
@ -94,6 +96,7 @@ impl WindowsWindowState {
|
|||
origin,
|
||||
logical_size,
|
||||
fullscreen_restore_bounds,
|
||||
border_offset,
|
||||
scale_factor,
|
||||
callbacks,
|
||||
input_handler,
|
||||
|
@ -124,7 +127,8 @@ impl WindowsWindowState {
|
|||
}
|
||||
}
|
||||
|
||||
fn window_bounds(&self) -> WindowBounds {
|
||||
// Calculate the bounds used for saving and whether the window is maximized.
|
||||
fn calculate_window_bounds(&self) -> (Bounds<Pixels>, bool) {
|
||||
let placement = unsafe {
|
||||
let mut placement = WINDOWPLACEMENT {
|
||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
||||
|
@ -133,22 +137,22 @@ 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: logical_point(
|
||||
placement.rcNormalPosition.left as f32,
|
||||
placement.rcNormalPosition.top as f32,
|
||||
(
|
||||
calculate_client_rect(
|
||||
placement.rcNormalPosition,
|
||||
self.border_offset,
|
||||
self.scale_factor,
|
||||
),
|
||||
size: physical_size.to_pixels(self.scale_factor),
|
||||
};
|
||||
placement.showCmd == SW_SHOWMAXIMIZED.0 as u32,
|
||||
)
|
||||
}
|
||||
|
||||
fn window_bounds(&self) -> WindowBounds {
|
||||
let (bounds, maximized) = self.calculate_window_bounds();
|
||||
|
||||
if self.is_fullscreen() {
|
||||
WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
|
||||
} else if placement.showCmd == SW_SHOWMAXIMIZED.0 as u32 {
|
||||
} else if maximized {
|
||||
WindowBounds::Maximized(bounds)
|
||||
} else {
|
||||
WindowBounds::Windowed(bounds)
|
||||
|
@ -308,7 +312,6 @@ impl WindowsWindow {
|
|||
};
|
||||
let state_ptr = Rc::clone(context.inner.as_ref().unwrap());
|
||||
register_drag_drop(state_ptr.clone());
|
||||
let wnd = Self(state_ptr);
|
||||
|
||||
unsafe {
|
||||
let mut placement = WINDOWPLACEMENT {
|
||||
|
@ -322,13 +325,16 @@ impl WindowsWindow {
|
|||
} else {
|
||||
display.default_bounds()
|
||||
};
|
||||
let bounds = bounds.to_device_pixels(wnd.0.state.borrow().scale_factor);
|
||||
placement.rcNormalPosition = calcualte_window_position(bounds, raw_hwnd).unwrap();
|
||||
let mut lock = state_ptr.state.borrow_mut();
|
||||
let bounds = bounds.to_device_pixels(lock.scale_factor);
|
||||
lock.border_offset.udpate(raw_hwnd).unwrap();
|
||||
placement.rcNormalPosition = calcualte_window_rect(bounds, lock.border_offset);
|
||||
drop(lock);
|
||||
SetWindowPlacement(raw_hwnd, &placement).log_err();
|
||||
}
|
||||
unsafe { ShowWindow(raw_hwnd, SW_SHOW).ok().log_err() };
|
||||
|
||||
wnd
|
||||
Self(state_ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -544,10 +550,6 @@ impl PlatformWindow for WindowsWindow {
|
|||
.executor
|
||||
.spawn(async move {
|
||||
let mut lock = state_ptr.state.borrow_mut();
|
||||
lock.fullscreen_restore_bounds = Bounds {
|
||||
origin: lock.origin,
|
||||
size: lock.logical_size,
|
||||
};
|
||||
let StyleAndBounds {
|
||||
style,
|
||||
x,
|
||||
|
@ -557,6 +559,8 @@ impl PlatformWindow for WindowsWindow {
|
|||
} = if let Some(state) = lock.fullscreen.take() {
|
||||
state
|
||||
} else {
|
||||
let (window_bounds, _) = lock.calculate_window_bounds();
|
||||
lock.fullscreen_restore_bounds = window_bounds;
|
||||
let style =
|
||||
WINDOW_STYLE(unsafe { get_window_long(state_ptr.hwnd, GWL_STYLE) } as _);
|
||||
let mut rc = RECT::default();
|
||||
|
@ -861,6 +865,32 @@ struct StyleAndBounds {
|
|||
cy: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub(crate) struct WindowBorderOffset {
|
||||
width_offset: i32,
|
||||
height_offset: i32,
|
||||
}
|
||||
|
||||
impl WindowBorderOffset {
|
||||
pub(crate) fn udpate(&mut self, hwnd: HWND) -> anyhow::Result<()> {
|
||||
let window_rect = unsafe {
|
||||
let mut rect = std::mem::zeroed();
|
||||
GetWindowRect(hwnd, &mut rect)?;
|
||||
rect
|
||||
};
|
||||
let client_rect = unsafe {
|
||||
let mut rect = std::mem::zeroed();
|
||||
GetClientRect(hwnd, &mut rect)?;
|
||||
rect
|
||||
};
|
||||
self.width_offset =
|
||||
(window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
|
||||
self.height_offset =
|
||||
(window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn register_wnd_class(icon_handle: HICON) -> PCWSTR {
|
||||
const CLASS_NAME: PCWSTR = w!("Zed::Window");
|
||||
|
||||
|
@ -955,36 +985,49 @@ fn register_drag_drop(state_ptr: Rc<WindowsWindowStatePtr>) {
|
|||
};
|
||||
}
|
||||
|
||||
fn calcualte_window_position(bounds: Bounds<DevicePixels>, hwnd: HWND) -> anyhow::Result<RECT> {
|
||||
fn calcualte_window_rect(bounds: Bounds<DevicePixels>, border_offset: WindowBorderOffset) -> RECT {
|
||||
// NOTE:
|
||||
// The reason that not using `AdjustWindowRectEx()` here is
|
||||
// that the size reported by this function is incorrect.
|
||||
// You can test it, and there are similar discussions online.
|
||||
// See: https://stackoverflow.com/questions/12423584/how-to-set-exact-client-size-for-overlapped-window-winapi
|
||||
//
|
||||
// So we manually calculate these values here.
|
||||
let mut rect = RECT {
|
||||
left: bounds.left().0,
|
||||
top: bounds.top().0,
|
||||
right: bounds.right().0,
|
||||
bottom: bounds.bottom().0,
|
||||
};
|
||||
let window_rect = unsafe {
|
||||
let mut rect = std::mem::zeroed();
|
||||
GetWindowRect(hwnd, &mut rect)?;
|
||||
rect
|
||||
};
|
||||
let client_rect = unsafe {
|
||||
let mut rect = std::mem::zeroed();
|
||||
GetClientRect(hwnd, &mut rect)?;
|
||||
rect
|
||||
};
|
||||
let width_offset =
|
||||
(window_rect.right - window_rect.left) - (client_rect.right - client_rect.left);
|
||||
let height_offset =
|
||||
(window_rect.bottom - window_rect.top) - (client_rect.bottom - client_rect.top);
|
||||
let left_offset = width_offset / 2;
|
||||
let top_offset = height_offset / 2;
|
||||
let right_offset = width_offset - left_offset;
|
||||
let bottom_offet = height_offset - top_offset;
|
||||
let left_offset = border_offset.width_offset / 2;
|
||||
let top_offset = border_offset.height_offset / 2;
|
||||
let right_offset = border_offset.width_offset - left_offset;
|
||||
let bottom_offet = border_offset.height_offset - top_offset;
|
||||
rect.left -= left_offset;
|
||||
rect.top -= top_offset;
|
||||
rect.right += right_offset;
|
||||
rect.bottom += bottom_offet;
|
||||
Ok(rect)
|
||||
rect
|
||||
}
|
||||
|
||||
fn calculate_client_rect(
|
||||
rect: RECT,
|
||||
border_offset: WindowBorderOffset,
|
||||
scale_factor: f32,
|
||||
) -> Bounds<Pixels> {
|
||||
let left_offset = border_offset.width_offset / 2;
|
||||
let top_offset = border_offset.height_offset / 2;
|
||||
let right_offset = border_offset.width_offset - left_offset;
|
||||
let bottom_offet = border_offset.height_offset - top_offset;
|
||||
let left = rect.left + left_offset;
|
||||
let top = rect.top + top_offset;
|
||||
let right = rect.right - right_offset;
|
||||
let bottom = rect.bottom - bottom_offet;
|
||||
let physical_size = size(DevicePixels(right - left), DevicePixels(bottom - top));
|
||||
Bounds {
|
||||
origin: logical_point(left as f32, top as f32, scale_factor),
|
||||
size: physical_size.to_pixels(scale_factor),
|
||||
}
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-dragqueryfilew
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue