diff --git a/docs/features.md b/docs/features.md index 75cdb96a..618887fe 100644 --- a/docs/features.md +++ b/docs/features.md @@ -176,6 +176,7 @@ Jay supports the following wayland protocols: | wl_subcompositor | 1 | | | wp_alpha_modifier_v1 | 1 | | | wp_color_manager_v1 | 2 | | +| wp_color_representation_manager_v1 | 1 | | | wp_commit_timing_manager_v1 | 1 | | | wp_content_type_manager_v1 | 1 | | | wp_cursor_shape_manager_v1 | 2 | | diff --git a/src/globals.rs b/src/globals.rs index 0a72aa48..d1731a3b 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -47,6 +47,7 @@ use { wlr_output_manager::zwlr_output_manager_v1::ZwlrOutputManagerV1Global, workspace_manager::ext_workspace_manager_v1::ExtWorkspaceManagerV1Global, wp_alpha_modifier_v1::WpAlphaModifierV1Global, + wp_color_representation_manager_v1::WpColorRepresentationManagerV1Global, wp_commit_timing_manager_v1::WpCommitTimingManagerV1Global, wp_content_type_manager_v1::WpContentTypeManagerV1Global, wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global, @@ -235,6 +236,7 @@ impl Globals { add_singleton!(WpPointerWarpV1Global); add_singleton!(JayPopupExtManagerV1Global); add_singleton!(ZwlrGammaControlManagerV1Global); + add_singleton!(WpColorRepresentationManagerV1Global); } pub fn add_backend_singletons(&self, backend: &Rc) { diff --git a/src/ifs.rs b/src/ifs.rs index 31def4a6..1036af14 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -56,6 +56,7 @@ pub mod wl_surface; pub mod wlr_output_manager; pub mod workspace_manager; pub mod wp_alpha_modifier_v1; +pub mod wp_color_representation_manager_v1; pub mod wp_commit_timing_manager_v1; pub mod wp_content_type_manager_v1; pub mod wp_content_type_v1; diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index c1d9b93d..4ef51ed3 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -6,6 +6,7 @@ pub mod tray; pub mod wl_subsurface; pub mod wp_alpha_modifier_surface_v1; pub mod wp_color_management_surface_v1; +pub mod wp_color_representation_surface_v1; pub mod wp_commit_timer_v1; pub mod wp_fifo_v1; pub mod wp_fractional_scale_v1; @@ -54,6 +55,7 @@ use { tray::TrayItemId, wl_subsurface::{PendingSubsurfaceData, SubsurfaceId, WlSubsurface}, wp_alpha_modifier_surface_v1::WpAlphaModifierSurfaceV1, + wp_color_representation_surface_v1::WpColorRepresentationSurfaceV1, wp_commit_timer_v1::WpCommitTimerV1, wp_fifo_v1::WpFifoV1, wp_fractional_scale_v1::WpFractionalScaleV1, @@ -350,6 +352,7 @@ pub struct WlSurface { color_management_feedback: CopyHashMap>, color_description: CloneCell>>, + color_representation_surface: CloneCell>>, } impl Debug for WlSurface { @@ -704,6 +707,7 @@ impl WlSurface { color_management_surface: Default::default(), color_management_feedback: Default::default(), color_description: Default::default(), + color_representation_surface: Default::default(), } } @@ -1786,6 +1790,7 @@ impl Object for WlSurface { self.commit_timer.take(); self.color_management_surface.take(); self.color_management_feedback.clear(); + self.color_representation_surface.take(); } } diff --git a/src/ifs/wl_surface/wp_color_representation_surface_v1.rs b/src/ifs/wl_surface/wp_color_representation_surface_v1.rs new file mode 100644 index 00000000..87300e28 --- /dev/null +++ b/src/ifs/wl_surface/wp_color_representation_surface_v1.rs @@ -0,0 +1,105 @@ +use { + crate::{ + client::{Client, ClientError}, + ifs::wl_surface::WlSurface, + leaks::Tracker, + object::{Object, Version}, + wire::{ + WpColorRepresentationSurfaceV1Id, + wp_color_representation_surface_v1::{ + Destroy, SetAlphaMode, SetChromaLocation, SetCoefficientsAndRange, + WpColorRepresentationSurfaceV1RequestHandler, + }, + }, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct WpColorRepresentationSurfaceV1 { + pub id: WpColorRepresentationSurfaceV1Id, + pub client: Rc, + pub version: Version, + pub tracker: Tracker, + pub surface: Rc, +} + +pub const AM_PREMULTIPLIED_ELECTRICAL: u32 = 0; +#[expect(dead_code)] +pub const AM_PREMULTIPLIED_OPTICAL: u32 = 1; +#[expect(dead_code)] +pub const AM_STRAIGHT: u32 = 2; + +impl WpColorRepresentationSurfaceV1 { + pub fn install(self: &Rc) -> Result<(), WpColorRepresentationSurfaceV1Error> { + if self.surface.color_representation_surface.is_some() { + return Err(WpColorRepresentationSurfaceV1Error::HasSurface); + } + self.surface + .color_representation_surface + .set(Some(self.clone())); + Ok(()) + } +} + +impl WpColorRepresentationSurfaceV1RequestHandler for WpColorRepresentationSurfaceV1 { + type Error = WpColorRepresentationSurfaceV1Error; + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.surface.color_representation_surface.take(); + self.client.remove_obj(self)?; + Ok(()) + } + + fn set_alpha_mode(&self, req: SetAlphaMode, _slf: &Rc) -> Result<(), Self::Error> { + if req.alpha_mode != AM_PREMULTIPLIED_ELECTRICAL { + return Err(WpColorRepresentationSurfaceV1Error::UnsupportedAlphaMode( + req.alpha_mode, + )); + } + Ok(()) + } + + fn set_coefficients_and_range( + &self, + req: SetCoefficientsAndRange, + _slf: &Rc, + ) -> Result<(), Self::Error> { + Err( + WpColorRepresentationSurfaceV1Error::UnsupportedCoefficientsAndRange( + req.coefficients, + req.range, + ), + ) + } + + fn set_chroma_location( + &self, + _req: SetChromaLocation, + _slf: &Rc, + ) -> Result<(), Self::Error> { + Ok(()) + } +} + +object_base! { + self = WpColorRepresentationSurfaceV1; + version = self.version; +} + +impl Object for WpColorRepresentationSurfaceV1 {} + +simple_add_obj!(WpColorRepresentationSurfaceV1); + +#[derive(Debug, Error)] +pub enum WpColorRepresentationSurfaceV1Error { + #[error(transparent)] + ClientError(Box), + #[error("wl_surface already has a color-representation extension")] + HasSurface, + #[error("{0} is not a supported alpha mode")] + UnsupportedAlphaMode(u32), + #[error("{0}/{1} are not supported coefficients and range")] + UnsupportedCoefficientsAndRange(u32, u32), +} +efrom!(WpColorRepresentationSurfaceV1Error, ClientError); diff --git a/src/ifs/wp_color_representation_manager_v1.rs b/src/ifs/wp_color_representation_manager_v1.rs new file mode 100644 index 00000000..9e43c8eb --- /dev/null +++ b/src/ifs/wp_color_representation_manager_v1.rs @@ -0,0 +1,134 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName}, + ifs::wl_surface::wp_color_representation_surface_v1::{ + AM_PREMULTIPLIED_ELECTRICAL, WpColorRepresentationSurfaceV1, + WpColorRepresentationSurfaceV1Error, + }, + leaks::Tracker, + object::{Object, Version}, + wire::{ + WpColorRepresentationManagerV1Id, + wp_color_representation_manager_v1::{ + Destroy, Done, GetSurface, SupportedAlphaMode, + WpColorRepresentationManagerV1RequestHandler, + }, + }, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct WpColorRepresentationManagerV1Global { + pub name: GlobalName, +} + +impl WpColorRepresentationManagerV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: WpColorRepresentationManagerV1Id, + client: &Rc, + version: Version, + ) -> Result<(), WpColorRepresentationManagerV1Error> { + let obj = Rc::new(WpColorRepresentationManagerV1 { + id, + client: client.clone(), + tracker: Default::default(), + version, + }); + track!(client, obj); + client.add_client_obj(&obj)?; + obj.send_capabilities(); + Ok(()) + } +} + +pub struct WpColorRepresentationManagerV1 { + pub id: WpColorRepresentationManagerV1Id, + pub client: Rc, + pub version: Version, + pub tracker: Tracker, +} + +impl WpColorRepresentationManagerV1 { + fn send_capabilities(&self) { + self.send_supported_alpha_mode(AM_PREMULTIPLIED_ELECTRICAL); + self.send_done(); + } + + fn send_supported_alpha_mode(&self, alpha_mode: u32) { + self.client.event(SupportedAlphaMode { + self_id: self.id, + alpha_mode, + }); + } + + fn send_done(&self) { + self.client.event(Done { self_id: self.id }); + } +} + +impl WpColorRepresentationManagerV1RequestHandler for WpColorRepresentationManagerV1 { + type Error = WpColorRepresentationManagerV1Error; + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.client.remove_obj(self)?; + Ok(()) + } + + fn get_surface(&self, req: GetSurface, _slf: &Rc) -> Result<(), Self::Error> { + let surface = self.client.lookup(req.surface)?; + let obj = Rc::new(WpColorRepresentationSurfaceV1 { + id: req.id, + client: self.client.clone(), + version: self.version, + tracker: Default::default(), + surface: surface.clone(), + }); + track!(self.client, obj); + self.client.add_client_obj(&obj)?; + obj.install()?; + Ok(()) + } +} + +global_base!( + WpColorRepresentationManagerV1Global, + WpColorRepresentationManagerV1, + WpColorRepresentationManagerV1Error +); + +impl Global for WpColorRepresentationManagerV1Global { + fn singleton(&self) -> bool { + true + } + + fn version(&self) -> u32 { + 1 + } +} + +simple_add_global!(WpColorRepresentationManagerV1Global); + +object_base! { + self = WpColorRepresentationManagerV1; + version = self.version; +} + +impl Object for WpColorRepresentationManagerV1 {} + +simple_add_obj!(WpColorRepresentationManagerV1); + +#[derive(Debug, Error)] +pub enum WpColorRepresentationManagerV1Error { + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + Surface(#[from] WpColorRepresentationSurfaceV1Error), +} +efrom!(WpColorRepresentationManagerV1Error, ClientError); diff --git a/wire/wp_color_representation_manager_v1.txt b/wire/wp_color_representation_manager_v1.txt new file mode 100644 index 00000000..c4975d4a --- /dev/null +++ b/wire/wp_color_representation_manager_v1.txt @@ -0,0 +1,19 @@ +request destroy (destructor) { +} + +request get_surface { + id: id(wp_color_representation_surface_v1) (new), + surface: id(wl_surface), +} + +event supported_alpha_mode { + alpha_mode: u32, +} + +event supported_coefficients_and_ranges { + coefficients: u32, + range: u32, +} + +event done { +} diff --git a/wire/wp_color_representation_surface_v1.txt b/wire/wp_color_representation_surface_v1.txt new file mode 100644 index 00000000..86a6af13 --- /dev/null +++ b/wire/wp_color_representation_surface_v1.txt @@ -0,0 +1,15 @@ +request destroy (destructor) { +} + +request set_alpha_mode { + alpha_mode: u32, +} + +request set_coefficients_and_range { + coefficients: u32, + range: u32, +} + +request set_chroma_location { + chroma_location: u32, +}