diff --git a/src/backend/transaction.rs b/src/backend/transaction.rs index e118af0c..dca5ac1a 100644 --- a/src/backend/transaction.rs +++ b/src/backend/transaction.rs @@ -2,9 +2,10 @@ use { crate::{ backend::{ BackendColorSpace, BackendConnectorState, BackendTransferFunction, Connector, - ConnectorKernelId, Mode, + ConnectorId, ConnectorKernelId, Mode, }, backends::metal::MetalError, + state::State, utils::{errorfmt::ErrorFmt, hash_map_ext::HashMapExt}, video::drm::DrmError, }, @@ -149,50 +150,74 @@ pub trait BackendAppliedConnectorTransaction { fn rollback(self: Box) -> Result<(), BackendConnectorTransactionError>; } -#[derive(Default)] +struct Common { + state: Rc, + states: AHashMap, +} + pub struct ConnectorTransaction { + common: Common, parts: AHashMap, Box>, } -#[derive(Default)] pub struct PreparedConnectorTransaction { + common: Common, parts: Vec>, } -#[derive(Default)] pub struct AppliedConnectorTransaction { + common: Common, parts: Vec>, } impl ConnectorTransaction { + pub fn new(state: &Rc) -> Self { + Self { + common: Common { + state: state.clone(), + states: Default::default(), + }, + parts: Default::default(), + } + } + pub fn add( &mut self, connector: &Rc, - change: BackendConnectorState, + mut state: BackendConnectorState, ) -> Result<(), BackendConnectorTransactionError> { + state.serial = self.common.state.backend_connector_state_serials.next(); let ty = connector.transaction_type(); let tran = match self.parts.entry(ty) { Entry::Occupied(v) => v.into_mut(), Entry::Vacant(v) => v.insert(connector.create_transaction()?), }; - tran.add(connector, change) + tran.add(connector, state)?; + self.common.states.insert(connector.id(), state); + Ok(()) } pub fn prepare( - &mut self, + mut self, ) -> Result { let mut new = vec![]; for tran in self.parts.drain_values() { new.push(tran.prepare()?); } - Ok(PreparedConnectorTransaction { parts: new }) + Ok(PreparedConnectorTransaction { + common: self.common, + parts: new, + }) } } impl PreparedConnectorTransaction { pub fn apply(self) -> Result { - let mut applied = AppliedConnectorTransaction::default(); + let mut applied = AppliedConnectorTransaction { + common: self.common, + parts: vec![], + }; for tran in self.parts { applied.parts.push(tran.apply()?); } @@ -205,6 +230,11 @@ impl AppliedConnectorTransaction { for tran in self.parts.drain(..) { tran.commit(); } + for (connector_id, state) in self.common.states.drain() { + if let Some(c) = self.common.state.connectors.get(&connector_id) { + c.set_state(&self.common.state, state); + } + } } } diff --git a/src/state.rs b/src/state.rs index b8e3dfad..a1277b09 100644 --- a/src/state.rs +++ b/src/state.rs @@ -422,14 +422,21 @@ impl ConnectorData { let mut tran = self.connector.create_transaction()?; tran.add(&self.connector, s)?; tran.prepare()?.apply()?.commit(); + self.set_state(state, s); + Ok(()) + } + + pub fn set_state(&self, state: &State, s: BackendConnectorState) { + let old = self.state.get(); + if old.serial >= s.serial { + return; + } + self.state.set(s); if let Some(output) = state.outputs.get(&self.connector.id()) && let Some(node) = &output.node { - node.update_state(s); - } else { - self.state.set(s); + node.update_state(old, s); } - Ok(()) } } diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index 9b9b752b..ca5eea28 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -105,10 +105,7 @@ impl ConnectorHandler { async fn handle_connected(&self, info: MonitorInfo) { log::info!("Connector {} connected", self.data.connector.kernel_id()); self.data.connected.set(true); - let old_state = self.data.state.get(); - if old_state.serial < info.state.serial { - self.data.state.set(info.state); - } + self.data.set_state(&self.state, info.state); let name = self.state.globals.name(); if info.non_desktop { self.handle_non_desktop_connected(info).await; @@ -290,7 +287,7 @@ impl ConnectorHandler { on.global.formats.set(formats); } ConnectorEvent::State(state) => { - on.update_state(state); + self.data.set_state(&self.state, state); } ev => unreachable!("received unexpected event {:?}", ev), } diff --git a/src/tasks/idle.rs b/src/tasks/idle.rs index b576b4bc..71db33e0 100644 --- a/src/tasks/idle.rs +++ b/src/tasks/idle.rs @@ -136,7 +136,7 @@ impl Idle { } fn try_set_idle(&self, idle: bool) -> Result<(), BackendConnectorTransactionError> { - let mut tran = ConnectorTransaction::default(); + let mut tran = ConnectorTransaction::new(&self.state); for connector in self.state.connectors.lock().values() { let mut state = connector.state.get(); state.active = !idle; diff --git a/src/tree/output.rs b/src/tree/output.rs index 924cd0f5..60c091ba 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -849,12 +849,7 @@ impl OutputNode { self.state.tree_changed(); } - pub fn update_state(self: &Rc, state: BackendConnectorState) { - let old = self.global.connector.state.get(); - if old.serial >= state.serial { - return; - } - self.global.connector.state.set(state); + pub fn update_state(self: &Rc, old: BackendConnectorState, state: BackendConnectorState) { self.update_btf_and_bcs(state.transfer_function, state.color_space); if old.vrr != state.vrr { self.schedule.set_vrr_enabled(state.vrr);