feat: make scrolling the active default layout

This commit is contained in:
Samuel Onoja committed 2026-09-25 02:08:04 +01:00
1 parent 8e4283bf16
commit 9d90415e55
13 files changed
+915 -56

No files matched your search

+57 -28
View File
@@ -7,8 +7,12 @@ use std::{
};
use ferese_animation::{ClientSize, SpringConfig, WindowGeometry};
use ferese_core::{OutputGeometry, OutputId, OutputWorkspaceMap, WindowPlacement, WorkspaceSet};
use ferese_layout::{Axis, Direction, GapConfig, LayoutResult, Rect, SizeConstraints, WindowId};
use ferese_core::{
LayoutMode, OutputGeometry, OutputId, OutputWorkspaceMap, WindowPlacement, WorkspaceSet,
};
use ferese_layout::{
Axis, ColumnWidth, Direction, GapConfig, LayoutResult, Rect, SizeConstraints, WindowId,
};
use smithay::{
backend::{
@@ -267,6 +271,8 @@ impl Ferese {
pub fn new(
event_loop: &mut EventLoop<'static, Self>,
display: Display<Self>,
default_layout_mode: LayoutMode,
default_column_width: ColumnWidth,
) -> Result<Self, Box<dyn Error>> {
let display_handle = display.handle();
crate::handlers::screencopy::init_global(&display_handle);
@@ -315,7 +321,7 @@ impl Ferese {
display_handle,
loop_signal: event_loop.get_signal(),
space: Space::default(),
workspaces: WorkspaceSet::default(),
workspaces: WorkspaceSet::new(default_layout_mode, default_column_width),
output_workspaces: OutputWorkspaceMap::default(),
output_ids: HashMap::new(),
output_identity_ids: HashMap::new(),
@@ -620,6 +626,7 @@ impl Ferese {
pub fn relayout(&mut self) {
self.arrange_layers();
let outputs = self.space.outputs().cloned().collect::<Vec<_>>();
let constraints = self.window_constraints();
let mut visible = HashSet::new();
let mut placements = Vec::new();
@@ -630,23 +637,28 @@ impl Ferese {
let Some(workspace_id) = self.output_workspaces.active_workspace(output_id) else {
continue;
};
let Some(workspace) = self.workspaces.workspace(workspace_id) else {
continue;
};
let Some(bounds) = self.output_bounds_for(&output) else {
continue;
};
let fullscreen_bounds = self.full_output_bounds_for(&output).unwrap_or(bounds);
let Some(workspace) = self.workspaces.workspace(workspace_id) else {
continue;
};
let workspace_fullscreen = workspace.fullscreen;
let workspace_focus = workspace.last_focused;
let focused = self
.focused_window
.filter(|window| {
self.workspaces.workspace_for_window(*window) == Some(workspace_id)
})
.or(workspace.last_focused);
.or(workspace_focus);
let Some(workspace) = self.workspaces.workspace_mut(workspace_id) else {
continue;
};
let layout = match workspace.layout.geometry_with_constraints(
bounds,
GapConfig::default(),
&self.window_constraints(),
&constraints,
focused,
) {
Ok(layout) => layout,
@@ -671,9 +683,9 @@ impl Ferese {
continue;
}
let rect = if workspace.fullscreen == Some(*id) {
let rect = if workspace_fullscreen == Some(*id) {
fullscreen_bounds
} else if workspace.fullscreen.is_some() {
} else if workspace_fullscreen.is_some() {
continue;
} else {
match self.workspaces.placement(*id) {
@@ -687,7 +699,7 @@ impl Ferese {
None => continue,
}
};
let is_fullscreen = workspace.fullscreen == Some(*id);
let is_fullscreen = workspace_fullscreen == Some(*id);
let is_floating = matches!(
self.workspaces.placement(*id),
Some(WindowPlacement::Floating { .. })
@@ -885,6 +897,8 @@ impl Ferese {
toplevel.send_pending_configure();
}
}
self.relayout();
}
pub fn move_direction(&mut self, direction: Direction) {
@@ -926,6 +940,22 @@ impl Ferese {
}
}
pub fn toggle_layout_mode(&mut self) {
let Some(bounds) = self.output_bounds() else {
return;
};
let mode = match self.workspaces.active().layout.mode() {
LayoutMode::Scrolling => LayoutMode::Tree,
LayoutMode::Tree => LayoutMode::Scrolling,
};
match self.workspaces.set_active_layout_mode(mode, bounds) {
Ok(true) => self.relayout(),
Ok(false) => {}
Err(error) => tracing::error!(%error, ?mode, "failed to change layout mode"),
}
}
pub fn toggle_focused_floating(&mut self) {
let Some(window) = self.focused_window else {
return;
@@ -1142,23 +1172,22 @@ impl Ferese {
}
}
fn logical_window_rect(&self, window: WindowId, bounds: Rect) -> Option<Rect> {
fn logical_window_rect(&mut self, window: WindowId, bounds: Rect) -> Option<Rect> {
let workspace = self.workspaces.workspace_for_window(window)?;
let workspace = self.workspaces.workspace(workspace)?;
let fullscreen = self.workspaces.workspace(workspace)?.fullscreen;
if workspace.fullscreen == Some(window) {
if fullscreen == Some(window) {
return Some(bounds);
}
let constraints = self.window_constraints();
let focused = self.focused_window;
match self.workspaces.placement(window)? {
WindowPlacement::Tiled => workspace
WindowPlacement::Tiled => self
.workspaces
.workspace_mut(workspace)?
.layout
.geometry_with_constraints(
bounds,
GapConfig::default(),
&self.window_constraints(),
self.focused_window,
)
.geometry_with_constraints(bounds, GapConfig::default(), &constraints, focused)
.ok()?
.geometry
.get(&window)
@@ -1167,13 +1196,13 @@ impl Ferese {
}
}
fn tiled_layout(&self, bounds: Rect) -> Result<LayoutResult, ferese_layout::LayoutError> {
self.workspaces.active().layout.geometry_with_constraints(
bounds,
GapConfig::default(),
&self.window_constraints(),
self.focused_window,
)
fn tiled_layout(&mut self, bounds: Rect) -> Result<LayoutResult, ferese_layout::LayoutError> {
let constraints = self.window_constraints();
let focused = self.focused_window;
self.workspaces
.active_mut()
.layout
.geometry_with_constraints(bounds, GapConfig::default(), &constraints, focused)
}
fn window_constraints(&self) -> HashMap<WindowId, SizeConstraints> {