Unify per-monitor workspace numbering and lifecycle policy

This commit is contained in:
Samuel Onoja committed 2026-10-01 18:24:12 +01:00
1 parent 07bda5a21c
commit 1441875096
20 files changed
+707 -316

No files matched your search

+1 -1
View File
@@ -313,7 +313,7 @@ impl Ferese {
})
.collect::<HashSet<_>>();
self.unmap_invisible_windows(&visible_windows);
self.prune_empty_workspaces(&visible);
self.reconcile_workspaces(&visible);
self.send_shell_snapshots();
active_animation = true;
}
+6 -6
View File
@@ -15,11 +15,11 @@ impl Ferese {
visible
}
pub(super) fn prune_empty_workspaces(&mut self, visible: &HashSet<WorkspaceId>) {
let mut protected = visible.clone();
protected.extend(self.output_workspaces.history_workspaces());
for workspace in self.workspaces.prune_empty(&protected) {
self.output_workspaces.forget_workspace(workspace);
pub(super) fn reconcile_workspaces(&mut self, visible: &HashSet<WorkspaceId>) {
for workspace in self
.output_workspaces
.reconcile_workspaces(&mut self.workspaces, visible)
{
self.viewport_animations.remove(&workspace);
}
}
@@ -52,7 +52,7 @@ impl Ferese {
pub fn relayout(&mut self) {
self.refresh_input_capture_zones();
let visible_workspaces = self.visible_workspace_ids();
self.prune_empty_workspaces(&visible_workspaces);
self.reconcile_workspaces(&visible_workspaces);
if self.session_lock.active {
self.configure_lock_surfaces();
}
+14 -20
View File
@@ -394,16 +394,13 @@ impl Ferese {
slide_direction: Option<SwipeDirection>,
auto_back_and_forth: bool,
) {
let workspace = match self.workspaces.ensure_numeric(index) {
Ok(workspace) => workspace,
Err(error) => {
tracing::error!(%error, index, "failed to switch workspace");
return;
}
};
let Some(output) = self.output_workspaces.focused_output() else {
return;
};
let Some(workspace) = self.output_workspaces.workspace_at(&self.workspaces, output, index) else {
return;
};
let previous = self.output_workspaces.active_workspace(output);
let owner = match self
.output_workspaces
@@ -526,26 +523,23 @@ impl Ferese {
let Some(window) = self.focused_window else {
return;
};
let Some(output) = self.output_workspaces.focused_output() else {
return;
};
let Some(destination) = self.output_workspaces.workspace_at(&self.workspaces, output, index) else {
return;
};
let axis = self
.output_bounds()
.and_then(|bounds| {
let workspace = self.workspaces.ensure_numeric(index).ok()?;
let target = self.workspaces.workspace(workspace)?;
let target = self.workspaces.workspace(destination)?;
target.layout.automatic_axis(target.last_focused, bounds).ok()
})
.unwrap_or(Axis::Horizontal);
let destination = match self.workspaces.move_window_to_numeric(window, index, axis, 0.5) {
Ok(destination) => destination,
Err(error) => {
tracing::error!(%error, ?window, index, "failed to move window to workspace");
return;
}
};
if let Some(output) = self.output_workspaces.focused_output()
&& let Err(error) = self.output_workspaces.assign_workspace(output, destination)
{
tracing::error!(%error, ?destination, "failed to assign destination workspace");
if let Err(error) = self.workspaces.move_window_to_workspace(window, destination, axis, 0.5) {
tracing::error!(%error, ?window, index, "failed to move window to workspace");
return;
}
self.focused_window = self.workspaces.active().last_focused;
+11 -13
View File
@@ -15,25 +15,23 @@ impl Ferese {
self.next_output_id = self.next_output_id.saturating_add(1);
id
});
let fallback_workspace = (1..)
.find_map(|index| {
let workspace = self.workspaces.ensure_numeric(index).ok()?;
self.output_workspaces
.output_for_workspace(workspace)
.is_none()
.then_some(workspace)
})
.expect("numeric workspaces are inexhaustible");
let fallback_workspace = self
.workspaces
.iter()
.filter(|workspace| self.output_workspaces.output_for_workspace(workspace.id).is_none())
.map(|workspace| workspace.id)
.min_by_key(|id| id.0)
.unwrap_or_else(|| self.workspaces.create_workspace());
let geometry = OutputGeometry::new(geometry.loc.x, geometry.loc.y, geometry.size.w, geometry.size.h);
let registration = self.output_workspaces.connect(output_id, geometry, fallback_workspace);
match registration {
Ok(workspace) => {
Ok(_) => {
self.output_ids.insert(output.clone(), output_id);
if self.output_workspaces.focused_output() == Some(output_id) {
self.activate_output_workspace(output_id, workspace);
}
self.restore_output_focus();
let visible = self.visible_workspace_ids();
self.reconcile_workspaces(&visible);
self.send_shell_snapshots();
}
Err(error) => {
+8 -3
View File
@@ -287,10 +287,15 @@ impl Ferese {
.automatic_axis(self.focused_window, bounds)
.unwrap_or(Axis::Horizontal);
if let Some(workspace) = rule.workspace
&& let Err(error) = self.workspaces.move_window_to_numeric(id, workspace, axis, 0.5)
if let Some(index) = rule.workspace
&& let Some(output) = self
.workspaces
.workspace_for_window(id)
.and_then(|workspace| self.output_workspaces.output_for_workspace(workspace))
&& let Some(workspace) = self.output_workspaces.workspace_at(&self.workspaces, output, index)
&& let Err(error) = self.workspaces.move_window_to_workspace(id, workspace, axis, 0.5)
{
tracing::warn!(%error, ?id, workspace, "failed to apply window workspace rule");
tracing::warn!(%error, ?id, ?workspace, "failed to apply window workspace rule");
}
let bounds = self.floating_bounds_for_window(id).unwrap_or(bounds);