Split shell, settings, and compositor into focused modules

This commit is contained in:
Samuel Onoja committed 2026-10-01 12:47:26 +01:00
1 parent 2b9f30fa5d
commit cbf048566a
38 files changed
+9998 -9817

No files matched your search

+232
View File
@@ -0,0 +1,232 @@
use super::*;
impl Ferese {
pub fn surface_under(&self, position: Point<f64, Logical>) -> Option<(WlSurface, Point<f64, Logical>)> {
if self.session_lock.active {
return self.lock_surface_under(position);
}
if self.input_capture.active() {
return None;
}
self.layer_surface_under(position, &[Layer::Overlay, Layer::Top])
.map(|(_, surface, origin)| (surface, origin))
.or_else(|| self.window_surface_under(position))
.or_else(|| {
self.layer_surface_under(position, &[Layer::Bottom, Layer::Background])
.map(|(_, surface, origin)| (surface, origin))
})
}
pub fn layer_under(&self, position: Point<f64, Logical>) -> Option<(LayerSurface, WlSurface, Point<f64, Logical>)> {
if self.session_lock.active {
return None;
}
if let Some(layer) = self.layer_surface_under(position, &[Layer::Overlay, Layer::Top]) {
return Some(layer);
}
if self.window_surface_under(position).is_some() {
return None;
}
self.layer_surface_under(position, &[Layer::Bottom, Layer::Background])
}
pub(super) fn window_surface_under(
&self,
position: Point<f64, Logical>,
) -> Option<(WlSurface, Point<f64, Logical>)> {
if self.overview.is_active() {
return None;
}
let workspace = self.workspace_under_pointer(position)?;
self.space.elements().rev().find_map(|window| {
let id = self.window_ids.get(window)?;
if self.workspaces.workspace_for_window(*id) != Some(workspace) {
return None;
}
let visual = self.presented_window_rect(*id)?;
let inside_visual = position.x >= visual.x
&& position.y >= visual.y
&& position.x < visual.x + visual.width
&& position.y < visual.y + visual.height;
if !inside_visual {
return None;
}
let (source_x, source_y) = self.inverse_presented_window_point(*id, position.x, position.y)?;
let source_point = Point::from((source_x, source_y)) + window.geometry().loc.to_f64();
let surface = window.surface_under(source_point, WindowSurfaceType::ALL);
let (surface, surface_location) = match surface {
Some(hit) => hit,
None if self.window_fills_visual_bounds(*id, workspace) => {
(window.toplevel()?.wl_surface().clone(), Point::from((0, 0)))
}
None => return None,
};
let surface_point = source_point - surface_location.to_f64();
Some((surface, position - surface_point))
})
}
pub(super) fn window_fills_visual_bounds(&self, id: WindowId, workspace: WorkspaceId) -> bool {
self.maximized_windows.contains(&id)
|| self
.workspaces
.workspace(workspace)
.is_some_and(|workspace| workspace.fullscreen == Some(id))
}
pub(super) fn layer_surface_under(
&self,
position: Point<f64, Logical>,
layers: &[Layer],
) -> Option<(LayerSurface, WlSurface, Point<f64, Logical>)> {
let output = self.space.output_under(position).next()?;
let output_geometry = self.space.output_geometry(output)?;
let output_position = position - output_geometry.loc.to_f64();
let map = layer_map_for_output(output);
for requested in layers {
if *requested == Layer::Top && self.output_has_fullscreen(output) {
continue;
}
for layer in map.layers_on(*requested).rev() {
let geometry = map.layer_geometry(layer)?;
let layer_position = output_position - geometry.loc.to_f64();
let Some((surface, surface_location)) = layer.surface_under(layer_position, WindowSurfaceType::ALL)
else {
continue;
};
let origin = output_geometry.loc + geometry.loc + surface_location;
return Some((layer.clone(), surface, origin.to_f64()));
}
}
None
}
pub fn send_cursor_frame(&self, output: &Output) {
let CursorImageStatus::Surface(surface) = &self.cursor_status else {
return;
};
let Some(pointer) = self.seat.get_pointer() else {
return;
};
if self.space.output_under(pointer.current_location()).next() != Some(output) {
return;
}
send_frames_surface_tree(
surface,
output,
self.start_time.elapsed(),
Some(Duration::ZERO),
|_, _| Some(output.clone()),
);
}
pub fn window_under_visual(&self, position: Point<f64, Logical>) -> Option<Window> {
let overview_active = self.overview.is_active();
let workspace = self.workspace_under_pointer(position)?;
let hit = |window: &Window| -> Option<Window> {
if !self.window_content_ready(window) {
return None;
}
let id = self.window_ids.get(window)?;
if self.workspaces.workspace_for_window(*id) != Some(workspace) {
return None;
}
let visual = self.presented_window_rect(*id)?;
let caption_height = if overview_active { 34.0 } else { 0.0 };
let inside_visual = position.x >= visual.x
&& position.y >= visual.y
&& position.x < visual.x + visual.width
&& position.y < visual.y + visual.height + caption_height;
if !inside_visual {
return None;
}
if !overview_active {
let (source_x, source_y) = self.inverse_presented_window_point(*id, position.x, position.y)?;
let source_point = Point::from((source_x, source_y)) + window.geometry().loc.to_f64();
if window.surface_under(source_point, WindowSurfaceType::ALL).is_none()
&& !self.window_fills_visual_bounds(*id, workspace)
{
return None;
}
}
Some(window.clone())
};
if overview_active {
let mut candidates = self.window_ids.keys().cloned().collect::<Vec<_>>();
// Match Overview's front-to-back render order during overlapping motion.
candidates.sort_by_key(|window| std::cmp::Reverse(self.window_ids.get(window).map_or(0, |id| id.0)));
candidates.iter().find_map(hit)
} else {
self.space.elements().rev().find_map(hit)
}
}
pub(super) fn workspace_under_pointer(&self, position: Point<f64, Logical>) -> Option<WorkspaceId> {
let output = self.space.output_under(position).next()?;
self.output_workspaces.active_workspace(self.output_id(output)?)
}
pub(crate) fn window_belongs_to_output(&self, window: WindowId, output: &Output) -> bool {
let Some(output_id) = self.output_id(output) else {
return false;
};
let workspace = self.workspaces.workspace_for_window(window);
workspace == self.output_workspaces.active_workspace(output_id)
|| self
.workspace_slides
.get(&output_id)
.is_some_and(|slide| workspace.is_some_and(|workspace| slide.contains(workspace)))
}
pub fn visual_scale_for_window(&self, window: &Window) -> Option<(f64, f64)> {
if !self.overview.is_presenting() {
return Some((1.0, 1.0));
}
let id = self.window_ids.get(window)?;
let geometry = self.window_geometry.get(id)?;
let source = geometry.client.committed_size?;
let presented = self.presented_window_rect(*id)?;
if source.width <= 0 || source.height <= 0 {
return None;
}
Some((
presented.width / f64::from(source.width),
presented.height / f64::from(source.height),
))
}
pub(crate) fn visual_rect_for_window(&self, window: &Window) -> Option<Rectangle<i32, Logical>> {
let id = self.window_ids.get(window)?;
let rect = self.presented_window_rect(*id)?;
let size = ClientSize::from_rect(rect);
Some(Rectangle::new(
(rect.x.round() as i32, rect.y.round() as i32).into(),
(size.width, size.height).into(),
))
}
pub(crate) fn window_content_ready(&self, window: &Window) -> bool {
window_has_buffer(window)
&& self
.window_ids
.get(window)
.and_then(|id| self.window_geometry.get(id))
.is_some_and(|geometry| geometry.client.committed_size.is_some())
}
}