micro optimization fixes
This commit is contained in:
1 parent
0d7203f84b
commit
da60ecb719
36 files changed
+1781
-521
No files matched your search
@@ -4,6 +4,10 @@ use std::hash::Hash;
|
||||
use ferese_animation::{AnimatedValue, WindowGeometry};
|
||||
use ferese_core::WorkspaceId;
|
||||
use ferese_layout::{ColumnWidth, Rect, WindowId};
|
||||
use smithay::desktop::Window;
|
||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||
use smithay::wayland::compositor::with_states;
|
||||
use smithay::wayland::shell::xdg::XdgToplevelSurfaceData;
|
||||
|
||||
use crate::resize_transaction::ResizeTransaction;
|
||||
|
||||
@@ -12,6 +16,10 @@ use crate::resize_transaction::ResizeTransaction;
|
||||
#[derive(Default)]
|
||||
pub(crate) struct WindowRecord {
|
||||
pub geometry: Option<WindowGeometry>,
|
||||
pub surface: Option<WlSurface>,
|
||||
pub app_id: String,
|
||||
pub title: String,
|
||||
pub metadata_revision: u64,
|
||||
pub resize: Option<ResizeTransaction>,
|
||||
pub focus: Option<crate::dimming::DimAnimation>,
|
||||
pub dimming: Option<crate::dimming::DimAnimation>,
|
||||
@@ -32,7 +40,11 @@ pub(crate) struct WindowRecord {
|
||||
/// handle always updates its record as well. IDs are never reused on remapping.
|
||||
pub(crate) struct WindowRegistry<W> {
|
||||
ids: HashMap<W, WindowId>,
|
||||
by_id: HashMap<WindowId, W>,
|
||||
surface_ids: HashMap<WlSurface, WindowId>,
|
||||
pub(super) records: HashMap<WindowId, WindowRecord>,
|
||||
// Ascending IDs; overview reverses this for front-to-back traversal.
|
||||
overview_order: Vec<WindowId>,
|
||||
next_id: u64,
|
||||
}
|
||||
|
||||
@@ -40,7 +52,10 @@ impl<W> Default for WindowRegistry<W> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ids: HashMap::new(),
|
||||
by_id: HashMap::new(),
|
||||
surface_ids: HashMap::new(),
|
||||
records: HashMap::new(),
|
||||
overview_order: Vec::new(),
|
||||
next_id: 1,
|
||||
}
|
||||
}
|
||||
@@ -54,10 +69,16 @@ impl<W: Eq + Hash> WindowRegistry<W> {
|
||||
id
|
||||
}
|
||||
|
||||
pub fn register(&mut self, window: W, id: WindowId) {
|
||||
pub fn register(&mut self, window: W, id: WindowId)
|
||||
where
|
||||
W: Clone,
|
||||
{
|
||||
assert!(!self.ids.contains_key(&window), "window already registered");
|
||||
assert!(!self.records.contains_key(&id), "window ID already registered");
|
||||
|
||||
let index = self.overview_order.partition_point(|existing| existing.0 < id.0);
|
||||
self.overview_order.insert(index, id);
|
||||
self.by_id.insert(id, window.clone());
|
||||
self.ids.insert(window, id);
|
||||
self.records.insert(id, WindowRecord::default());
|
||||
}
|
||||
@@ -66,6 +87,24 @@ impl<W: Eq + Hash> WindowRegistry<W> {
|
||||
&self.ids
|
||||
}
|
||||
|
||||
/// Overview render and hit order, with the newest ID in front. Normal
|
||||
/// stacking changes do not affect this independent presentation order.
|
||||
pub fn overview_windows(&self) -> impl DoubleEndedIterator<Item = &W> {
|
||||
self.overview_order.iter().rev().filter_map(|id| self.by_id.get(id))
|
||||
}
|
||||
|
||||
pub fn window(&self, id: WindowId) -> Option<&W> {
|
||||
self.by_id.get(&id)
|
||||
}
|
||||
|
||||
pub fn id_for_surface(&self, surface: &WlSurface) -> Option<WindowId> {
|
||||
self.surface_ids.get(surface).copied()
|
||||
}
|
||||
|
||||
pub fn ordered_ids(&self) -> impl DoubleEndedIterator<Item = WindowId> + '_ {
|
||||
self.overview_order.iter().copied()
|
||||
}
|
||||
|
||||
pub fn record(&self, id: WindowId) -> Option<&WindowRecord> {
|
||||
self.records.get(&id)
|
||||
}
|
||||
@@ -74,14 +113,14 @@ impl<W: Eq + Hash> WindowRegistry<W> {
|
||||
self.records.get_mut(&id)
|
||||
}
|
||||
|
||||
pub fn records_mut(&mut self) -> impl Iterator<Item = (&WindowId, &mut WindowRecord)> {
|
||||
self.records.iter_mut()
|
||||
}
|
||||
|
||||
pub fn records(&self) -> impl Iterator<Item = (&WindowId, &WindowRecord)> {
|
||||
self.records.iter()
|
||||
}
|
||||
|
||||
pub fn records_mut(&mut self) -> impl Iterator<Item = (&WindowId, &mut WindowRecord)> {
|
||||
self.records.iter_mut()
|
||||
}
|
||||
|
||||
pub fn take_world_positions(&mut self) -> HashMap<WindowId, (WorkspaceId, AnimatedValue)> {
|
||||
self.records
|
||||
.iter_mut()
|
||||
@@ -140,7 +179,17 @@ impl<W: Eq + Hash> WindowRegistry<W> {
|
||||
|
||||
pub fn remove(&mut self, window: &W) -> Option<WindowId> {
|
||||
let id = self.ids.remove(window)?;
|
||||
self.records.remove(&id);
|
||||
self.by_id.remove(&id);
|
||||
if let Some(record) = self.records.remove(&id)
|
||||
&& let Some(surface) = record.surface
|
||||
{
|
||||
self.surface_ids.remove(&surface);
|
||||
}
|
||||
let index = self
|
||||
.overview_order
|
||||
.binary_search_by_key(&id.0, |id| id.0)
|
||||
.expect("registered windows have an overview entry");
|
||||
self.overview_order.remove(index);
|
||||
|
||||
Some(id)
|
||||
}
|
||||
@@ -153,10 +202,96 @@ impl<W: Eq + Hash> WindowRegistry<W> {
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowRegistry<Window> {
|
||||
pub fn register_window(&mut self, window: Window, id: WindowId) {
|
||||
let surface = window.toplevel().map(|toplevel| toplevel.wl_surface().clone());
|
||||
self.register(window, id);
|
||||
|
||||
if let Some(surface) = surface {
|
||||
self.surface_ids.insert(surface.clone(), id);
|
||||
self.records.get_mut(&id).unwrap().surface = Some(surface.clone());
|
||||
self.refresh_metadata(&surface);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn refresh_metadata(&mut self, surface: &WlSurface) -> bool {
|
||||
let Some(id) = self.id_for_surface(surface) else {
|
||||
return false;
|
||||
};
|
||||
let record = self.records.get_mut(&id).unwrap();
|
||||
with_states(surface, |states| {
|
||||
let attributes = states.data_map.get::<XdgToplevelSurfaceData>().unwrap().lock().unwrap();
|
||||
let app_id = attributes.app_id.as_deref().unwrap_or_default();
|
||||
let title = attributes.title.as_deref().unwrap_or_default();
|
||||
let changed = record.app_id != app_id || record.title != title;
|
||||
|
||||
if changed {
|
||||
record.app_id.clear();
|
||||
record.app_id.push_str(app_id);
|
||||
record.title.clear();
|
||||
record.title.push_str(title);
|
||||
record.metadata_revision = record.metadata_revision.wrapping_add(1);
|
||||
}
|
||||
|
||||
changed
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn overview_order_tracks_registration_removal_and_remapping() {
|
||||
let mut windows = WindowRegistry::default();
|
||||
let first = windows.allocate_id();
|
||||
let second = windows.allocate_id();
|
||||
let third = windows.allocate_id();
|
||||
// Registration need not happen in allocation order.
|
||||
windows.register("second", second);
|
||||
windows.register("first", first);
|
||||
windows.register("third", third);
|
||||
assert_eq!(
|
||||
windows.overview_windows().copied().collect::<Vec<_>>(),
|
||||
["third", "second", "first"]
|
||||
);
|
||||
|
||||
windows.remove(&"second");
|
||||
assert_eq!(
|
||||
windows.overview_windows().copied().collect::<Vec<_>>(),
|
||||
["third", "first"]
|
||||
);
|
||||
windows.remove(&"first");
|
||||
let remapped = windows.allocate_id();
|
||||
windows.register("first", remapped);
|
||||
assert_eq!(
|
||||
windows.overview_windows().copied().collect::<Vec<_>>(),
|
||||
["first", "third"]
|
||||
);
|
||||
|
||||
windows.remove(&"first");
|
||||
windows.remove(&"third");
|
||||
assert_eq!(windows.overview_windows().count(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overview_iteration_borrows_handles_and_removal_releases_cached_handles() {
|
||||
let handle = std::rc::Rc::new("surface");
|
||||
let mut windows = WindowRegistry::default();
|
||||
let id = windows.allocate_id();
|
||||
windows.register(handle.clone(), id);
|
||||
assert_eq!(std::rc::Rc::strong_count(&handle), 3);
|
||||
|
||||
for _ in 0..100 {
|
||||
assert!(std::rc::Rc::ptr_eq(windows.overview_windows().next().unwrap(), &handle));
|
||||
assert_eq!(std::rc::Rc::strong_count(&handle), 3);
|
||||
}
|
||||
|
||||
windows.remove(&handle);
|
||||
assert_eq!(std::rc::Rc::strong_count(&handle), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unmap_drops_metadata_and_late_updates_cannot_resurrect_it() {
|
||||
let mut windows = WindowRegistry::default();
|
||||
|
||||
Reference in new issue
Block a user