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_STARTCOMPOSITION => handle_ime_position(handle, state_ptr),
|
||||||
WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
|
WM_IME_COMPOSITION => handle_ime_composition(handle, lparam, state_ptr),
|
||||||
WM_SETCURSOR => handle_set_cursor(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),
|
CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
@ -732,7 +732,10 @@ fn handle_dpi_changed_msg(
|
||||||
state_ptr: Rc<WindowsWindowStatePtr>,
|
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||||
) -> Option<isize> {
|
) -> Option<isize> {
|
||||||
let new_dpi = wparam.loword() as f32;
|
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 rect = unsafe { &*(lparam.0 as *const RECT) };
|
||||||
let width = rect.right - rect.left;
|
let width = rect.right - rect.left;
|
||||||
|
@ -1050,12 +1053,17 @@ fn handle_set_cursor(lparam: LPARAM, state_ptr: Rc<WindowsWindowStatePtr>) -> Op
|
||||||
Some(1)
|
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();
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
// mouse wheel
|
// mouse wheel
|
||||||
lock.system_settings.mouse_wheel_settings.update();
|
lock.system_settings.mouse_wheel_settings.update();
|
||||||
// mouse double click
|
// mouse double click
|
||||||
lock.click_state.system_update();
|
lock.click_state.system_update();
|
||||||
|
// window border offset
|
||||||
|
lock.border_offset.udpate(handle).log_err();
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub struct WindowsWindowState {
|
||||||
pub origin: Point<Pixels>,
|
pub origin: Point<Pixels>,
|
||||||
pub logical_size: Size<Pixels>,
|
pub logical_size: Size<Pixels>,
|
||||||
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
||||||
|
pub border_offset: WindowBorderOffset,
|
||||||
pub scale_factor: f32,
|
pub scale_factor: f32,
|
||||||
|
|
||||||
pub callbacks: Callbacks,
|
pub callbacks: Callbacks,
|
||||||
|
@ -82,6 +83,7 @@ impl WindowsWindowState {
|
||||||
origin,
|
origin,
|
||||||
size: logical_size,
|
size: logical_size,
|
||||||
};
|
};
|
||||||
|
let border_offset = WindowBorderOffset::default();
|
||||||
let renderer = windows_renderer::windows_renderer(hwnd, transparent);
|
let renderer = windows_renderer::windows_renderer(hwnd, transparent);
|
||||||
let callbacks = Callbacks::default();
|
let callbacks = Callbacks::default();
|
||||||
let input_handler = None;
|
let input_handler = None;
|
||||||
|
@ -94,6 +96,7 @@ impl WindowsWindowState {
|
||||||
origin,
|
origin,
|
||||||
logical_size,
|
logical_size,
|
||||||
fullscreen_restore_bounds,
|
fullscreen_restore_bounds,
|
||||||
|
border_offset,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
callbacks,
|
callbacks,
|
||||||
input_handler,
|
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 placement = unsafe {
|
||||||
let mut placement = WINDOWPLACEMENT {
|
let mut placement = WINDOWPLACEMENT {
|
||||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
length: std::mem::size_of::<WINDOWPLACEMENT>() as u32,
|
||||||
|
@ -133,22 +137,22 @@ impl WindowsWindowState {
|
||||||
GetWindowPlacement(self.hwnd, &mut placement).log_err();
|
GetWindowPlacement(self.hwnd, &mut placement).log_err();
|
||||||
placement
|
placement
|
||||||
};
|
};
|
||||||
let physical_size = size(
|
(
|
||||||
DevicePixels(placement.rcNormalPosition.right - placement.rcNormalPosition.left),
|
calculate_client_rect(
|
||||||
DevicePixels(placement.rcNormalPosition.bottom - placement.rcNormalPosition.top),
|
placement.rcNormalPosition,
|
||||||
);
|
self.border_offset,
|
||||||
let bounds = Bounds {
|
|
||||||
origin: logical_point(
|
|
||||||
placement.rcNormalPosition.left as f32,
|
|
||||||
placement.rcNormalPosition.top as f32,
|
|
||||||
self.scale_factor,
|
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() {
|
if self.is_fullscreen() {
|
||||||
WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
|
WindowBounds::Fullscreen(self.fullscreen_restore_bounds)
|
||||||
} else if placement.showCmd == SW_SHOWMAXIMIZED.0 as u32 {
|
} else if maximized {
|
||||||
WindowBounds::Maximized(bounds)
|
WindowBounds::Maximized(bounds)
|
||||||
} else {
|
} else {
|
||||||
WindowBounds::Windowed(bounds)
|
WindowBounds::Windowed(bounds)
|
||||||
|
@ -308,7 +312,6 @@ impl WindowsWindow {
|
||||||
};
|
};
|
||||||
let state_ptr = Rc::clone(context.inner.as_ref().unwrap());
|
let state_ptr = Rc::clone(context.inner.as_ref().unwrap());
|
||||||
register_drag_drop(state_ptr.clone());
|
register_drag_drop(state_ptr.clone());
|
||||||
let wnd = Self(state_ptr);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut placement = WINDOWPLACEMENT {
|
let mut placement = WINDOWPLACEMENT {
|
||||||
|
@ -322,13 +325,16 @@ impl WindowsWindow {
|
||||||
} else {
|
} else {
|
||||||
display.default_bounds()
|
display.default_bounds()
|
||||||
};
|
};
|
||||||
let bounds = bounds.to_device_pixels(wnd.0.state.borrow().scale_factor);
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
placement.rcNormalPosition = calcualte_window_position(bounds, raw_hwnd).unwrap();
|
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();
|
SetWindowPlacement(raw_hwnd, &placement).log_err();
|
||||||
}
|
}
|
||||||
unsafe { ShowWindow(raw_hwnd, SW_SHOW).ok().log_err() };
|
unsafe { ShowWindow(raw_hwnd, SW_SHOW).ok().log_err() };
|
||||||
|
|
||||||
wnd
|
Self(state_ptr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,10 +550,6 @@ impl PlatformWindow for WindowsWindow {
|
||||||
.executor
|
.executor
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let mut lock = state_ptr.state.borrow_mut();
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
lock.fullscreen_restore_bounds = Bounds {
|
|
||||||
origin: lock.origin,
|
|
||||||
size: lock.logical_size,
|
|
||||||
};
|
|
||||||
let StyleAndBounds {
|
let StyleAndBounds {
|
||||||
style,
|
style,
|
||||||
x,
|
x,
|
||||||
|
@ -557,6 +559,8 @@ impl PlatformWindow for WindowsWindow {
|
||||||
} = if let Some(state) = lock.fullscreen.take() {
|
} = if let Some(state) = lock.fullscreen.take() {
|
||||||
state
|
state
|
||||||
} else {
|
} else {
|
||||||
|
let (window_bounds, _) = lock.calculate_window_bounds();
|
||||||
|
lock.fullscreen_restore_bounds = window_bounds;
|
||||||
let style =
|
let style =
|
||||||
WINDOW_STYLE(unsafe { get_window_long(state_ptr.hwnd, GWL_STYLE) } as _);
|
WINDOW_STYLE(unsafe { get_window_long(state_ptr.hwnd, GWL_STYLE) } as _);
|
||||||
let mut rc = RECT::default();
|
let mut rc = RECT::default();
|
||||||
|
@ -861,6 +865,32 @@ struct StyleAndBounds {
|
||||||
cy: i32,
|
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 {
|
fn register_wnd_class(icon_handle: HICON) -> PCWSTR {
|
||||||
const CLASS_NAME: PCWSTR = w!("Zed::Window");
|
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 {
|
let mut rect = RECT {
|
||||||
left: bounds.left().0,
|
left: bounds.left().0,
|
||||||
top: bounds.top().0,
|
top: bounds.top().0,
|
||||||
right: bounds.right().0,
|
right: bounds.right().0,
|
||||||
bottom: bounds.bottom().0,
|
bottom: bounds.bottom().0,
|
||||||
};
|
};
|
||||||
let window_rect = unsafe {
|
let left_offset = border_offset.width_offset / 2;
|
||||||
let mut rect = std::mem::zeroed();
|
let top_offset = border_offset.height_offset / 2;
|
||||||
GetWindowRect(hwnd, &mut rect)?;
|
let right_offset = border_offset.width_offset - left_offset;
|
||||||
rect
|
let bottom_offet = border_offset.height_offset - top_offset;
|
||||||
};
|
|
||||||
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;
|
|
||||||
rect.left -= left_offset;
|
rect.left -= left_offset;
|
||||||
rect.top -= top_offset;
|
rect.top -= top_offset;
|
||||||
rect.right += right_offset;
|
rect.right += right_offset;
|
||||||
rect.bottom += bottom_offet;
|
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
|
// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-dragqueryfilew
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue