metal: allow configuring color space and transfer function
This commit is contained in:
parent
04f280aabe
commit
bb56efb968
38 changed files with 1365 additions and 160 deletions
|
|
@ -1,7 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::color_management::wp_image_description_v1::WpImageDescriptionV1,
|
||||
ifs::{
|
||||
color_management::{CAUSE_NO_OUTPUT, wp_image_description_v1::WpImageDescriptionV1},
|
||||
wl_output::OutputGlobalOpt,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{WpColorManagementOutputV1Id, wp_color_management_output_v1::*},
|
||||
|
|
@ -15,20 +18,29 @@ pub struct WpColorManagementOutputV1 {
|
|||
pub client: Rc<Client>,
|
||||
pub version: Version,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub output: Rc<OutputGlobalOpt>,
|
||||
}
|
||||
|
||||
impl WpColorManagementOutputV1 {
|
||||
#[expect(dead_code)]
|
||||
pub fn send_image_description_changed(&self) {
|
||||
self.client
|
||||
.event(ImageDescriptionChanged { self_id: self.id });
|
||||
}
|
||||
|
||||
fn detach(&self) {
|
||||
if let Some(output) = self.output.get() {
|
||||
output
|
||||
.color_description_listeners
|
||||
.remove(&(self.client.id, self.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WpColorManagementOutputV1RequestHandler for WpColorManagementOutputV1 {
|
||||
type Error = WpColorManagementOutputV1Error;
|
||||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.detach();
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -43,11 +55,15 @@ impl WpColorManagementOutputV1RequestHandler for WpColorManagementOutputV1 {
|
|||
client: self.client.clone(),
|
||||
version: self.version,
|
||||
tracker: Default::default(),
|
||||
description: self.client.state.color_manager.srgb_srgb().clone(),
|
||||
description: self.output.get().map(|o| o.color_description.get()),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
obj.send_ready();
|
||||
if obj.description.is_some() {
|
||||
obj.send_ready();
|
||||
} else {
|
||||
obj.send_failed(CAUSE_NO_OUTPUT, "the output no longer exists");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -57,7 +73,11 @@ object_base! {
|
|||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for WpColorManagementOutputV1 {}
|
||||
impl Object for WpColorManagementOutputV1 {
|
||||
fn break_loops(&self) {
|
||||
self.detach();
|
||||
}
|
||||
}
|
||||
|
||||
simple_add_obj!(WpColorManagementOutputV1);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
client::{Client, ClientError},
|
||||
ifs::color_management::wp_image_description_v1::WpImageDescriptionV1,
|
||||
cmm::cmm_description::ColorDescription,
|
||||
ifs::{
|
||||
color_management::wp_image_description_v1::WpImageDescriptionV1, wl_surface::WlSurface,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
wire::{
|
||||
|
|
@ -18,6 +21,7 @@ pub struct WpColorManagementSurfaceFeedbackV1 {
|
|||
pub client: Rc<Client>,
|
||||
pub version: Version,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub surface: Rc<WlSurface>,
|
||||
}
|
||||
|
||||
impl WpColorManagementSurfaceFeedbackV1 {
|
||||
|
|
@ -30,13 +34,20 @@ impl WpColorManagementSurfaceFeedbackV1 {
|
|||
client: self.client.clone(),
|
||||
version: self.version,
|
||||
tracker: Default::default(),
|
||||
description: self.client.state.color_manager.srgb_srgb().clone(),
|
||||
description: Some(self.surface.get_output().global.color_description.get()),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
obj.send_ready();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn send_preferred_changed(&self, cd: &ColorDescription) {
|
||||
self.client.event(PreferredChanged {
|
||||
self_id: self.id,
|
||||
identity: cd.id.raw(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl WpColorManagementSurfaceFeedbackV1RequestHandler for WpColorManagementSurfaceFeedbackV1 {
|
||||
|
|
@ -44,6 +55,7 @@ impl WpColorManagementSurfaceFeedbackV1RequestHandler for WpColorManagementSurfa
|
|||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.client.remove_obj(self)?;
|
||||
self.surface.remove_color_management_feedback(self);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,15 +147,21 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
|
|||
}
|
||||
|
||||
fn get_output(&self, req: GetOutput, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let _ = self.client.lookup(req.output)?;
|
||||
let output = self.client.lookup(req.output)?;
|
||||
let obj = Rc::new(WpColorManagementOutputV1 {
|
||||
id: req.id,
|
||||
client: self.client.clone(),
|
||||
version: self.version,
|
||||
tracker: Default::default(),
|
||||
output: output.global.clone(),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
if let Some(global) = output.global.get() {
|
||||
global
|
||||
.color_description_listeners
|
||||
.set((self.client.id, req.id), obj);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -179,15 +185,17 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
|
|||
req: GetSurfaceFeedback,
|
||||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
let _ = self.client.lookup(req.surface)?;
|
||||
let surface = self.client.lookup(req.surface)?;
|
||||
let obj = Rc::new(WpColorManagementSurfaceFeedbackV1 {
|
||||
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)?;
|
||||
surface.add_color_management_feedback(&obj);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +240,7 @@ impl WpColorManagerV1RequestHandler for WpColorManagerV1 {
|
|||
client: self.client.clone(),
|
||||
version: self.version,
|
||||
tracker: Default::default(),
|
||||
description: self.client.state.color_manager.windows_scrgb().clone(),
|
||||
description: Some(self.client.state.color_manager.windows_scrgb().clone()),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ impl WpImageDescriptionCreatorParamsV1RequestHandler for WpImageDescriptionCreat
|
|||
client: self.client.clone(),
|
||||
version: self.version,
|
||||
tracker: Default::default(),
|
||||
description,
|
||||
description: Some(description),
|
||||
});
|
||||
track!(self.client, obj);
|
||||
self.client.add_client_obj(&obj)?;
|
||||
|
|
|
|||
|
|
@ -16,11 +16,10 @@ pub struct WpImageDescriptionV1 {
|
|||
pub client: Rc<Client>,
|
||||
pub version: Version,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub description: Rc<ColorDescription>,
|
||||
pub description: Option<Rc<ColorDescription>>,
|
||||
}
|
||||
|
||||
impl WpImageDescriptionV1 {
|
||||
#[expect(dead_code)]
|
||||
pub fn send_failed(&self, cause: u32, msg: &str) {
|
||||
self.client.event(Failed {
|
||||
self_id: self.id,
|
||||
|
|
@ -32,7 +31,7 @@ impl WpImageDescriptionV1 {
|
|||
pub fn send_ready(&self) {
|
||||
self.client.event(Ready {
|
||||
self_id: self.id,
|
||||
identity: self.description.id.into(),
|
||||
identity: self.description.as_ref().unwrap().id.raw(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -46,6 +45,9 @@ impl WpImageDescriptionV1RequestHandler for WpImageDescriptionV1 {
|
|||
}
|
||||
|
||||
fn get_information(&self, req: GetInformation, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let Some(desc) = &self.description else {
|
||||
return Err(WpImageDescriptionV1Error::NotReady);
|
||||
};
|
||||
let obj = Rc::new(WpImageDescriptionInfoV1 {
|
||||
id: req.information,
|
||||
client: self.client.clone(),
|
||||
|
|
@ -54,7 +56,7 @@ impl WpImageDescriptionV1RequestHandler for WpImageDescriptionV1 {
|
|||
});
|
||||
self.client.add_client_obj(&obj)?;
|
||||
track!(self.client, obj);
|
||||
obj.send_description(self.client.state.color_manager.srgb_srgb());
|
||||
obj.send_description(desc);
|
||||
self.client.remove_obj(&*obj)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -77,5 +79,7 @@ dedicated_add_obj!(
|
|||
pub enum WpImageDescriptionV1Error {
|
||||
#[error(transparent)]
|
||||
ClientError(Box<ClientError>),
|
||||
#[error("The description is not ready")]
|
||||
NotReady,
|
||||
}
|
||||
efrom!(WpImageDescriptionV1Error, ClientError);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ impl Global for JayCompositorGlobal {
|
|||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
14
|
||||
15
|
||||
}
|
||||
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
backend,
|
||||
backend::{self, BackendColorSpace, BackendTransferFunction},
|
||||
client::{Client, ClientError},
|
||||
compositor::MAX_EXTENTS,
|
||||
format::named_formats,
|
||||
|
|
@ -15,6 +15,7 @@ use {
|
|||
jay_config::video::{
|
||||
GfxApi, TearingMode as ConfigTearingMode, Transform, VrrMode as ConfigVrrMode,
|
||||
},
|
||||
linearize::LinearizeExt,
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
|
@ -30,6 +31,7 @@ const VRR_CAPABLE_SINCE: Version = Version(2);
|
|||
const TEARING_SINCE: Version = Version(3);
|
||||
const FORMAT_SINCE: Version = Version(8);
|
||||
const FLIP_MARGIN_SINCE: Version = Version(10);
|
||||
const COLORIMETRY_SINCE: Version = Version(15);
|
||||
|
||||
impl JayRandr {
|
||||
pub fn new(id: JayRandrId, client: &Rc<Client>, version: Version) -> Self {
|
||||
|
|
@ -163,6 +165,28 @@ impl JayRandr {
|
|||
current: (mode == ¤t_mode) as _,
|
||||
});
|
||||
}
|
||||
if self.version >= COLORIMETRY_SINCE {
|
||||
for tf in &node.global.transfer_functions {
|
||||
self.client.event(SupportedTransferFunction {
|
||||
self_id: self.id,
|
||||
transfer_function: tf.name(),
|
||||
});
|
||||
}
|
||||
self.client.event(CurrentTransferFunction {
|
||||
self_id: self.id,
|
||||
transfer_function: node.global.btf.get().name(),
|
||||
});
|
||||
for cs in &node.global.color_spaces {
|
||||
self.client.event(SupportedColorSpace {
|
||||
self_id: self.id,
|
||||
color_space: cs.name(),
|
||||
});
|
||||
}
|
||||
self.client.event(CurrentColorSpace {
|
||||
self_id: self.id,
|
||||
color_space: node.global.bcs.get().name(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn send_error(&self, msg: &str) {
|
||||
|
|
@ -412,6 +436,34 @@ impl JayRandrRequestHandler for JayRandr {
|
|||
dev.dev.set_flip_margin(req.margin_ns);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_colors(&self, req: SetColors<'_>, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let cs = 'cs: {
|
||||
for cs in BackendColorSpace::variants() {
|
||||
if cs.name() == req.color_space {
|
||||
break 'cs cs;
|
||||
}
|
||||
}
|
||||
return Err(JayRandrError::UnknownColorSpace(
|
||||
req.color_space.to_string(),
|
||||
));
|
||||
};
|
||||
let tf = 'tf: {
|
||||
for tf in BackendTransferFunction::variants() {
|
||||
if tf.name() == req.transfer_function {
|
||||
break 'tf tf;
|
||||
}
|
||||
}
|
||||
return Err(JayRandrError::UnknownTransferFunction(
|
||||
req.transfer_function.to_string(),
|
||||
));
|
||||
};
|
||||
let Some(c) = self.get_connector(req.output) else {
|
||||
return Ok(());
|
||||
};
|
||||
c.connector.set_colors(cs, tf);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
|
|
@ -433,5 +485,9 @@ pub enum JayRandrError {
|
|||
UnknownTearingMode(u32),
|
||||
#[error("Unknown format {0}")]
|
||||
UnknownFormat(String),
|
||||
#[error("Unknown color space {0}")]
|
||||
UnknownColorSpace(String),
|
||||
#[error("Unknown transfer function {0}")]
|
||||
UnknownTransferFunction(String),
|
||||
}
|
||||
efrom!(JayRandrError, ClientError);
|
||||
|
|
|
|||
|
|
@ -2,22 +2,31 @@ mod removed_output;
|
|||
|
||||
use {
|
||||
crate::{
|
||||
backend,
|
||||
backend::{self, BackendColorSpace, BackendLuminance, BackendTransferFunction},
|
||||
client::{Client, ClientError, ClientId},
|
||||
cmm::{
|
||||
cmm_description::ColorDescription,
|
||||
cmm_luminance::Luminance,
|
||||
cmm_primaries::{NamedPrimaries, Primaries},
|
||||
cmm_transfer_function::TransferFunction,
|
||||
},
|
||||
damage::DamageMatrix,
|
||||
format::{Format, XRGB8888},
|
||||
globals::{Global, GlobalName},
|
||||
ifs::{wl_surface::WlSurface, zxdg_output_v1::ZxdgOutputV1},
|
||||
ifs::{
|
||||
color_management::wp_color_management_output_v1::WpColorManagementOutputV1,
|
||||
wl_surface::WlSurface, zxdg_output_v1::ZxdgOutputV1,
|
||||
},
|
||||
leaks::Tracker,
|
||||
object::{Object, Version},
|
||||
rect::Rect,
|
||||
state::{ConnectorData, State},
|
||||
tree::{OutputNode, TearingMode, VrrMode, calculate_logical_size},
|
||||
utils::{
|
||||
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, rc_eq::rc_eq,
|
||||
transform_ext::TransformExt,
|
||||
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, ordered_float::F64,
|
||||
rc_eq::rc_eq, transform_ext::TransformExt,
|
||||
},
|
||||
wire::{WlOutputId, ZxdgOutputV1Id, wl_output::*},
|
||||
wire::{WlOutputId, WpColorManagementOutputV1Id, ZxdgOutputV1Id, wl_output::*},
|
||||
},
|
||||
ahash::AHashMap,
|
||||
jay_config::video::Transform,
|
||||
|
|
@ -67,12 +76,22 @@ pub struct WlOutputGlobal {
|
|||
pub format: Cell<&'static Format>,
|
||||
pub width_mm: i32,
|
||||
pub height_mm: i32,
|
||||
pub transfer_functions: Vec<BackendTransferFunction>,
|
||||
pub color_spaces: Vec<BackendColorSpace>,
|
||||
pub primaries: Primaries,
|
||||
pub luminance: Option<BackendLuminance>,
|
||||
pub bindings: RefCell<AHashMap<ClientId, AHashMap<WlOutputId, Rc<WlOutput>>>>,
|
||||
pub destroyed: Cell<bool>,
|
||||
pub legacy_scale: Cell<u32>,
|
||||
pub persistent: Rc<PersistentOutputState>,
|
||||
pub opt: Rc<OutputGlobalOpt>,
|
||||
pub damage_matrix: Cell<DamageMatrix>,
|
||||
pub btf: Cell<BackendTransferFunction>,
|
||||
pub bcs: Cell<BackendColorSpace>,
|
||||
pub color_description: CloneCell<Rc<ColorDescription>>,
|
||||
pub linear_color_description: CloneCell<Rc<ColorDescription>>,
|
||||
pub color_description_listeners:
|
||||
CopyHashMap<(ClientId, WpColorManagementOutputV1Id), Rc<WpColorManagementOutputV1>>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -133,6 +152,7 @@ impl WlOutputGlobal {
|
|||
pub fn clear(&self) {
|
||||
self.opt.clear();
|
||||
self.bindings.borrow_mut().clear();
|
||||
self.color_description_listeners.clear();
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
|
|
@ -145,6 +165,12 @@ impl WlOutputGlobal {
|
|||
height_mm: i32,
|
||||
output_id: &Rc<OutputId>,
|
||||
persistent_state: &Rc<PersistentOutputState>,
|
||||
transfer_functions: Vec<BackendTransferFunction>,
|
||||
btf: BackendTransferFunction,
|
||||
color_spaces: Vec<BackendColorSpace>,
|
||||
bcs: BackendColorSpace,
|
||||
primaries: Primaries,
|
||||
luminance: Option<BackendLuminance>,
|
||||
) -> Self {
|
||||
let (x, y) = persistent_state.pos.get();
|
||||
let scale = persistent_state.scale.get();
|
||||
|
|
@ -166,14 +192,24 @@ impl WlOutputGlobal {
|
|||
format: Cell::new(XRGB8888),
|
||||
width_mm,
|
||||
height_mm,
|
||||
transfer_functions,
|
||||
color_spaces,
|
||||
primaries,
|
||||
luminance,
|
||||
bindings: Default::default(),
|
||||
destroyed: Cell::new(false),
|
||||
legacy_scale: Cell::new(scale.round_up()),
|
||||
persistent: persistent_state.clone(),
|
||||
opt: Default::default(),
|
||||
damage_matrix: Default::default(),
|
||||
btf: Cell::new(btf),
|
||||
bcs: Cell::new(bcs),
|
||||
color_description: CloneCell::new(state.color_manager.srgb_srgb().clone()),
|
||||
linear_color_description: CloneCell::new(state.color_manager.srgb_linear().clone()),
|
||||
color_description_listeners: Default::default(),
|
||||
};
|
||||
global.update_damage_matrix();
|
||||
global.update_color_description();
|
||||
global
|
||||
}
|
||||
|
||||
|
|
@ -292,6 +328,46 @@ impl WlOutputGlobal {
|
|||
pub fn add_visualizer_damage(&self) {
|
||||
self.state.damage_visualizer.copy_damage(self);
|
||||
}
|
||||
|
||||
pub fn update_color_description(&self) -> bool {
|
||||
let mut luminance = Luminance::SRGB;
|
||||
let tf = match self.btf.get() {
|
||||
BackendTransferFunction::Default => TransferFunction::Srgb,
|
||||
BackendTransferFunction::Pq => {
|
||||
luminance = Luminance::ST2084_PQ;
|
||||
TransferFunction::St2084Pq
|
||||
}
|
||||
};
|
||||
let mut target_luminance = luminance.to_target();
|
||||
let mut max_cll = None;
|
||||
let mut max_fall = None;
|
||||
if let Some(l) = self.luminance {
|
||||
target_luminance.min = F64(l.min);
|
||||
target_luminance.max = F64(l.max);
|
||||
max_cll = Some(F64(l.max));
|
||||
max_fall = Some(F64(l.max_fall));
|
||||
}
|
||||
let primaries = match self.bcs.get() {
|
||||
BackendColorSpace::Default => NamedPrimaries::Srgb,
|
||||
BackendColorSpace::Bt2020 => NamedPrimaries::Bt2020,
|
||||
};
|
||||
let cd = self.state.color_manager.get_description(
|
||||
Some(primaries),
|
||||
primaries.primaries(),
|
||||
luminance,
|
||||
tf,
|
||||
self.primaries,
|
||||
target_luminance,
|
||||
max_cll,
|
||||
max_fall,
|
||||
);
|
||||
let cd_linear = self
|
||||
.state
|
||||
.color_manager
|
||||
.get_with_tf(&cd, TransferFunction::Linear);
|
||||
self.linear_color_description.set(cd_linear.clone());
|
||||
self.color_description.set(cd.clone()).id != cd.id
|
||||
}
|
||||
}
|
||||
|
||||
global_base!(WlOutputGlobal, WlOutput, WlOutputError);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ use {
|
|||
ReleaseSync, SampleRect, SyncFile,
|
||||
},
|
||||
ifs::{
|
||||
color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
|
||||
wl_buffer::WlBuffer,
|
||||
wl_callback::WlCallback,
|
||||
wl_seat::{
|
||||
|
|
@ -89,8 +90,8 @@ use {
|
|||
drm::sync_obj::{SyncObj, SyncObjPoint},
|
||||
},
|
||||
wire::{
|
||||
WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id, ZwpLinuxDmabufFeedbackV1Id,
|
||||
wl_surface::*,
|
||||
WlOutputId, WlSurfaceId, WpColorManagementSurfaceFeedbackV1Id, ZwpIdleInhibitorV1Id,
|
||||
ZwpLinuxDmabufFeedbackV1Id, wl_surface::*,
|
||||
},
|
||||
xwayland::XWaylandEvent,
|
||||
},
|
||||
|
|
@ -201,6 +202,14 @@ impl NodeVisitorBase for SurfaceSendPreferredTransformVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct SurfaceSendPreferredColorDescription;
|
||||
impl NodeVisitorBase for SurfaceSendPreferredColorDescription {
|
||||
fn visit_surface(&mut self, node: &Rc<WlSurface>) {
|
||||
node.send_preferred_color_description();
|
||||
node.node_visit_children(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct SurfaceBufferExplicitRelease {
|
||||
sync_obj: Rc<SyncObj>,
|
||||
point: SyncObjPoint,
|
||||
|
|
@ -336,6 +345,8 @@ pub struct WlSurface {
|
|||
before_latch_listener: EventListener<dyn BeforeLatchListener>,
|
||||
is_opaque: Cell<bool>,
|
||||
color_management_surface: CloneCell<Option<Rc<WpColorManagementSurfaceV1>>>,
|
||||
color_management_feedback:
|
||||
CopyHashMap<WpColorManagementSurfaceFeedbackV1Id, Rc<WpColorManagementSurfaceFeedbackV1>>,
|
||||
color_description: CloneCell<Option<Rc<ColorDescription>>>,
|
||||
}
|
||||
|
||||
|
|
@ -678,6 +689,7 @@ impl WlSurface {
|
|||
before_latch_listener: EventListener::new(slf.clone()),
|
||||
is_opaque: Cell::new(false),
|
||||
color_management_surface: Default::default(),
|
||||
color_management_feedback: Default::default(),
|
||||
color_description: Default::default(),
|
||||
}
|
||||
}
|
||||
|
|
@ -699,7 +711,6 @@ impl WlSurface {
|
|||
Ok(ext.into_xsurface().unwrap())
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "it"), expect(dead_code))]
|
||||
pub fn get_output(&self) -> Rc<OutputNode> {
|
||||
self.output.get()
|
||||
}
|
||||
|
|
@ -720,6 +731,9 @@ impl WlSurface {
|
|||
if old.global.persistent.transform.get() != output.global.persistent.transform.get() {
|
||||
self.send_preferred_buffer_transform();
|
||||
}
|
||||
if old.global.color_description.get().id != output.global.color_description.get().id {
|
||||
self.send_preferred_color_description();
|
||||
}
|
||||
let children = self.children.borrow_mut();
|
||||
if let Some(children) = &*children {
|
||||
for ss in children.subsurfaces.values() {
|
||||
|
|
@ -1682,6 +1696,24 @@ impl WlSurface {
|
|||
None => self.client.state.color_manager.srgb_srgb().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_color_management_feedback(&self, fb: &Rc<WpColorManagementSurfaceFeedbackV1>) {
|
||||
self.color_management_feedback.set(fb.id, fb.clone());
|
||||
}
|
||||
|
||||
pub fn remove_color_management_feedback(&self, fb: &WpColorManagementSurfaceFeedbackV1) {
|
||||
self.color_management_feedback.remove(&fb.id);
|
||||
}
|
||||
|
||||
pub fn send_preferred_color_description(&self) {
|
||||
if self.color_management_feedback.is_empty() {
|
||||
return;
|
||||
}
|
||||
let cd = self.output.get().global.color_description.get();
|
||||
for fb in self.color_management_feedback.lock().values() {
|
||||
fb.send_preferred_changed(&cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
|
|
@ -1714,6 +1746,7 @@ impl Object for WlSurface {
|
|||
self.fifo.take();
|
||||
self.commit_timer.take();
|
||||
self.color_management_surface.take();
|
||||
self.color_management_feedback.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 {
|
|||
|
||||
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.surface.color_management_surface.take();
|
||||
self.surface.pending.borrow_mut().color_description = Some(None);
|
||||
self.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -56,7 +57,10 @@ impl WpColorManagementSurfaceV1RequestHandler for WpColorManagementSurfaceV1 {
|
|||
));
|
||||
}
|
||||
let desc = self.client.lookup(req.image_description)?;
|
||||
self.surface.pending.borrow_mut().color_description = Some(Some(desc.description.clone()));
|
||||
if desc.description.is_none() {
|
||||
return Err(WpColorManagementSurfaceV1Error::NotReady);
|
||||
}
|
||||
self.surface.pending.borrow_mut().color_description = Some(desc.description.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -87,5 +91,7 @@ pub enum WpColorManagementSurfaceV1Error {
|
|||
UnsupportedRenderIntent(u32),
|
||||
#[error("wl_surface already has a color-management extension")]
|
||||
HasSurface,
|
||||
#[error("The color description is not ready")]
|
||||
NotReady,
|
||||
}
|
||||
efrom!(WpColorManagementSurfaceV1Error, ClientError);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue