mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-27 10:34:53 +03:00
Windows: impl WindowsDisplay
(#9287)
Tested on my laptop, and I've noticed that when I move the window, `WindowsPlatform::displays()` is being continuously called. Is this intended? Release Notes: - N/A
This commit is contained in:
parent
36cbfbfb94
commit
3274cc93df
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -8729,6 +8729,12 @@ dependencies = [
|
|||||||
"digest 0.10.7",
|
"digest 0.10.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1_smol"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.9.9"
|
version = "0.9.9"
|
||||||
@ -11034,6 +11040,7 @@ checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.10",
|
"getrandom 0.2.10",
|
||||||
"serde",
|
"serde",
|
||||||
|
"sha1_smol",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -70,7 +70,7 @@ time.workspace = true
|
|||||||
tiny-skia = "0.5"
|
tiny-skia = "0.5"
|
||||||
usvg = { version = "0.14", features = [] }
|
usvg = { version = "0.14", features = [] }
|
||||||
util.workspace = true
|
util.workspace = true
|
||||||
uuid = { version = "1.1.2", features = ["v4"] }
|
uuid = { version = "1.1.2", features = ["v4", "v5"] }
|
||||||
waker-fn = "1.1.0"
|
waker-fn = "1.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -1,48 +1,169 @@
|
|||||||
use anyhow::{anyhow, Result};
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use windows::{
|
use windows::Win32::{
|
||||||
core::PCSTR,
|
Foundation::{BOOL, LPARAM, POINT, RECT},
|
||||||
Win32::Graphics::Gdi::{EnumDisplaySettingsA, DEVMODEA, ENUM_CURRENT_SETTINGS},
|
Graphics::Gdi::{
|
||||||
|
EnumDisplayMonitors, GetMonitorInfoW, MonitorFromPoint, HDC, HMONITOR, MONITORINFO,
|
||||||
|
MONITORINFOEXW, MONITOR_DEFAULTTOPRIMARY,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Point, Size};
|
use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Point, Size};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct WindowsDisplay;
|
pub(crate) struct WindowsDisplay {
|
||||||
|
pub display_id: DisplayId,
|
||||||
|
bounds: Bounds<GlobalPixels>,
|
||||||
|
uuid: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
impl WindowsDisplay {
|
impl WindowsDisplay {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new(display_id: DisplayId) -> Option<Self> {
|
||||||
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 uuid = generate_uuid(&info.szDevice);
|
||||||
|
|
||||||
|
Some(WindowsDisplay {
|
||||||
|
display_id,
|
||||||
|
bounds: Bounds {
|
||||||
|
origin: Point {
|
||||||
|
x: GlobalPixels(size.left as f32),
|
||||||
|
y: GlobalPixels(size.top as f32),
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
width: GlobalPixels((size.right - size.left) as f32),
|
||||||
|
height: GlobalPixels((size.bottom - size.top) as f32),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uuid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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 uuid = generate_uuid(&info.szDevice);
|
||||||
|
|
||||||
|
WindowsDisplay {
|
||||||
|
display_id,
|
||||||
|
bounds: Bounds {
|
||||||
|
origin: Point {
|
||||||
|
x: GlobalPixels(size.left as f32),
|
||||||
|
y: GlobalPixels(size.top as f32),
|
||||||
|
},
|
||||||
|
size: Size {
|
||||||
|
width: GlobalPixels((size.right - size.left) as f32),
|
||||||
|
height: GlobalPixels((size.bottom - size.top) as f32),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uuid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn primary_monitor() -> Option<Self> {
|
||||||
|
// https://devblogs.microsoft.com/oldnewthing/20070809-00/?p=25643
|
||||||
|
const POINT_ZERO: POINT = POINT { x: 0, y: 0 };
|
||||||
|
let monitor = unsafe { MonitorFromPoint(POINT_ZERO, MONITOR_DEFAULTTOPRIMARY) };
|
||||||
|
if monitor.is_invalid() {
|
||||||
|
log::error!(
|
||||||
|
"can not find the primary monitor: {}",
|
||||||
|
std::io::Error::last_os_error()
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let Some(display_id) = available_monitors()
|
||||||
|
.iter()
|
||||||
|
.position(|handle| handle.0 == monitor.0)
|
||||||
|
else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(WindowsDisplay::new_with_handle_and_id(
|
||||||
|
monitor,
|
||||||
|
DisplayId(display_id as _),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn displays() -> Vec<Rc<dyn PlatformDisplay>> {
|
||||||
|
available_monitors()
|
||||||
|
.into_iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(id, handle)| {
|
||||||
|
Rc::new(WindowsDisplay::new_with_handle_and_id(
|
||||||
|
handle,
|
||||||
|
DisplayId(id as _),
|
||||||
|
)) as Rc<dyn PlatformDisplay>
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlatformDisplay for WindowsDisplay {
|
impl PlatformDisplay for WindowsDisplay {
|
||||||
// todo(windows)
|
|
||||||
fn id(&self) -> DisplayId {
|
fn id(&self) -> DisplayId {
|
||||||
DisplayId(1)
|
self.display_id
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
fn uuid(&self) -> anyhow::Result<Uuid> {
|
||||||
fn uuid(&self) -> Result<Uuid> {
|
Ok(self.uuid)
|
||||||
Err(anyhow!("not implemented yet."))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bounds(&self) -> Bounds<GlobalPixels> {
|
fn bounds(&self) -> Bounds<GlobalPixels> {
|
||||||
let mut dev = DEVMODEA {
|
self.bounds
|
||||||
dmSize: std::mem::size_of::<DEVMODEA>() as _,
|
|
||||||
..unsafe { std::mem::zeroed() }
|
|
||||||
};
|
|
||||||
unsafe { EnumDisplaySettingsA(PCSTR::null(), ENUM_CURRENT_SETTINGS, &mut dev) };
|
|
||||||
let w = dev.dmPelsWidth;
|
|
||||||
let h = dev.dmPelsHeight;
|
|
||||||
|
|
||||||
log::debug!("Screen size: {w} {h}");
|
|
||||||
Bounds::new(
|
|
||||||
Point::new(0.0.into(), 0.0.into()),
|
|
||||||
Size {
|
|
||||||
width: GlobalPixels(w as f32),
|
|
||||||
height: GlobalPixels(h as f32),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn available_monitors() -> SmallVec<[HMONITOR; 4]> {
|
||||||
|
let mut monitors: SmallVec<[HMONITOR; 4]> = SmallVec::new();
|
||||||
|
unsafe {
|
||||||
|
EnumDisplayMonitors(
|
||||||
|
HDC::default(),
|
||||||
|
None,
|
||||||
|
Some(monitor_enum_proc),
|
||||||
|
LPARAM(&mut monitors as *mut _ as _),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
monitors
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "system" fn monitor_enum_proc(
|
||||||
|
hmonitor: HMONITOR,
|
||||||
|
_hdc: HDC,
|
||||||
|
_place: *mut RECT,
|
||||||
|
data: LPARAM,
|
||||||
|
) -> BOOL {
|
||||||
|
let monitors = data.0 as *mut SmallVec<[HMONITOR; 4]>;
|
||||||
|
unsafe { (*monitors).push(hmonitor) };
|
||||||
|
BOOL(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_monitor_info(hmonitor: HMONITOR) -> anyhow::Result<MONITORINFOEXW> {
|
||||||
|
let mut monitor_info: MONITORINFOEXW = unsafe { std::mem::zeroed() };
|
||||||
|
monitor_info.monitorInfo.cbSize = std::mem::size_of::<MONITORINFOEXW>() as u32;
|
||||||
|
let status = unsafe {
|
||||||
|
GetMonitorInfoW(
|
||||||
|
hmonitor,
|
||||||
|
&mut monitor_info as *mut MONITORINFOEXW as *mut MONITORINFO,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if status.as_bool() {
|
||||||
|
Ok(monitor_info)
|
||||||
|
} else {
|
||||||
|
Err(anyhow::anyhow!(std::io::Error::last_os_error()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_uuid(device_name: &[u16]) -> Uuid {
|
||||||
|
let name = device_name
|
||||||
|
.iter()
|
||||||
|
.flat_map(|&a| a.to_be_bytes().to_vec())
|
||||||
|
.collect_vec();
|
||||||
|
Uuid::new_v5(&Uuid::NAMESPACE_DNS, &name)
|
||||||
|
}
|
||||||
|
@ -284,19 +284,24 @@ impl Platform for WindowsPlatform {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
|
||||||
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>> {
|
||||||
vec![Rc::new(WindowsDisplay::new())]
|
WindowsDisplay::displays()
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
|
||||||
fn display(&self, id: crate::DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
|
fn display(&self, id: crate::DisplayId) -> Option<Rc<dyn PlatformDisplay>> {
|
||||||
Some(Rc::new(WindowsDisplay::new()))
|
if let Some(display) = WindowsDisplay::new(id) {
|
||||||
|
Some(Rc::new(display) as Rc<dyn PlatformDisplay>)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
|
||||||
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
|
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>> {
|
||||||
Some(Rc::new(WindowsDisplay::new()))
|
if let Some(display) = WindowsDisplay::primary_monitor() {
|
||||||
|
Some(Rc::new(display) as Rc<dyn PlatformDisplay>)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
// todo(windows)
|
||||||
|
@ -637,6 +637,7 @@ struct Callbacks {
|
|||||||
pub(crate) struct WindowsWindow {
|
pub(crate) struct WindowsWindow {
|
||||||
inner: Rc<WindowsWindowInner>,
|
inner: Rc<WindowsWindowInner>,
|
||||||
drag_drop_handler: IDropTarget,
|
drag_drop_handler: IDropTarget,
|
||||||
|
display: Rc<WindowsDisplay>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WindowCreateContext {
|
struct WindowCreateContext {
|
||||||
@ -701,9 +702,12 @@ impl WindowsWindow {
|
|||||||
};
|
};
|
||||||
drag_drop_handler
|
drag_drop_handler
|
||||||
};
|
};
|
||||||
|
// todo(windows) move window to target monitor
|
||||||
|
// options.display_id
|
||||||
let wnd = Self {
|
let wnd = Self {
|
||||||
inner: context.inner.unwrap(),
|
inner: context.inner.unwrap(),
|
||||||
drag_drop_handler,
|
drag_drop_handler,
|
||||||
|
display: Rc::new(WindowsDisplay::primary_monitor().unwrap()),
|
||||||
};
|
};
|
||||||
platform_inner
|
platform_inner
|
||||||
.raw_window_handles
|
.raw_window_handles
|
||||||
@ -780,9 +784,8 @@ impl PlatformWindow for WindowsWindow {
|
|||||||
WindowAppearance::Dark
|
WindowAppearance::Dark
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(windows)
|
|
||||||
fn display(&self) -> Rc<dyn PlatformDisplay> {
|
fn display(&self) -> Rc<dyn PlatformDisplay> {
|
||||||
Rc::new(WindowsDisplay::new())
|
self.display.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_position(&self) -> Point<Pixels> {
|
fn mouse_position(&self) -> Point<Pixels> {
|
||||||
|
Loading…
Reference in New Issue
Block a user