use {
super::layer::{Layer, LayerConfig, LayerId, OverlayConstraints, WindowPlacement, Zone},
crate::{NavigateDirection, Rect, SplitDirection, WindowId},
};
#[derive(Debug, Clone)]
pub struct CompositeResult {
pub placements: Vec<WindowPlacement>,
pub focused: Option<WindowId>,
pub active_layer: Option<LayerId>,
pub screen: Rect,
}
impl CompositeResult {
#[must_use]
#[allow(clippy::missing_const_for_fn)] pub fn empty(screen: Rect) -> Self {
Self {
placements: Vec::new(),
focused: None,
active_layer: None,
screen,
}
}
#[must_use]
pub fn get_placement(&self, window: WindowId) -> Option<&WindowPlacement> {
self.placements.iter().find(|p| p.window_id == window)
}
}
pub trait RootCompositor: Send + Sync {
fn composite(&self, screen: Rect) -> CompositeResult;
fn create_layer(&mut self, config: LayerConfig) -> LayerId;
fn remove_layer(&mut self, layer: LayerId);
fn layer_by_label(&self, label: &str) -> Option<LayerId>;
fn layers(&self) -> Vec<&Layer>;
fn set_layer_visible(&mut self, layer: LayerId, visible: bool);
fn set_layer_opacity(&mut self, layer: LayerId, opacity: f32);
fn reorder_layer(&mut self, layer: LayerId, new_z: u16);
fn set_active_layer(&mut self, layer: LayerId);
fn active_layer(&self) -> Option<LayerId>;
fn set_focus(&mut self, window: WindowId);
fn focused(&self) -> Option<WindowId>;
fn focus_at(&mut self, x: u16, y: u16) -> Option<WindowId>;
fn layer_compositor(&self, layer: LayerId) -> Option<&dyn WindowLayerCompositor>;
fn layer_compositor_mut(&mut self, layer: LayerId) -> Option<&mut dyn WindowLayerCompositor>;
fn window_count(&self) -> usize;
fn set_screen(&mut self, screen: Rect);
fn layer_of(&self, window: WindowId) -> Option<LayerId>;
fn boxed_clone(&self) -> Box<dyn RootCompositor>;
}
pub trait WindowLayerCompositor: Send + Sync {
fn id(&self) -> LayerId;
fn arrange(&self, bounds: Rect) -> Vec<WindowPlacement>;
fn add_tiled(&mut self) -> WindowId;
fn split_tiled(&mut self, from: WindowId, direction: SplitDirection) -> Option<WindowId>;
fn navigate_tiled(&self, from: WindowId, direction: NavigateDirection) -> Option<WindowId>;
fn resize_tiled(&mut self, window: WindowId, direction: NavigateDirection, delta: i16);
fn close_tiled(&mut self, window: WindowId) -> Option<WindowId>;
fn equalize_tiled(&mut self);
fn cycle_tiled(&self, from: WindowId, forward: bool) -> Option<WindowId>;
fn create_float(&mut self, bounds: Rect) -> WindowId;
fn move_float(&mut self, window: WindowId, x: u16, y: u16);
fn resize_float(&mut self, window: WindowId, width: u16, height: u16);
fn raise_float(&mut self, window: WindowId);
fn lower_float(&mut self, window: WindowId);
fn close_float(&mut self, window: WindowId);
fn toggle_float(&mut self, window: WindowId);
fn show_overlay(&mut self, constraints: OverlayConstraints) -> WindowId;
fn hide_overlay(&mut self, window: WindowId);
fn resize_overlay(&mut self, window: WindowId, width: u16, height: u16);
fn hide_all_overlays(&mut self);
fn set_focus(&mut self, window: WindowId);
fn focused(&self) -> Option<WindowId>;
fn windows_in_zone(&self, zone: Zone) -> Vec<WindowId>;
fn zone_of(&self, window: WindowId) -> Option<Zone>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WindowError {
CannotCloseLastWindow,
NoNeighbor(NavigateDirection),
NotEnoughRoom,
CannotResizeAtEdge,
WindowNotFound(WindowId),
LayerNotFound(LayerId),
}
impl WindowError {
#[must_use]
pub const fn vim_code(&self) -> &'static str {
match self {
Self::CannotCloseLastWindow => "E444",
Self::NotEnoughRoom => "E94",
Self::NoNeighbor(_)
| Self::CannotResizeAtEdge
| Self::WindowNotFound(_)
| Self::LayerNotFound(_) => "E36",
}
}
#[must_use]
pub fn message(&self) -> String {
match self {
Self::CannotCloseLastWindow => "Cannot close last window".to_string(),
Self::NoNeighbor(dir) => format!("No window in direction: {dir:?}"),
Self::NotEnoughRoom => "Not enough room to split".to_string(),
Self::CannotResizeAtEdge => "Cannot resize at edge".to_string(),
Self::WindowNotFound(id) => format!("Window not found: {}", id.as_usize()),
Self::LayerNotFound(id) => format!("Layer not found: {}", id.as_u16()),
}
}
}
impl std::fmt::Display for WindowError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}: {}", self.vim_code(), self.message())
}
}
impl std::error::Error for WindowError {}
#[cfg(test)]
#[path = "compositor_tests.rs"]
mod tests;