diff --git a/komorebi/src/monitor.rs b/komorebi/src/monitor.rs index 34068fd9..c6bd33e8 100644 --- a/komorebi/src/monitor.rs +++ b/komorebi/src/monitor.rs @@ -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, #[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(), diff --git a/komorebi/src/process_event.rs b/komorebi/src/process_event.rs index ed1066cb..e9f94aab 100644 --- a/komorebi/src/process_event.rs +++ b/komorebi/src/process_event.rs @@ -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 diff --git a/komorebi/src/window.rs b/komorebi/src/window.rs index c77ecfa9..ffef4240 100644 --- a/komorebi/src/window.rs +++ b/komorebi/src/window.rs @@ -231,6 +231,10 @@ impl Window { #[tracing::instrument(fields(exe, title))] pub fn should_manage(self, event: Option) -> Result { + if let Some(WindowManagerEvent::MonitorPoll(_, _)) = event { + return Ok(true); + } + if self.title().is_err() { return Ok(false); } diff --git a/komorebi/src/window_manager.rs b/komorebi/src/window_manager.rs index 759e4f5c..99ed6011 100644 --- a/komorebi/src/window_manager.rs +++ b/komorebi/src/window_manager.rs @@ -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)?; diff --git a/komorebi/src/window_manager_event.rs b/komorebi/src/window_manager_event.rs index 1547fe9b..8f277251 100644 --- a/komorebi/src/window_manager_event.rs +++ b/komorebi/src/window_manager_event.rs @@ -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, } } diff --git a/komorebi/src/windows_api.rs b/komorebi/src/windows_api.rs index be54d0bd..5d5fcfbd 100644 --- a/komorebi/src/windows_api.rs +++ b/komorebi/src/windows_api.rs @@ -560,11 +560,11 @@ impl WindowsApi { Ok(monitor_info) } - pub fn monitor(hmonitor: HMONITOR) -> Result { - let monitor_info = Self::monitor_info_w(hmonitor)?; + pub fn monitor(hmonitor: isize) -> Result { + let monitor_info = Self::monitor_info_w(HMONITOR(hmonitor))?; Ok(monitor::new( - hmonitor.0, + hmonitor, monitor_info.rcMonitor.into(), monitor_info.rcWork.into(), )) diff --git a/komorebi/src/windows_callbacks.rs b/komorebi/src/windows_callbacks.rs index cd959918..96997979 100644 --- a/komorebi/src/windows_callbacks.rs +++ b/komorebi/src/windows_callbacks.rs @@ -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); }