Files
feresaria/compositor/src/state/outputs.rs
T

176 lines
6.5 KiB
Rust

use super::*;
impl Ferese {
pub(crate) fn defer_output_redraw(&mut self, output: Output) {
if !self.output_redraw_pending.contains(&output) {
self.output_redraw_pending.push(output);
}
}
pub fn register_output(&mut self, output: &Output, identity: String) {
if self.output_ids.is_empty() {
self.reset_animation_clock();
}
if self.session_lock.active {
self.session_lock.output_added(output);
self.lock_input_activity();
}
let Some(geometry) = self.space.output_geometry(output) else {
tracing::error!(output = %output.name(), "cannot register an unmapped output");
return;
};
let output_id = *self.output_identity_ids.entry(identity).or_insert_with(|| {
let id = OutputId(self.next_output_id);
self.next_output_id = self.next_output_id.saturating_add(1);
id
});
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(_) => {
self.output_ids.insert(output.clone(), output_id);
self.outputs_by_id.insert(output_id, output.clone());
self.output_names.insert(output_id, output.name());
self.restore_output_focus();
let visible = self.visible_workspace_ids();
self.reconcile_workspaces(&visible);
self.send_shell_snapshots();
}
Err(error) => {
tracing::error!(%error, output = %output.name(), "failed to register output");
}
}
}
pub fn unregister_output(&mut self, output: &Output) {
self.display_presentation.remove_output(output);
self.refresh_idle_inhibition();
let Some(output_id) = self.output_ids.remove(output) else {
return;
};
self.output_redraw_pending.retain(|pending| pending != output);
self.outputs_by_id.remove(&output_id);
self.output_names.remove(&output_id);
self.workspace_slides.remove(&output_id);
self.render.remove_output(output_id);
self.pending_screencopies.retain(|capture| {
if capture.output == *output {
capture.fail();
false
} else {
true
}
});
self.space.unmap_output(output);
self.session_lock.surfaces.remove(output);
self.session_lock.backgrounds.remove(output);
self.session_lock.output_removed(output);
match self.output_workspaces.disconnect(output_id) {
Ok(Some(target)) => {
if let Some(workspace) = self.output_workspaces.active_workspace(target) {
self.activate_output_workspace(target, workspace);
}
}
Ok(None) => {
self.focused_window = None;
self.restore_keyboard_focus();
}
Err(error) => {
tracing::error!(%error, output = %output.name(), "failed to unregister output")
}
}
self.relayout();
}
pub(crate) fn reposition_output_floats(&mut self, output: OutputId, old: Rect, new: Rect) {
let floats = self
.windows
.ids()
.values()
.filter_map(|id| {
let workspace = self.workspaces.workspace_for_window(*id)?;
if self.output_workspaces.output_for_workspace(workspace) != Some(output) {
return None;
}
match self.workspaces.placement(*id)? {
WindowPlacement::Floating { rect } => Some((*id, moved_floating_rect(rect, old, new))),
_ => None,
}
})
.collect::<Vec<_>>();
for (id, rect) in floats {
let _ = self.workspaces.set_floating_rect(id, rect);
}
}
pub(super) fn activate_output_workspace(&mut self, output: OutputId, workspace: ferese_core::WorkspaceId) {
if let Err(error) = self.output_workspaces.focus_output(output) {
tracing::error!(%error, "failed to focus output");
return;
}
match self.workspaces.activate(workspace) {
Ok(focus) => self.focused_window = focus,
Err(error) => tracing::error!(%error, "failed to activate output workspace"),
}
}
pub(crate) fn focused_output(&self) -> Option<&Output> {
let focused = self.output_workspaces.focused_output()?;
self.outputs_by_id.get(&focused)
}
pub(crate) fn restore_output_focus(&mut self) {
if let Some(output) = self.output_workspaces.focused_output()
&& let Some(workspace) = self.output_workspaces.active_workspace(output)
{
self.activate_output_workspace(output, workspace);
self.restore_keyboard_focus();
}
}
pub(crate) fn output_id(&self, output: &Output) -> Option<OutputId> {
self.output_ids.get(output).copied()
}
pub(crate) fn focus_output_at(&mut self, position: Point<f64, Logical>) {
let output = self.space.outputs().find_map(|output| {
let geometry = self.space.output_geometry(output)?;
(position.x >= f64::from(geometry.loc.x)
&& position.y >= f64::from(geometry.loc.y)
&& position.x < f64::from(geometry.loc.x + geometry.size.w)
&& position.y < f64::from(geometry.loc.y + geometry.size.h))
.then(|| output.clone())
});
let Some(output) = output else {
return;
};
let Some(output_id) = self.output_ids.get(&output).copied() else {
return;
};
let Some(workspace) = self.output_workspaces.active_workspace(output_id) else {
return;
};
if self.output_workspaces.focused_output() == Some(output_id) && self.workspaces.active_id() == workspace {
return;
}
self.activate_output_workspace(output_id, workspace);
self.relayout();
}
}