feat(wm): adapt to scaling and resolution changes

This commit expands the reconcile_monitors fn to also update resolution
and work area sizes if they are different from what is stored in the
window manager state.

Another WindowManagerEvent has been added as a polling mechanism for
monitor-related changes (scaling, dpi, resolution etc.), and this will
now also trigger the reconcile_monitors fn in the existing event
pre-processing block.

resolve #36
This commit is contained in:
LGUG2Z
2021-09-16 14:53:05 -07:00
parent b8a27a93fe
commit 5b923a135c
7 changed files with 69 additions and 10 deletions

View File

@@ -19,8 +19,9 @@ use crate::workspace::Workspace;
pub struct Monitor {
#[getset(get_copy = "pub", set = "pub")]
id: isize,
monitor_size: Rect,
#[getset(get = "pub")]
#[getset(get = "pub", set = "pub")]
size: Rect,
#[getset(get = "pub", set = "pub")]
work_area_size: Rect,
workspaces: Ring<Workspace>,
#[serde(skip_serializing)]
@@ -30,13 +31,13 @@ pub struct Monitor {
impl_ring_elements!(Monitor, Workspace);
pub fn new(id: isize, monitor_size: Rect, work_area_size: Rect) -> Monitor {
pub fn new(id: isize, size: Rect, work_area_size: Rect) -> Monitor {
let mut workspaces = Ring::default();
workspaces.elements_mut().push_back(Workspace::default());
Monitor {
id,
monitor_size,
size,
work_area_size,
workspaces,
workspace_names: HashMap::default(),

View File

@@ -51,7 +51,8 @@ impl WindowManager {
// Make sure we have the most recently focused monitor from any event
match event {
WindowManagerEvent::FocusChange(_, window)
WindowManagerEvent::MonitorPoll(_, window)
| WindowManagerEvent::FocusChange(_, window)
| WindowManagerEvent::Show(_, window)
| WindowManagerEvent::MoveResizeEnd(_, window) => {
self.reconcile_monitors()?;
@@ -284,7 +285,7 @@ impl WindowManager {
self.update_focused_workspace(false)?;
}
}
WindowManagerEvent::MouseCapture(..) => {}
WindowManagerEvent::MonitorPoll(..) | WindowManagerEvent::MouseCapture(..) => {}
};
// If we unmanaged a window, it shouldn't be immediately hidden behind managed windows

View File

@@ -231,6 +231,10 @@ impl Window {
#[tracing::instrument(fields(exe, title))]
pub fn should_manage(self, event: Option<WindowManagerEvent>) -> Result<bool> {
if let Some(WindowManagerEvent::MonitorPoll(_, _)) = event {
return Ok(true);
}
if self.title().is_err() {
return Ok(false);
}

View File

@@ -265,6 +265,39 @@ impl WindowManager {
// Remove any invalid monitors from our state
self.monitors_mut().retain(|m| !invalid.contains(&m.id()));
let invisible_borders = self.invisible_borders;
for monitor in self.monitors_mut() {
let mut should_update = false;
let reference = WindowsApi::monitor(monitor.id())?;
// TODO: If this is different, force a redraw
if reference.work_area_size() != monitor.work_area_size() {
monitor.set_work_area_size(Rect {
left: reference.work_area_size().left,
top: reference.work_area_size().top,
right: reference.work_area_size().right,
bottom: reference.work_area_size().bottom,
});
should_update = true;
}
if reference.size() != monitor.size() {
monitor.set_size(Rect {
left: reference.size().left,
top: reference.size().top,
right: reference.size().right,
bottom: reference.size().bottom,
});
should_update = true;
}
if should_update {
monitor.update_focused_workspace(&invisible_borders)?;
}
}
// Check for and add any new monitors that may have been plugged in
WindowsApi::load_monitor_information(&mut self.monitors)?;

View File

@@ -17,6 +17,7 @@ pub enum WindowManagerEvent {
Manage(Window),
Unmanage(Window),
Raise(Window),
MonitorPoll(WinEvent, Window),
}
impl Display for WindowManagerEvent {
@@ -64,6 +65,13 @@ impl Display for WindowManagerEvent {
WindowManagerEvent::Raise(window) => {
write!(f, "Raise (Window: {})", window)
}
WindowManagerEvent::MonitorPoll(winevent, window) => {
write!(
f,
"MonitorPoll (WinEvent: {}, Window: {})",
winevent, window
)
}
}
}
}
@@ -78,6 +86,7 @@ impl WindowManagerEvent {
| WindowManagerEvent::Show(_, window)
| WindowManagerEvent::MoveResizeEnd(_, window)
| WindowManagerEvent::MouseCapture(_, window)
| WindowManagerEvent::MonitorPoll(_, window)
| WindowManagerEvent::Raise(window)
| WindowManagerEvent::Manage(window)
| WindowManagerEvent::Unmanage(window) => window,
@@ -121,6 +130,17 @@ impl WindowManagerEvent {
None
}
}
WinEvent::ObjectCreate => {
if let Ok(title) = window.title() {
// Hidden COM support mechanism window that fires this event on both DPI/scaling
// changes and resolution changes, a good candidate for polling
if title == "OLEChannelWnd" {
return Option::from(Self::MonitorPoll(winevent, window));
}
}
None
}
_ => None,
}
}

View File

@@ -560,11 +560,11 @@ impl WindowsApi {
Ok(monitor_info)
}
pub fn monitor(hmonitor: HMONITOR) -> Result<Monitor> {
let monitor_info = Self::monitor_info_w(hmonitor)?;
pub fn monitor(hmonitor: isize) -> Result<Monitor> {
let monitor_info = Self::monitor_info_w(HMONITOR(hmonitor))?;
Ok(monitor::new(
hmonitor.0,
hmonitor,
monitor_info.rcMonitor.into(),
monitor_info.rcWork.into(),
))

View File

@@ -42,7 +42,7 @@ pub extern "system" fn enum_display_monitor(
}
}
if let Ok(m) = WindowsApi::monitor(hmonitor) {
if let Ok(m) = WindowsApi::monitor(hmonitor.0) {
monitors.elements_mut().push_back(m);
}