diff --git a/src/api/layout.rs b/src/api/layout.rs index b3826f1..df7ad80 100644 --- a/src/api/layout.rs +++ b/src/api/layout.rs @@ -3,6 +3,7 @@ use pinnacle_api_defs::pinnacle::layout::v0alpha1::{ layout_service_server, LayoutRequest, LayoutResponse, }; use tonic::{Request, Response, Status, Streaming}; +use tracing::debug; use crate::output::OutputName; @@ -37,8 +38,7 @@ impl layout_service_server::LayoutService for LayoutService { match body { layout_request::Body::Geometries(geos) => { if let Err(err) = state.apply_layout(geos) { - // TODO: send a Status and handle the error client side - tracing::error!("{err}") + debug!("{err}") } } layout_request::Body::Layout(ExplicitLayout { output_name }) => { diff --git a/src/layout.rs b/src/layout.rs index be011ce..2815ae8 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,9 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use std::{ - collections::{HashMap, HashSet}, - time::Duration, -}; +use std::{collections::HashMap, time::Duration}; use pinnacle_api_defs::pinnacle::layout::v0alpha1::{layout_request::Geometries, LayoutResponse}; use smithay::{ @@ -165,23 +162,31 @@ impl Pinnacle { } /// A monotonically increasing identifier for layout requests. -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct LayoutRequestId(pub u32); +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct LayoutRequestId(u32); #[derive(Debug, Default)] pub struct LayoutState { pub layout_request_sender: Option<UnboundedSender<Result<LayoutResponse, Status>>>, pub pending_swap: bool, - id_maps: HashMap<Output, LayoutRequestId>, - pending_requests: HashMap<Output, Vec<(LayoutRequestId, Vec<WindowElement>)>>, - old_requests: HashMap<Output, HashSet<LayoutRequestId>>, + pending_requests: HashMap<Output, LayoutRequestId>, + fulfilled_requests: HashMap<Output, LayoutRequestId>, + current_id: LayoutRequestId, +} + +impl LayoutState { + fn next_id(&mut self) -> LayoutRequestId { + self.current_id.0 += 1; + self.current_id + } } impl Pinnacle { - pub fn request_layout(&mut self, output: &Output) { + pub fn request_layout(&mut self, output: &Output) -> Option<LayoutRequestId> { + let id = self.layout_state.next_id(); let Some(sender) = self.layout_state.layout_request_sender.as_ref() else { warn!("Layout requested but no client has connected to the layout service"); - return; + return None; }; let windows_on_foc_tags = output.with_state(|state| { @@ -220,19 +225,10 @@ impl Pinnacle { let tag_ids = output.with_state(|state| state.focused_tags().map(|tag| tag.id().0).collect()); - let id = self - .layout_state - .id_maps - .entry(output.clone()) - .or_insert(LayoutRequestId(0)); - self.layout_state .pending_requests - .entry(output.clone()) - .or_default() - .push((*id, windows)); + .insert(output.clone(), id); - // TODO: error let _ = sender.send(Ok(LayoutResponse { request_id: Some(id.0), output_name: Some(output.name()), @@ -242,7 +238,7 @@ impl Pinnacle { output_height: Some(output_height as u32), })); - *id = LayoutRequestId(id.0 + 1); + Some(id) } } @@ -262,41 +258,22 @@ impl State { anyhow::bail!("Output was invalid"); }; - let old_requests = self - .pinnacle - .layout_state - .old_requests - .entry(output.clone()) - .or_default(); - - if old_requests.contains(&request_id) { - anyhow::bail!("Attempted to layout but the request was already fulfilled"); - } - - let pending = self + let Some(current_pending) = self .pinnacle .layout_state .pending_requests - .entry(output.clone()) - .or_default(); - - let Some(latest) = pending.last().map(|(id, _)| *id) else { - anyhow::bail!("Attempted to layout but the request was nonexistent A"); + .get(&output) + .copied() + else { + anyhow::bail!("attempted to layout without request"); }; - if latest == request_id { - pending.pop(); - } else if let Some(pos) = pending - .split_last() - .and_then(|(_, rest)| rest.iter().position(|(id, _)| id == &request_id)) - { - // Ignore stale requests - old_requests.insert(request_id); - pending.remove(pos); - return Ok(()); - } else { - anyhow::bail!("Attempted to layout but the request was nonexistent B"); - }; + if current_pending > request_id { + anyhow::bail!("Attempted to layout but a new request came in"); + } + if current_pending < request_id { + anyhow::bail!("Attempted to layout but request is newer"); + } let geometries = geometries .into_iter() @@ -312,6 +289,12 @@ impl State { anyhow::bail!("Attempted to layout but one or more dimensions were null"); }; + self.pinnacle.layout_state.pending_requests.remove(&output); + self.pinnacle + .layout_state + .fulfilled_requests + .insert(output.clone(), current_pending); + self.pinnacle .update_windows_with_geometries(&output, geometries);