From 1d739ac4b6e17f317623339414aabdb3440cdbec Mon Sep 17 00:00:00 2001 From: kossLAN Date: Fri, 29 May 2026 19:00:12 -0400 Subject: [PATCH] config: split output handling --- src/config/handler.rs | 475 +------------------------------- src/config/handler/outputs.rs | 499 ++++++++++++++++++++++++++++++++++ 2 files changed, 500 insertions(+), 474 deletions(-) create mode 100644 src/config/handler/outputs.rs diff --git a/src/config/handler.rs b/src/config/handler.rs index d0daf09e..e5095410 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -89,6 +89,7 @@ use { mod dispatch; mod matchers; +mod outputs; mod windows; pub(super) struct ConfigProxyHandler { @@ -319,79 +320,6 @@ impl ConfigProxyHandler { res } - fn handle_get_connectors( - &self, - dev: Option, - connected_only: bool, - ) -> Result<(), CphError> { - let datas: Vec<_>; - if let Some(dev) = dev { - let dev = self.get_drm_device(dev)?; - datas = dev.connectors.lock().values().cloned().collect(); - } else { - datas = self.state.connectors.lock().values().cloned().collect(); - } - let connectors = datas - .iter() - .flat_map(|d| match (connected_only, d.connected.get()) { - (false, _) | (true, true) => Some(Connector(d.connector.id().raw() as _)), - _ => None, - }) - .collect(); - self.respond(Response::GetConnectors { connectors }); - Ok(()) - } - - fn handle_get_drm_device_syspath(&self, dev: DrmDevice) -> Result<(), CphError> { - let dev = self.get_drm_device(dev)?; - let syspath = dev.syspath.clone().unwrap_or_default(); - self.respond(Response::GetDrmDeviceSyspath { syspath }); - Ok(()) - } - - fn handle_get_drm_device_devnode(&self, dev: DrmDevice) -> Result<(), CphError> { - let dev = self.get_drm_device(dev)?; - let devnode = dev.devnode.clone().unwrap_or_default(); - self.respond(Response::GetDrmDeviceDevnode { devnode }); - Ok(()) - } - - fn handle_get_drm_device_vendor(&self, dev: DrmDevice) -> Result<(), CphError> { - let dev = self.get_drm_device(dev)?; - let vendor = dev.vendor.clone().unwrap_or_default(); - self.respond(Response::GetDrmDeviceVendor { vendor }); - Ok(()) - } - - fn handle_get_drm_devices(&self) { - let devs = self.state.drm_devs.lock(); - let mut res = vec![]; - for dev in devs.values() { - res.push(DrmDevice(dev.dev.id().raw() as _)); - } - self.respond(Response::GetDrmDevices { devices: res }); - } - - fn handle_make_render_device(&self, dev: DrmDevice) -> Result<(), CphError> { - let dev = self.get_drm_device(dev)?; - dev.make_render_device(); - Ok(()) - } - - fn handle_get_drm_device_model(&self, dev: DrmDevice) -> Result<(), CphError> { - let dev = self.get_drm_device(dev)?; - let model = dev.model.clone().unwrap_or_default(); - self.respond(Response::GetDrmDeviceModel { model }); - Ok(()) - } - - fn handle_get_drm_device_pci_id(&self, dev: DrmDevice) -> Result<(), CphError> { - let dev = self.get_drm_device(dev)?; - let pci_id = dev.pci_id.unwrap_or_default(); - self.respond(Response::GetDrmDevicePciId { pci_id }); - Ok(()) - } - fn handle_reload(&self) { self.state.reload_config(); } @@ -1158,112 +1086,6 @@ impl ConfigProxyHandler { self.state.set_color_management_enabled(enabled); } - fn handle_connector_connected(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_connector(connector)?; - self.respond(Response::ConnectorConnected { - connected: connector.connected.get(), - }); - Ok(()) - } - - fn handle_connector_type(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_connector(connector)?; - self.respond(Response::ConnectorType { - ty: connector.connector.kernel_id().ty.to_config(), - }); - Ok(()) - } - - fn handle_connector_mode(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - let mode = connector.global.mode.get(); - self.respond(Response::ConnectorMode { - width: mode.width, - height: mode.height, - refresh_millihz: mode.refresh_rate_millihz, - }); - Ok(()) - } - - fn handle_connector_set_mode( - &self, - connector: Connector, - mode: WireMode, - ) -> Result<(), CphError> { - let connector = self.get_connector(connector)?; - connector - .modify_state(&self.state, |s| { - s.mode = backend::Mode { - width: mode.width, - height: mode.height, - refresh_rate_millihz: mode.refresh_millihz, - }; - }) - .map_err(CphError::ModifyConnectorState)?; - Ok(()) - } - - fn handle_connector_modes(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - self.respond(Response::ConnectorModes { - modes: connector - .global - .modes - .iter() - .flatten() - .map(|m| WireMode { - width: m.width, - height: m.height, - refresh_millihz: m.refresh_rate_millihz, - }) - .collect(), - }); - Ok(()) - } - - fn handle_connector_supports_arbitrary_modes( - &self, - connector: Connector, - ) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - self.respond(Response::ConnectorSupportsArbitraryModes { - supports_arbitrary_modes: connector.global.modes.is_none(), - }); - Ok(()) - } - - fn handle_connector_name(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_connector(connector)?; - self.respond(Response::GetConnectorName { - name: connector.name.deref().clone(), - }); - Ok(()) - } - - fn handle_connector_model(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output(connector)?; - self.respond(Response::GetConnectorModel { - model: connector.monitor_info.output_id.model.clone(), - }); - Ok(()) - } - - fn handle_connector_manufacturer(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output(connector)?; - self.respond(Response::GetConnectorManufacturer { - manufacturer: connector.monitor_info.output_id.manufacturer.clone(), - }); - Ok(()) - } - - fn handle_connector_serial_number(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output(connector)?; - self.respond(Response::GetConnectorSerialNumber { - serial_number: connector.monitor_info.output_id.serial_number.clone(), - }); - Ok(()) - } - fn handle_set_cursor_size(&self, seat: Seat, size: i32) -> Result<(), CphError> { let seat = self.get_seat(seat)?; if size < 0 { @@ -1290,113 +1112,6 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_connector_size(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - let pos = connector.global.pos.get(); - self.respond(Response::ConnectorSize { - width: pos.width(), - height: pos.height(), - }); - Ok(()) - } - - fn handle_connector_get_scale(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - self.respond(Response::ConnectorGetScale { - scale: connector.global.persistent.scale.get().to_f64(), - }); - Ok(()) - } - - fn handle_connector_set_scale(&self, connector: Connector, scale: f64) -> Result<(), CphError> { - if scale < 0.1 { - return Err(CphError::ScaleTooSmall(scale)); - } - if scale > 1000.0 { - return Err(CphError::ScaleTooLarge(scale)); - } - let scale = Scale::from_f64(scale); - let connector = self.get_output_node(connector)?; - connector.set_preferred_scale(scale); - Ok(()) - } - - fn handle_connector_set_format( - &self, - connector: Connector, - format: ConfigFormat, - ) -> Result<(), CphError> { - let Some(&format) = config_formats().get(&format) else { - return Err(CphError::UnknownFormat(format)); - }; - let connector = self.get_connector(connector)?; - connector - .modify_state(&self.state, |s| s.format = format) - .map_err(CphError::ModifyConnectorState)?; - Ok(()) - } - - fn handle_connector_set_colors( - &self, - connector: Connector, - color_space: ColorSpace, - eotf: ConfigEotf, - ) -> Result<(), CphError> { - let bcs = match color_space { - ColorSpace::DEFAULT => BackendColorSpace::Default, - ColorSpace::BT2020 => BackendColorSpace::Bt2020, - _ => return Err(CphError::UnknownColorSpace(color_space)), - }; - let btf = match eotf { - ConfigEotf::DEFAULT => BackendEotfs::Default, - ConfigEotf::PQ => BackendEotfs::Pq, - _ => return Err(CphError::UnknownEotf(eotf)), - }; - let connector = self.get_connector(connector)?; - connector - .modify_state(&self.state, |s| { - s.color_space = bcs; - s.eotf = btf; - }) - .map_err(CphError::ModifyConnectorState)?; - Ok(()) - } - - fn handle_connector_set_blend_space( - &self, - connector: Connector, - blend_space: ConfigBlendSpace, - ) -> Result<(), CphError> { - let blend_space = match blend_space { - ConfigBlendSpace::SRGB => BlendSpace::Srgb, - ConfigBlendSpace::LINEAR => BlendSpace::Linear, - _ => return Err(CphError::UnknownBlendSpace(blend_space)), - }; - let connector = self.get_output_node(connector)?; - connector.set_blend_space(blend_space); - Ok(()) - } - - fn handle_connector_set_brightness( - &self, - connector: Connector, - brightness: Option, - ) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - connector.set_brightness(brightness); - Ok(()) - } - - fn handle_connector_set_use_native_gamut( - &self, - connector: Connector, - use_native_gamut: bool, - ) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - connector.set_use_native_gamut(use_native_gamut); - Ok(()) - } - fn handle_set_float_above_fullscreen(&self, above: bool) { self.state.set_float_above_fullscreen(above); } @@ -1499,194 +1214,6 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_set_vrr_mode( - &self, - connector: Option, - mode: ConfigVrrMode, - ) -> Result<(), CphError> { - let Some(mode) = VrrMode::from_config(mode) else { - return Err(CphError::UnknownVrrMode(mode)); - }; - match connector { - Some(c) => { - let connector = self.get_output_node(c)?; - connector.set_vrr_mode(mode); - } - _ => self.state.default_vrr_mode.set(*mode), - } - Ok(()) - } - - fn handle_set_vrr_cursor_hz( - &self, - connector: Option, - hz: f64, - ) -> Result<(), CphError> { - match connector { - Some(c) => { - let connector = self.get_output_node(c)?; - connector.schedule.set_cursor_hz(hz); - } - _ => { - let Some((hz, _)) = map_cursor_hz(hz) else { - return Err(CphError::InvalidCursorHz(hz)); - }; - self.state.default_vrr_cursor_hz.set(hz) - } - } - Ok(()) - } - - fn handle_set_tearing_mode( - &self, - connector: Option, - mode: ConfigTearingMode, - ) -> Result<(), CphError> { - let Some(mode) = TearingMode::from_config(mode) else { - return Err(CphError::UnknownTearingMode(mode)); - }; - match connector { - Some(c) => { - let connector = self.get_output_node(c)?; - connector.set_tearing_mode(mode); - } - _ => self.state.default_tearing_mode.set(*mode), - } - Ok(()) - } - - fn handle_connector_set_transform( - &self, - connector: Connector, - transform: Transform, - ) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - connector.update_transform(transform.into()); - Ok(()) - } - - fn handle_connector_set_position( - &self, - connector: Connector, - x: i32, - y: i32, - ) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - if x < 0 || y < 0 || x > MAX_EXTENTS || y > MAX_EXTENTS { - return Err(CphError::InvalidConnectorPosition(x, y)); - } - connector.set_position(x, y); - Ok(()) - } - - fn handle_connector_get_position(&self, connector: Connector) -> Result<(), CphError> { - let connector = self.get_output_node(connector)?; - let (x, y) = connector.global.pos.get().position(); - self.respond(Response::ConnectorGetPosition { x, y }); - Ok(()) - } - - fn handle_connector_set_enabled( - &self, - connector: Connector, - enabled: bool, - ) -> Result<(), CphError> { - let connector = self.get_connector(connector)?; - connector - .modify_state(&self.state, |s| { - s.enabled = enabled; - }) - .map_err(CphError::ModifyConnectorState)?; - Ok(()) - } - - fn handle_get_connector( - &self, - ty: jay_config::video::connector_type::ConnectorType, - idx: u32, - ) -> Result<(), CphError> { - let connectors = self.state.connectors.lock(); - let connector = 'get_connector: { - for connector in connectors.values() { - let kid = connector.connector.kernel_id(); - if ty == kid.ty.to_config() && idx == kid.idx { - break 'get_connector Connector(connector.connector.id().raw() as _); - } - } - Connector(0) - }; - self.respond(Response::GetConnector { connector }); - Ok(()) - } - - fn handle_get_connector_by_name(&self, name: &str) { - let connector = self - .state - .connectors - .lock() - .values() - .find(|c| *c.name == name) - .map(|c| c.connector.id().raw() as _) - .map(Connector) - .unwrap_or(Connector(0)); - self.respond(Response::GetConnector { connector }); - } - - fn handle_create_virtual_output(&self, name: &str) { - self.state.virtual_outputs.get_or_create(&self.state, name); - } - - fn handle_remove_virtual_output(&self, name: &str) { - self.state.virtual_outputs.remove_output(&self.state, name); - } - - fn handle_get_connector_active_workspace(&self, connector: Connector) -> Result<(), CphError> { - let output = self.get_output_node(connector)?; - let workspace = output - .workspace - .get() - .map_or(Workspace(0), |ws| self.get_workspace_by_name(&ws.name)); - self.respond(Response::GetConnectorActiveWorkspace { workspace }); - Ok(()) - } - - fn handle_get_connector_workspaces(&self, connector: Connector) -> Result<(), CphError> { - let output = self.get_output_node(connector)?; - let workspaces = output - .workspaces - .iter() - .map(|ws| self.get_workspace_by_name(&ws.name)) - .collect::>(); - self.respond(Response::GetConnectorWorkspaces { workspaces }); - Ok(()) - } - - fn handle_get_workspace_connector(&self, workspace: Workspace) -> Result<(), CphError> { - let connector = self - .get_existing_workspace(workspace)? - .map(|ws| ws.output.get()) - .filter(|o| !o.is_dummy) - .map(|o| Connector(o.global.connector.id.raw() as _)) - .unwrap_or(Connector(0)); - self.respond(Response::GetWorkspaceConnector { connector }); - Ok(()) - } - - fn handle_get_connector_in_direction( - &self, - connector: Connector, - direction: Direction, - ) -> Result<(), CphError> { - let source_output = self.get_output_node(connector)?; - let connector = self - .state - .find_output_in_direction(&source_output, direction.into()) - .map(|o| Connector(o.global.connector.id.raw() as u64)) - .unwrap_or(Connector(0)); - self.respond(Response::GetConnectorInDirection { connector }); - Ok(()) - } - fn handle_has_capability(&self, device: InputDevice, cap: Capability) -> Result<(), CphError> { let dev = self.get_device_handler_data(device)?; let mut is_unknown = false; diff --git a/src/config/handler/outputs.rs b/src/config/handler/outputs.rs new file mode 100644 index 00000000..85cfb27c --- /dev/null +++ b/src/config/handler/outputs.rs @@ -0,0 +1,499 @@ +use super::*; + +impl ConfigProxyHandler { + pub(super) fn handle_get_connectors( + &self, + dev: Option, + connected_only: bool, + ) -> Result<(), CphError> { + let datas: Vec<_>; + if let Some(dev) = dev { + let dev = self.get_drm_device(dev)?; + datas = dev.connectors.lock().values().cloned().collect(); + } else { + datas = self.state.connectors.lock().values().cloned().collect(); + } + let connectors = datas + .iter() + .flat_map(|d| match (connected_only, d.connected.get()) { + (false, _) | (true, true) => Some(Connector(d.connector.id().raw() as _)), + _ => None, + }) + .collect(); + self.respond(Response::GetConnectors { connectors }); + Ok(()) + } + + pub(super) fn handle_get_drm_device_syspath(&self, dev: DrmDevice) -> Result<(), CphError> { + let dev = self.get_drm_device(dev)?; + let syspath = dev.syspath.clone().unwrap_or_default(); + self.respond(Response::GetDrmDeviceSyspath { syspath }); + Ok(()) + } + + pub(super) fn handle_get_drm_device_devnode(&self, dev: DrmDevice) -> Result<(), CphError> { + let dev = self.get_drm_device(dev)?; + let devnode = dev.devnode.clone().unwrap_or_default(); + self.respond(Response::GetDrmDeviceDevnode { devnode }); + Ok(()) + } + + pub(super) fn handle_get_drm_device_vendor(&self, dev: DrmDevice) -> Result<(), CphError> { + let dev = self.get_drm_device(dev)?; + let vendor = dev.vendor.clone().unwrap_or_default(); + self.respond(Response::GetDrmDeviceVendor { vendor }); + Ok(()) + } + + pub(super) fn handle_get_drm_devices(&self) { + let devs = self.state.drm_devs.lock(); + let mut res = vec![]; + for dev in devs.values() { + res.push(DrmDevice(dev.dev.id().raw() as _)); + } + self.respond(Response::GetDrmDevices { devices: res }); + } + + pub(super) fn handle_make_render_device(&self, dev: DrmDevice) -> Result<(), CphError> { + let dev = self.get_drm_device(dev)?; + dev.make_render_device(); + Ok(()) + } + + pub(super) fn handle_get_drm_device_model(&self, dev: DrmDevice) -> Result<(), CphError> { + let dev = self.get_drm_device(dev)?; + let model = dev.model.clone().unwrap_or_default(); + self.respond(Response::GetDrmDeviceModel { model }); + Ok(()) + } + + pub(super) fn handle_get_drm_device_pci_id(&self, dev: DrmDevice) -> Result<(), CphError> { + let dev = self.get_drm_device(dev)?; + let pci_id = dev.pci_id.unwrap_or_default(); + self.respond(Response::GetDrmDevicePciId { pci_id }); + Ok(()) + } + + pub(super) fn handle_connector_connected(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_connector(connector)?; + self.respond(Response::ConnectorConnected { + connected: connector.connected.get(), + }); + Ok(()) + } + + pub(super) fn handle_connector_type(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_connector(connector)?; + self.respond(Response::ConnectorType { + ty: connector.connector.kernel_id().ty.to_config(), + }); + Ok(()) + } + + pub(super) fn handle_connector_mode(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + let mode = connector.global.mode.get(); + self.respond(Response::ConnectorMode { + width: mode.width, + height: mode.height, + refresh_millihz: mode.refresh_rate_millihz, + }); + Ok(()) + } + + pub(super) fn handle_connector_set_mode( + &self, + connector: Connector, + mode: WireMode, + ) -> Result<(), CphError> { + let connector = self.get_connector(connector)?; + connector + .modify_state(&self.state, |s| { + s.mode = backend::Mode { + width: mode.width, + height: mode.height, + refresh_rate_millihz: mode.refresh_millihz, + }; + }) + .map_err(CphError::ModifyConnectorState)?; + Ok(()) + } + + pub(super) fn handle_connector_modes(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + self.respond(Response::ConnectorModes { + modes: connector + .global + .modes + .iter() + .flatten() + .map(|m| WireMode { + width: m.width, + height: m.height, + refresh_millihz: m.refresh_rate_millihz, + }) + .collect(), + }); + Ok(()) + } + + pub(super) fn handle_connector_supports_arbitrary_modes( + &self, + connector: Connector, + ) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + self.respond(Response::ConnectorSupportsArbitraryModes { + supports_arbitrary_modes: connector.global.modes.is_none(), + }); + Ok(()) + } + + pub(super) fn handle_connector_name(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_connector(connector)?; + self.respond(Response::GetConnectorName { + name: connector.name.deref().clone(), + }); + Ok(()) + } + + pub(super) fn handle_connector_model(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_output(connector)?; + self.respond(Response::GetConnectorModel { + model: connector.monitor_info.output_id.model.clone(), + }); + Ok(()) + } + + pub(super) fn handle_connector_manufacturer( + &self, + connector: Connector, + ) -> Result<(), CphError> { + let connector = self.get_output(connector)?; + self.respond(Response::GetConnectorManufacturer { + manufacturer: connector.monitor_info.output_id.manufacturer.clone(), + }); + Ok(()) + } + + pub(super) fn handle_connector_serial_number( + &self, + connector: Connector, + ) -> Result<(), CphError> { + let connector = self.get_output(connector)?; + self.respond(Response::GetConnectorSerialNumber { + serial_number: connector.monitor_info.output_id.serial_number.clone(), + }); + Ok(()) + } + + pub(super) fn handle_connector_size(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + let pos = connector.global.pos.get(); + self.respond(Response::ConnectorSize { + width: pos.width(), + height: pos.height(), + }); + Ok(()) + } + + pub(super) fn handle_connector_get_scale(&self, connector: Connector) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + self.respond(Response::ConnectorGetScale { + scale: connector.global.persistent.scale.get().to_f64(), + }); + Ok(()) + } + + pub(super) fn handle_connector_set_scale( + &self, + connector: Connector, + scale: f64, + ) -> Result<(), CphError> { + if scale < 0.1 { + return Err(CphError::ScaleTooSmall(scale)); + } + if scale > 1000.0 { + return Err(CphError::ScaleTooLarge(scale)); + } + let scale = Scale::from_f64(scale); + let connector = self.get_output_node(connector)?; + connector.set_preferred_scale(scale); + Ok(()) + } + + pub(super) fn handle_connector_set_format( + &self, + connector: Connector, + format: ConfigFormat, + ) -> Result<(), CphError> { + let Some(&format) = config_formats().get(&format) else { + return Err(CphError::UnknownFormat(format)); + }; + let connector = self.get_connector(connector)?; + connector + .modify_state(&self.state, |s| s.format = format) + .map_err(CphError::ModifyConnectorState)?; + Ok(()) + } + + pub(super) fn handle_connector_set_colors( + &self, + connector: Connector, + color_space: ColorSpace, + eotf: ConfigEotf, + ) -> Result<(), CphError> { + let bcs = match color_space { + ColorSpace::DEFAULT => BackendColorSpace::Default, + ColorSpace::BT2020 => BackendColorSpace::Bt2020, + _ => return Err(CphError::UnknownColorSpace(color_space)), + }; + let btf = match eotf { + ConfigEotf::DEFAULT => BackendEotfs::Default, + ConfigEotf::PQ => BackendEotfs::Pq, + _ => return Err(CphError::UnknownEotf(eotf)), + }; + let connector = self.get_connector(connector)?; + connector + .modify_state(&self.state, |s| { + s.color_space = bcs; + s.eotf = btf; + }) + .map_err(CphError::ModifyConnectorState)?; + Ok(()) + } + + pub(super) fn handle_connector_set_blend_space( + &self, + connector: Connector, + blend_space: ConfigBlendSpace, + ) -> Result<(), CphError> { + let blend_space = match blend_space { + ConfigBlendSpace::SRGB => BlendSpace::Srgb, + ConfigBlendSpace::LINEAR => BlendSpace::Linear, + _ => return Err(CphError::UnknownBlendSpace(blend_space)), + }; + let connector = self.get_output_node(connector)?; + connector.set_blend_space(blend_space); + Ok(()) + } + + pub(super) fn handle_connector_set_brightness( + &self, + connector: Connector, + brightness: Option, + ) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + connector.set_brightness(brightness); + Ok(()) + } + + pub(super) fn handle_connector_set_use_native_gamut( + &self, + connector: Connector, + use_native_gamut: bool, + ) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + connector.set_use_native_gamut(use_native_gamut); + Ok(()) + } + + pub(super) fn handle_set_vrr_mode( + &self, + connector: Option, + mode: ConfigVrrMode, + ) -> Result<(), CphError> { + let Some(mode) = VrrMode::from_config(mode) else { + return Err(CphError::UnknownVrrMode(mode)); + }; + match connector { + Some(c) => { + let connector = self.get_output_node(c)?; + connector.set_vrr_mode(mode); + } + _ => self.state.default_vrr_mode.set(*mode), + } + Ok(()) + } + + pub(super) fn handle_set_vrr_cursor_hz( + &self, + connector: Option, + hz: f64, + ) -> Result<(), CphError> { + match connector { + Some(c) => { + let connector = self.get_output_node(c)?; + connector.schedule.set_cursor_hz(hz); + } + _ => { + let Some((hz, _)) = map_cursor_hz(hz) else { + return Err(CphError::InvalidCursorHz(hz)); + }; + self.state.default_vrr_cursor_hz.set(hz) + } + } + Ok(()) + } + + pub(super) fn handle_set_tearing_mode( + &self, + connector: Option, + mode: ConfigTearingMode, + ) -> Result<(), CphError> { + let Some(mode) = TearingMode::from_config(mode) else { + return Err(CphError::UnknownTearingMode(mode)); + }; + match connector { + Some(c) => { + let connector = self.get_output_node(c)?; + connector.set_tearing_mode(mode); + } + _ => self.state.default_tearing_mode.set(*mode), + } + Ok(()) + } + + pub(super) fn handle_connector_set_transform( + &self, + connector: Connector, + transform: Transform, + ) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + connector.update_transform(transform.into()); + Ok(()) + } + + pub(super) fn handle_connector_set_position( + &self, + connector: Connector, + x: i32, + y: i32, + ) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + if x < 0 || y < 0 || x > MAX_EXTENTS || y > MAX_EXTENTS { + return Err(CphError::InvalidConnectorPosition(x, y)); + } + connector.set_position(x, y); + Ok(()) + } + + pub(super) fn handle_connector_get_position( + &self, + connector: Connector, + ) -> Result<(), CphError> { + let connector = self.get_output_node(connector)?; + let (x, y) = connector.global.pos.get().position(); + self.respond(Response::ConnectorGetPosition { x, y }); + Ok(()) + } + + pub(super) fn handle_connector_set_enabled( + &self, + connector: Connector, + enabled: bool, + ) -> Result<(), CphError> { + let connector = self.get_connector(connector)?; + connector + .modify_state(&self.state, |s| { + s.enabled = enabled; + }) + .map_err(CphError::ModifyConnectorState)?; + Ok(()) + } + + pub(super) fn handle_get_connector( + &self, + ty: jay_config::video::connector_type::ConnectorType, + idx: u32, + ) -> Result<(), CphError> { + let connectors = self.state.connectors.lock(); + let connector = 'get_connector: { + for connector in connectors.values() { + let kid = connector.connector.kernel_id(); + if ty == kid.ty.to_config() && idx == kid.idx { + break 'get_connector Connector(connector.connector.id().raw() as _); + } + } + Connector(0) + }; + self.respond(Response::GetConnector { connector }); + Ok(()) + } + + pub(super) fn handle_get_connector_by_name(&self, name: &str) { + let connector = self + .state + .connectors + .lock() + .values() + .find(|c| *c.name == name) + .map(|c| c.connector.id().raw() as _) + .map(Connector) + .unwrap_or(Connector(0)); + self.respond(Response::GetConnector { connector }); + } + + pub(super) fn handle_create_virtual_output(&self, name: &str) { + self.state.virtual_outputs.get_or_create(&self.state, name); + } + + pub(super) fn handle_remove_virtual_output(&self, name: &str) { + self.state.virtual_outputs.remove_output(&self.state, name); + } + + pub(super) fn handle_get_connector_active_workspace( + &self, + connector: Connector, + ) -> Result<(), CphError> { + let output = self.get_output_node(connector)?; + let workspace = output + .workspace + .get() + .map_or(Workspace(0), |ws| self.get_workspace_by_name(&ws.name)); + self.respond(Response::GetConnectorActiveWorkspace { workspace }); + Ok(()) + } + + pub(super) fn handle_get_connector_workspaces( + &self, + connector: Connector, + ) -> Result<(), CphError> { + let output = self.get_output_node(connector)?; + let workspaces = output + .workspaces + .iter() + .map(|ws| self.get_workspace_by_name(&ws.name)) + .collect::>(); + self.respond(Response::GetConnectorWorkspaces { workspaces }); + Ok(()) + } + + pub(super) fn handle_get_workspace_connector( + &self, + workspace: Workspace, + ) -> Result<(), CphError> { + let connector = self + .get_existing_workspace(workspace)? + .map(|ws| ws.output.get()) + .filter(|o| !o.is_dummy) + .map(|o| Connector(o.global.connector.id.raw() as _)) + .unwrap_or(Connector(0)); + self.respond(Response::GetWorkspaceConnector { connector }); + Ok(()) + } + + pub(super) fn handle_get_connector_in_direction( + &self, + connector: Connector, + direction: Direction, + ) -> Result<(), CphError> { + let source_output = self.get_output_node(connector)?; + let connector = self + .state + .find_output_in_direction(&source_output, direction.into()) + .map(|o| Connector(o.global.connector.id.raw() as u64)) + .unwrap_or(Connector(0)); + self.respond(Response::GetConnectorInDirection { connector }); + Ok(()) + } +}