From 7e69a80dbcf3381a19cb212440a84b263b946802 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 12 Jul 2025 09:33:44 +0200 Subject: [PATCH] head-management: add mode-setter-v1 extension --- src/ifs/head_management.rs | 5 ++ .../head_management/head_management_macros.rs | 1 + src/ifs/head_management/jay_head_ext.rs | 1 + .../jay_head_ext_mode_setter_v1.rs | 90 +++++++++++++++++++ .../jay_head_manager_session_v1.rs | 7 ++ wire/jay_head_ext_mode_setter_v1.txt | 17 ++++ wire/jay_head_manager_ext_mode_setter_v1.txt | 7 ++ 7 files changed, 128 insertions(+) create mode 100644 src/ifs/head_management/jay_head_ext/jay_head_ext_mode_setter_v1.rs create mode 100644 wire/jay_head_ext_mode_setter_v1.txt create mode 100644 wire/jay_head_manager_ext_mode_setter_v1.txt diff --git a/src/ifs/head_management.rs b/src/ifs/head_management.rs index 93a224c6..2333ff88 100644 --- a/src/ifs/head_management.rs +++ b/src/ifs/head_management.rs @@ -108,6 +108,7 @@ enum HeadOp { SetConnectorEnabled(bool), SetTransform(Transform), SetScale(Scale), + SetMode(usize), } #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -222,6 +223,10 @@ impl HeadManagers { ext.send_mode(state); head.session.schedule_done(); } + if let Some(ext) = &head.ext.mode_setter_v1 { + ext.send_modes(state); + head.session.schedule_done(); + } if let Some(ext) = &head.ext.compositor_space_info_v1 { ext.send_inside_outside(state); head.session.schedule_done(); diff --git a/src/ifs/head_management/head_management_macros.rs b/src/ifs/head_management/head_management_macros.rs index 54b10996..1149819a 100644 --- a/src/ifs/head_management/head_management_macros.rs +++ b/src/ifs/head_management/head_management_macros.rs @@ -396,4 +396,5 @@ declare_extensions! { compositor_space_enabler_v1: CompositorSpaceEnablerV1, connector_info_v1: ConnectorInfoV1, mode_info_v1: ModeInfoV1, + mode_setter_v1: ModeSetterV1, } diff --git a/src/ifs/head_management/jay_head_ext.rs b/src/ifs/head_management/jay_head_ext.rs index af8d366a..427b5ea5 100644 --- a/src/ifs/head_management/jay_head_ext.rs +++ b/src/ifs/head_management/jay_head_ext.rs @@ -6,3 +6,4 @@ pub(super) mod jay_head_ext_compositor_space_transformer_v1; pub(super) mod jay_head_ext_connector_info_v1; pub(super) mod jay_head_ext_core_info_v1; pub(super) mod jay_head_ext_mode_info_v1; +pub(super) mod jay_head_ext_mode_setter_v1; diff --git a/src/ifs/head_management/jay_head_ext/jay_head_ext_mode_setter_v1.rs b/src/ifs/head_management/jay_head_ext/jay_head_ext_mode_setter_v1.rs new file mode 100644 index 00000000..7fb64c2f --- /dev/null +++ b/src/ifs/head_management/jay_head_ext/jay_head_ext_mode_setter_v1.rs @@ -0,0 +1,90 @@ +use { + crate::{ + backend::CONCAP_MODE_SETTING, + ifs::head_management::{HeadCommon, HeadOp, HeadState}, + state::ConnectorData, + wire::{ + jay_head_ext_mode_setter_v1::{ + JayHeadExtModeSetterV1RequestHandler, Mode, Reset, SetMode, + }, + jay_head_manager_ext_mode_setter_v1::JayHeadManagerExtModeSetterV1RequestHandler, + }, + }, + std::rc::Rc, +}; + +impl_mode_setter_v1! { + version = 1, + filter = filter, + after_announce = after_announce, + after_transaction = after_transaction, +} + +impl MgrName { + fn filter(&self, connector: &ConnectorData, _common: &Rc) -> bool { + connector.connector.caps().contains(CONCAP_MODE_SETTING) + } +} + +impl HeadName { + fn after_announce(&self, shared: &HeadState) { + self.send_modes(shared); + } + + fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { + match (&shared.monitor_info, &tran.monitor_info) { + (Some(s), Some(t)) if s != t => {} + _ => return, + } + self.send_modes(shared); + } + + pub(in super::super) fn send_modes(&self, state: &HeadState) { + self.client.event(Reset { self_id: self.id }); + if let Some(mi) = &state.monitor_info { + for mode in &mi.modes { + self.client.event(Mode { + self_id: self.id, + width: mode.width, + height: mode.height, + refresh_mhz: mode.refresh_rate_millihz, + }) + } + } + } +} + +impl JayHeadManagerExtModeSetterV1RequestHandler for MgrName { + type Error = ErrorName; + + mgr_common_req!(); +} + +impl JayHeadExtModeSetterV1RequestHandler for HeadName { + type Error = ErrorName; + + head_common_req!(); + + fn set_mode(&self, req: SetMode, _slf: &Rc) -> Result<(), Self::Error> { + self.common.assert_in_transaction()?; + let num_modes = self + .common + .snapshot_state + .borrow() + .monitor_info + .as_deref() + .map(|i| i.modes.len()) + .unwrap_or(0); + let idx = req.idx as usize; + if idx >= num_modes { + return Err(JayHeadExtModeSetterV1Error::ModeOutOfBounds); + } + self.common.push_op(HeadOp::SetMode(idx))?; + Ok(()) + } +} + +error! { + #[error("The mode is out of bounds")] + ModeOutOfBounds, +} diff --git a/src/ifs/head_management/jay_head_manager_session_v1.rs b/src/ifs/head_management/jay_head_manager_session_v1.rs index 82c6ea38..ecd51f3b 100644 --- a/src/ifs/head_management/jay_head_manager_session_v1.rs +++ b/src/ifs/head_management/jay_head_manager_session_v1.rs @@ -264,6 +264,7 @@ impl JayHeadManagerSessionV1 { let old = connector.state.get(); let mut new = old; new.enabled = desired.connector_enabled; + new.mode = desired.mode; if old == new { continue; } @@ -414,6 +415,12 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { to_send |= COMPOSITOR_SPACE_INFO_SCALE; to_send |= COMPOSITOR_SPACE_INFO_SIZE; } + HeadOp::SetMode(i) => { + state.mode = snapshot.monitor_info.as_deref().unwrap().modes[i]; + state.update_size(); + to_send |= MODE_INFO; + to_send |= COMPOSITOR_SPACE_INFO_SIZE; + } } } if to_send.contains(CORE_INFO) diff --git a/wire/jay_head_ext_mode_setter_v1.txt b/wire/jay_head_ext_mode_setter_v1.txt new file mode 100644 index 00000000..b575a8ba --- /dev/null +++ b/wire/jay_head_ext_mode_setter_v1.txt @@ -0,0 +1,17 @@ +request destroy (destructor) { + +} + +request set_mode { + idx: u32, +} + +event reset { + +} + +event mode { + width: i32, + height: i32, + refresh_mhz: u32, +} diff --git a/wire/jay_head_manager_ext_mode_setter_v1.txt b/wire/jay_head_manager_ext_mode_setter_v1.txt new file mode 100644 index 00000000..676efbb3 --- /dev/null +++ b/wire/jay_head_manager_ext_mode_setter_v1.txt @@ -0,0 +1,7 @@ +request destroy (destructor) { + +} + +event head { + head: id(jay_head_ext_mode_setter_v1) (new), +}