@@ -13,6 +13,7 @@ use std::{
};
use ::util::ResultExt;
+use anyhow::Context;
use blade_graphics as gpu;
use futures::channel::oneshot::{self, Receiver};
use itertools::Itertools;
@@ -41,14 +42,13 @@ use crate::*;
pub(crate) struct WindowsWindowInner {
hwnd: HWND,
origin: Cell<Point<GlobalPixels>>,
- size: Cell<Size<GlobalPixels>>,
- mouse_position: Cell<Point<Pixels>>,
+ physical_size: Cell<Size<GlobalPixels>>,
+ scale_factor: Cell<f32>,
input_handler: Cell<Option<PlatformInputHandler>>,
renderer: RefCell<BladeRenderer>,
callbacks: RefCell<Callbacks>,
platform_inner: Rc<WindowsPlatformInner>,
pub(crate) handle: AnyWindowHandle,
- scale_factor: f32,
hide_title_bar: bool,
display: RefCell<Rc<WindowsDisplay>>,
}
@@ -62,12 +62,16 @@ impl WindowsWindowInner {
hide_title_bar: bool,
display: Rc<WindowsDisplay>,
) -> Self {
- let origin = Cell::new(Point::new((cs.x as f64).into(), (cs.y as f64).into()));
- let size = Cell::new(Size {
- width: (cs.cx as f64).into(),
- height: (cs.cy as f64).into(),
+ let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
+ let origin = Cell::new(Point {
+ x: GlobalPixels(cs.x as f32),
+ y: GlobalPixels(cs.y as f32),
});
- let mouse_position = Cell::new(Point::default());
+ let physical_size = Cell::new(Size {
+ width: GlobalPixels(cs.cx as f32),
+ height: GlobalPixels(cs.cy as f32),
+ });
+ let scale_factor = Cell::new(monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32);
let input_handler = Cell::new(None);
struct RawWindow {
hwnd: *mut c_void,
@@ -109,14 +113,13 @@ impl WindowsWindowInner {
Self {
hwnd,
origin,
- size,
- mouse_position,
+ physical_size,
+ scale_factor,
input_handler,
renderer,
callbacks,
platform_inner,
handle,
- scale_factor: 1.0,
hide_title_bar,
display,
}
@@ -133,6 +136,7 @@ impl WindowsWindowInner {
fn get_titlebar_rect(&self) -> anyhow::Result<RECT> {
let top_and_bottom_borders = 2;
+ let scale_factor = self.scale_factor.get();
let theme = unsafe { OpenThemeData(self.hwnd, w!("WINDOW")) };
let title_bar_size = unsafe {
GetThemePartSize(
@@ -147,7 +151,7 @@ impl WindowsWindowInner {
unsafe { CloseThemeData(theme) }?;
let mut height =
- (title_bar_size.cy as f32 * self.scale_factor).round() as i32 + top_and_bottom_borders;
+ (title_bar_size.cy as f32 * scale_factor).round() as i32 + top_and_bottom_borders;
if self.is_maximized() {
let dpi = unsafe { GetDpiForWindow(self.hwnd) };
@@ -189,7 +193,7 @@ impl WindowsWindowInner {
WM_MOVE => self.handle_move_msg(lparam),
WM_SIZE => self.handle_size_msg(lparam),
WM_NCCALCSIZE => self.handle_calc_client_size(msg, wparam, lparam),
- WM_DPICHANGED => self.handle_dpi_changed_msg(msg, wparam, lparam),
+ WM_DPICHANGED => self.handle_dpi_changed_msg(wparam, lparam),
WM_NCHITTEST => self.handle_hit_test_msg(msg, wparam, lparam),
WM_PAINT => self.handle_paint_msg(),
WM_CLOSE => self.handle_close_msg(msg, wparam, lparam),
@@ -255,12 +259,15 @@ impl WindowsWindowInner {
}
fn handle_move_msg(&self, lparam: LPARAM) -> LRESULT {
- let x = lparam.signed_loword() as f64;
- let y = lparam.signed_hiword() as f64;
- self.origin.set(Point::new(x.into(), y.into()));
- let size = self.size.get();
- let center_x = x as f32 + size.width.0 / 2.0;
- let center_y = y as f32 + size.height.0 / 2.0;
+ let x = lparam.signed_loword() as f32;
+ let y = lparam.signed_hiword() as f32;
+ self.origin.set(Point {
+ x: GlobalPixels(x),
+ y: GlobalPixels(y),
+ });
+ let size = self.physical_size.get();
+ let center_x = x + size.width.0 / 2.0;
+ let center_y = y + size.height.0 / 2.0;
let monitor_bounds = self.display.borrow().bounds();
if center_x < monitor_bounds.left().0
|| center_x > monitor_bounds.right().0
@@ -282,23 +289,22 @@ impl WindowsWindowInner {
}
fn handle_size_msg(&self, lparam: LPARAM) -> LRESULT {
- let width = lparam.loword().max(1) as f64;
- let height = lparam.hiword().max(1) as f64;
- self.renderer
- .borrow_mut()
- .update_drawable_size(Size { width, height });
- let width = width.into();
- let height = height.into();
- self.size.set(Size { width, height });
+ let width = lparam.loword().max(1) as f32;
+ let height = lparam.hiword().max(1) as f32;
+ let scale_factor = self.scale_factor.get();
+ let new_physical_size = Size {
+ width: GlobalPixels(width),
+ height: GlobalPixels(height),
+ };
+ self.physical_size.set(new_physical_size);
+ self.renderer.borrow_mut().update_drawable_size(Size {
+ width: width as f64,
+ height: height as f64,
+ });
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.resize.as_mut() {
- callback(
- Size {
- width: Pixels(width.0),
- height: Pixels(height.0),
- },
- 1.0,
- );
+ let logical_size = logical_size(new_physical_size, scale_factor);
+ callback(logical_size, scale_factor);
}
self.invalidate_client_area();
LRESULT(0)
@@ -351,9 +357,6 @@ impl WindowsWindowInner {
}
fn handle_mouse_move_msg(&self, lparam: LPARAM, wparam: WPARAM) -> LRESULT {
- let x = Pixels::from(lparam.signed_loword() as f32);
- let y = Pixels::from(lparam.signed_hiword() as f32);
- self.mouse_position.set(Point { x, y });
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.input.as_mut() {
let pressed_button = match MODIFIERKEYS_FLAGS(wparam.loword() as u32) {
@@ -368,8 +371,11 @@ impl WindowsWindowInner {
}
_ => None,
};
+ let x = lparam.signed_loword() as f32;
+ let y = lparam.signed_hiword() as f32;
+ let scale_factor = self.scale_factor.get();
let event = MouseMoveEvent {
- position: Point { x, y },
+ position: logical_point(x, y, scale_factor),
pressed_button,
modifiers: self.current_modifiers(),
};
@@ -601,11 +607,12 @@ impl WindowsWindowInner {
fn handle_mouse_down_msg(&self, button: MouseButton, lparam: LPARAM) -> LRESULT {
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.input.as_mut() {
- let x = Pixels::from(lparam.signed_loword() as f32);
- let y = Pixels::from(lparam.signed_hiword() as f32);
+ let x = lparam.signed_loword() as f32;
+ let y = lparam.signed_hiword() as f32;
+ let scale_factor = self.scale_factor.get();
let event = MouseDownEvent {
button,
- position: Point { x, y },
+ position: logical_point(x, y, scale_factor),
modifiers: self.current_modifiers(),
click_count: 1,
};
@@ -619,11 +626,12 @@ impl WindowsWindowInner {
fn handle_mouse_up_msg(&self, button: MouseButton, lparam: LPARAM) -> LRESULT {
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.input.as_mut() {
- let x = Pixels::from(lparam.signed_loword() as f32);
- let y = Pixels::from(lparam.signed_hiword() as f32);
+ let x = lparam.signed_loword() as f32;
+ let y = lparam.signed_hiword() as f32;
+ let scale_factor = self.scale_factor.get();
let event = MouseUpEvent {
button,
- position: Point { x, y },
+ position: logical_point(x, y, scale_factor),
modifiers: self.current_modifiers(),
click_count: 1,
};
@@ -637,12 +645,13 @@ impl WindowsWindowInner {
fn handle_mouse_wheel_msg(&self, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.input.as_mut() {
- let x = Pixels::from(lparam.signed_loword() as f32);
- let y = Pixels::from(lparam.signed_hiword() as f32);
let wheel_distance = (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32)
* self.platform_inner.settings.borrow().wheel_scroll_lines as f32;
+ let x = lparam.signed_loword() as f32;
+ let y = lparam.signed_hiword() as f32;
+ let scale_factor = self.scale_factor.get();
let event = crate::ScrollWheelEvent {
- position: Point { x, y },
+ position: logical_point(x, y, scale_factor),
delta: ScrollDelta::Lines(Point {
x: 0.0,
y: wheel_distance,
@@ -659,12 +668,13 @@ impl WindowsWindowInner {
fn handle_mouse_horizontal_wheel_msg(&self, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.input.as_mut() {
- let x = Pixels::from(lparam.signed_loword() as f32);
- let y = Pixels::from(lparam.signed_hiword() as f32);
let wheel_distance = (wparam.signed_hiword() as f32 / WHEEL_DELTA as f32)
* self.platform_inner.settings.borrow().wheel_scroll_chars as f32;
+ let x = lparam.signed_loword() as f32;
+ let y = lparam.signed_hiword() as f32;
+ let scale_factor = self.scale_factor.get();
let event = crate::ScrollWheelEvent {
- position: Point { x, y },
+ position: logical_point(x, y, scale_factor),
delta: ScrollDelta::Lines(Point {
x: wheel_distance,
y: 0.0,
@@ -819,12 +829,13 @@ impl WindowsWindowInner {
fn handle_create_msg(&self, _lparam: LPARAM) -> LRESULT {
let mut size_rect = RECT::default();
unsafe { GetWindowRect(self.hwnd, &mut size_rect).log_err() };
+
let width = size_rect.right - size_rect.left;
let height = size_rect.bottom - size_rect.top;
- self.size.set(Size {
- width: GlobalPixels::from(width as f64),
- height: GlobalPixels::from(height as f64),
+ self.physical_size.set(Size {
+ width: GlobalPixels(width as f32),
+ height: GlobalPixels(height as f32),
});
if self.hide_title_bar {
@@ -847,8 +858,31 @@ impl WindowsWindowInner {
LRESULT(0)
}
- fn handle_dpi_changed_msg(&self, _msg: u32, _wparam: WPARAM, _lparam: LPARAM) -> LRESULT {
- LRESULT(1)
+ fn handle_dpi_changed_msg(&self, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
+ let new_dpi = wparam.loword() as f32;
+ let scale_factor = new_dpi / USER_DEFAULT_SCREEN_DPI as f32;
+ self.scale_factor.set(scale_factor);
+ let rect = unsafe { &*(lparam.0 as *const RECT) };
+ let width = rect.right - rect.left;
+ let height = rect.bottom - rect.top;
+ // this will emit `WM_SIZE` and `WM_MOVE` right here
+ // even before this funtion returns
+ // the new size is handled in `WM_SIZE`
+ unsafe {
+ SetWindowPos(
+ self.hwnd,
+ None,
+ rect.left,
+ rect.top,
+ width,
+ height,
+ SWP_NOZORDER | SWP_NOACTIVATE,
+ )
+ .context("unable to set window position after dpi has changed")
+ .log_err();
+ }
+ self.invalidate_client_area();
+ LRESULT(0)
}
fn handle_hit_test_msg(&self, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT {
@@ -910,18 +944,16 @@ impl WindowsWindowInner {
return unsafe { DefWindowProcW(self.hwnd, msg, wparam, lparam) };
}
- let mut cursor_point = POINT {
- x: lparam.signed_loword().into(),
- y: lparam.signed_hiword().into(),
- };
- unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
- let x = Pixels::from(cursor_point.x as f32);
- let y = Pixels::from(cursor_point.y as f32);
- self.mouse_position.set(Point { x, y });
let mut callbacks = self.callbacks.borrow_mut();
if let Some(callback) = callbacks.input.as_mut() {
+ let mut cursor_point = POINT {
+ x: lparam.signed_loword().into(),
+ y: lparam.signed_hiword().into(),
+ };
+ unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
+ let scale_factor = self.scale_factor.get();
let event = MouseMoveEvent {
- position: Point { x, y },
+ position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
pressed_button: None,
modifiers: self.current_modifiers(),
};
@@ -951,11 +983,10 @@ impl WindowsWindowInner {
y: lparam.signed_hiword().into(),
};
unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
- let x = Pixels::from(cursor_point.x as f32);
- let y = Pixels::from(cursor_point.y as f32);
+ let scale_factor = self.scale_factor.get();
let event = MouseDownEvent {
button,
- position: Point { x, y },
+ position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
modifiers: self.current_modifiers(),
click_count: 1,
};
@@ -990,11 +1021,10 @@ impl WindowsWindowInner {
y: lparam.signed_hiword().into(),
};
unsafe { ScreenToClient(self.hwnd, &mut cursor_point) };
- let x = Pixels::from(cursor_point.x as f32);
- let y = Pixels::from(cursor_point.y as f32);
+ let scale_factor = self.scale_factor.get();
let event = MouseUpEvent {
button,
- position: Point { x, y },
+ position: logical_point(cursor_point.x as f32, cursor_point.y as f32, scale_factor),
modifiers: self.current_modifiers(),
click_count: 1,
};
@@ -1194,7 +1224,7 @@ impl PlatformWindow for WindowsWindow {
fn bounds(&self) -> Bounds<GlobalPixels> {
Bounds {
origin: self.inner.origin.get(),
- size: self.inner.size.get(),
+ size: self.inner.physical_size.get(),
}
}
@@ -1202,18 +1232,19 @@ impl PlatformWindow for WindowsWindow {
self.inner.is_maximized()
}
- // todo(windows)
+ /// get the logical size of the app's drawable area.
+ ///
+ /// 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> {
- let size = self.inner.size.get();
- Size {
- width: size.width.0.into(),
- height: size.height.0.into(),
- }
+ logical_size(
+ self.inner.physical_size.get(),
+ self.inner.scale_factor.get(),
+ )
}
- // todo(windows)
fn scale_factor(&self) -> f32 {
- self.inner.scale_factor
+ self.inner.scale_factor.get()
}
// todo(windows)
@@ -1226,7 +1257,19 @@ impl PlatformWindow for WindowsWindow {
}
fn mouse_position(&self) -> Point<Pixels> {
- self.inner.mouse_position.get()
+ let point = unsafe {
+ let mut point: POINT = std::mem::zeroed();
+ GetCursorPos(&mut point)
+ .context("unable to get cursor position")
+ .log_err();
+ ScreenToClient(self.inner.hwnd, &mut point);
+ point
+ };
+ logical_point(
+ point.x as f32,
+ point.y as f32,
+ self.inner.scale_factor.get(),
+ )
}
// todo(windows)
@@ -1657,5 +1700,21 @@ fn oemkey_vkcode_to_string(code: u16) -> Option<String> {
}
}
+#[inline]
+fn logical_size(physical_size: Size<GlobalPixels>, scale_factor: f32) -> Size<Pixels> {
+ Size {
+ width: px(physical_size.width.0 / scale_factor),
+ height: px(physical_size.height.0 / scale_factor),
+ }
+}
+
+#[inline]
+fn logical_point(x: f32, y: f32, scale_factor: f32) -> Point<Pixels> {
+ Point {
+ x: px(x / scale_factor),
+ y: px(y / scale_factor),
+ }
+}
+
// https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-dragqueryfilew
const DRAGDROP_GET_FILES_COUNT: u32 = 0xFFFFFFFF;