feat(wm): introduce lazy monitor cache

This commit introduces a lazy monitor cache that only gets populated
with a monitor has been disconnected, before the monitor is removed from
the state. If and when the same monitor is reconnected and identified by
its size on the virtual screen, the cached monitor state will be used to
repopulate layout options, avoiding a potentially expensive full
configuration reload.

re #275
This commit is contained in:
LGUG2Z
2022-10-27 09:08:36 -07:00
committed by جاد
parent 2575ca2da4
commit 3ad0ae6aca
+46 -2
View File
@@ -1,3 +1,4 @@
use std::collections::HashMap;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::ErrorKind; use std::io::ErrorKind;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
@@ -54,6 +55,7 @@ use crate::WORKSPACE_RULES;
#[derive(Debug)] #[derive(Debug)]
pub struct WindowManager { pub struct WindowManager {
pub monitors: Ring<Monitor>, pub monitors: Ring<Monitor>,
pub monitor_cache: HashMap<usize, Monitor>,
pub incoming_events: Arc<Mutex<Receiver<WindowManagerEvent>>>, pub incoming_events: Arc<Mutex<Receiver<WindowManagerEvent>>>,
pub command_listener: UnixListener, pub command_listener: UnixListener,
pub is_paused: bool, pub is_paused: bool,
@@ -166,6 +168,7 @@ impl WindowManager {
Ok(Self { Ok(Self {
monitors: Ring::default(), monitors: Ring::default(),
monitor_cache: HashMap::new(),
incoming_events: incoming, incoming_events: incoming,
command_listener: listener, command_listener: listener,
is_paused: false, is_paused: false,
@@ -341,12 +344,15 @@ impl WindowManager {
} }
let mut orphaned_containers = vec![]; let mut orphaned_containers = vec![];
let mut invalid_indices = vec![];
for invalid in self for (i, invalid) in self
.monitors() .monitors()
.iter() .iter()
.filter(|m| !valid_names.contains(m.name())) .enumerate()
.filter(|(_, m)| !valid_names.contains(m.name()))
{ {
invalid_indices.push(i);
for workspace in invalid.workspaces() { for workspace in invalid.workspaces() {
for container in workspace.containers() { for container in workspace.containers() {
// Save the orphaned containers from an invalid monitor // Save the orphaned containers from an invalid monitor
@@ -356,6 +362,12 @@ impl WindowManager {
} }
} }
for i in invalid_indices {
if let Some(monitor) = self.monitors().get(i) {
self.monitor_cache.insert(i, monitor.clone());
}
}
// Remove any invalid monitors from our state // Remove any invalid monitors from our state
self.monitors_mut() self.monitors_mut()
.retain(|m| valid_names.contains(m.name())); .retain(|m| valid_names.contains(m.name()));
@@ -411,9 +423,41 @@ impl WindowManager {
} }
} }
#[allow(clippy::needless_collect)]
let old_sizes = self
.monitors()
.iter()
.map(Monitor::size)
.copied()
.collect::<Vec<_>>();
// Check for and add any new monitors that may have been plugged in // Check for and add any new monitors that may have been plugged in
WindowsApi::load_monitor_information(&mut self.monitors)?; WindowsApi::load_monitor_information(&mut self.monitors)?;
let mut check_cache = vec![];
for (i, m) in self.monitors().iter().enumerate() {
if !old_sizes.contains(m.size()) {
check_cache.push(i);
}
}
for i in check_cache {
if let Some(cached) = self.monitor_cache.get(&i).cloned() {
if let Some(monitor) = self.monitors_mut().get_mut(i) {
for (w_idx, workspace) in monitor.workspaces_mut().iter_mut().enumerate() {
if let Some(cached_workspace) = cached.workspaces().get(w_idx) {
workspace.set_layout(cached_workspace.layout().clone());
workspace.set_layout_rules(cached_workspace.layout_rules().clone());
workspace.set_layout_flip(cached_workspace.layout_flip());
workspace.set_workspace_padding(cached_workspace.workspace_padding());
workspace.set_container_padding(cached_workspace.container_padding());
}
}
}
}
}
let final_count = self.monitors().len(); let final_count = self.monitors().len();
if after_count != final_count { if after_count != final_count {
self.retile_all(true)?; self.retile_all(true)?;