use crate::backend::Mode;
use crate::client::Client;
use crate::client::LookupError;
use crate::fixed::Fixed;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::ADAPTIVE_SYNC_STATE_DISABLED;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::ADAPTIVE_SYNC_STATE_ENABLED;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::WlrOutputHeadId;
use crate::leaks::Tracker;
use crate::object::Version;
use crate::scale::Scale;
use crate::tree::Transform;
use crate::tree::VrrMode;
use crate::wire::ZwlrOutputConfigurationHeadV1Id;
use crate::wire::zwlr_output_configuration_head_v1::*;
use jay_proc::Object;
use std::cell::RefCell;
use std::rc::Rc;
use thiserror::Error;
#[derive(Object)]
pub struct ZwlrOutputConfigurationHeadV1 {
pub(super) id: ZwlrOutputConfigurationHeadV1Id,
pub(super) head_id: WlrOutputHeadId,
pub(super) version: Version,
pub(super) client: Rc<Client>,
pub(super) config: RefCell<OutputConfig>,
pub(super) tracker: Tracker<Self>,
}
#[derive(Default, Copy, Clone)]
pub struct OutputConfig {
pub(super) transform: Option<Transform>,
pub(super) scale: Option<Scale>,
pub(super) vrr_mode: Option<VrrMode>,
pub(super) pos: Option<(i32, i32)>,
pub(super) mode: Option<Mode>,
}
impl ZwlrOutputConfigurationHeadV1RequestHandler for ZwlrOutputConfigurationHeadV1 {
type Error = ZwlrOutputConfigurationHeadV1Error;
fn set_mode(&self, req: SetMode, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let config = &mut *self.config.borrow_mut();
if config.mode.is_some() {
return Err(ZwlrOutputConfigurationHeadV1Error::AlreadySet);
}
let mode = self.client.lookup(req.mode)?;
if self.head_id != mode.head_id {
return Err(ZwlrOutputConfigurationHeadV1Error::InvalidMode);
}
config.mode = Some(mode.mode);
Ok(())
}
fn set_custom_mode(&self, req: SetCustomMode, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let config = &mut *self.config.borrow_mut();
if config.mode.is_some() {
return Err(ZwlrOutputConfigurationHeadV1Error::AlreadySet);
}
config.mode = Some(Mode {
width: req.width,
height: req.height,
refresh_rate_millihz: req.refresh as u32,
});
Ok(())
}
fn set_position(&self, req: SetPosition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let config = &mut *self.config.borrow_mut();
if config.pos.is_some() {
return Err(ZwlrOutputConfigurationHeadV1Error::AlreadySet);
}
config.pos = Some((req.x, req.y));
Ok(())
}
fn set_transform(&self, req: SetTransform, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let config = &mut *self.config.borrow_mut();
if config.transform.is_some() {
return Err(ZwlrOutputConfigurationHeadV1Error::AlreadySet);
}
let Some(transform) = Transform::from_wl(req.transform) else {
return Err(ZwlrOutputConfigurationHeadV1Error::InvalidTransform(
req.transform,
));
};
config.transform = Some(transform);
Ok(())
}
fn set_scale(&self, req: SetScale, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let config = &mut *self.config.borrow_mut();
if config.scale.is_some() {
return Err(ZwlrOutputConfigurationHeadV1Error::AlreadySet);
}
if req.scale <= 0 {
return Err(ZwlrOutputConfigurationHeadV1Error::InvalidScale(req.scale));
}
config.scale = Some(Scale::from_f64(req.scale.to_f64()));
Ok(())
}
fn set_adaptive_sync(&self, req: SetAdaptiveSync, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let config = &mut *self.config.borrow_mut();
if config.vrr_mode.is_some() {
return Err(ZwlrOutputConfigurationHeadV1Error::AlreadySet);
}
let state = match req.state {
ADAPTIVE_SYNC_STATE_DISABLED => VrrMode::NEVER,
ADAPTIVE_SYNC_STATE_ENABLED => VrrMode::ALWAYS,
_ => {
return Err(
ZwlrOutputConfigurationHeadV1Error::InvalidAdaptiveSyncState(req.state),
);
}
};
config.vrr_mode = Some(*state);
Ok(())
}
}
#[derive(Debug, Error)]
pub enum ZwlrOutputConfigurationHeadV1Error {
#[error(transparent)]
Lookup(#[from] LookupError),
#[error("Property has already been set")]
AlreadySet,
#[error("Mode doesn't belong to head")]
InvalidMode,
#[error("Unknown transform {0}")]
InvalidTransform(i32),
#[error("Invalid scale {0}")]
InvalidScale(Fixed),
#[error("Invalid adaptive sync state {0}")]
InvalidAdaptiveSyncState(u32),
}