use crate::backend::BackendColorSpace;
use crate::backend::BackendEotfs;
use crate::backend::ConnectorId;
use crate::backend::Mode;
use crate::backend::MonitorInfo;
use crate::format::Format;
use crate::gfx_api::ScalingFilter;
use crate::globals::GlobalName;
use crate::ifs::wl_output::BlendSpace;
use crate::ifs::wl_output::PersistentOutputState;
use crate::scale::Scale;
use crate::state::OutputData;
use crate::state::State;
use crate::tree::OutputNode;
use crate::tree::TearingMode;
use crate::tree::Transform;
use crate::tree::TreeTimeline::LiveTL;
use crate::tree::VrrMode;
use crate::utils::rc_eq::RcEq;
use hashbrown::hash_map::Entry;
use std::cell::Ref;
use std::cell::RefCell;
use std::rc::Rc;
linear_ids!(HeadNames, HeadName, u64);
#[derive(Clone, PartialEq)]
pub struct HeadState {
pub connector_id: ConnectorId,
pub name: RcEq<String>,
pub wl_output: Option<GlobalName>,
pub connector_enabled: bool,
pub active: bool,
pub connected: bool,
pub in_compositor_space: bool,
pub position: (i32, i32),
pub size: (i32, i32),
pub mode: Mode,
pub transform: Transform,
pub scale: Scale,
pub scaling_filter: ScalingFilter,
pub monitor_info: Option<RcEq<MonitorInfo>>,
pub inherent_non_desktop: bool,
pub override_non_desktop: Option<bool>,
pub vrr: bool,
pub vrr_mode: VrrMode,
pub tearing_enabled: bool,
pub tearing_active: bool,
pub tearing_mode: TearingMode,
pub format: &'static Format,
pub color_space: BackendColorSpace,
pub eotf: BackendEotfs,
pub supported_formats: RcEq<Vec<&'static Format>>,
pub brightness: Option<f64>,
pub blend_space: BlendSpace,
pub use_native_gamut: bool,
pub vrr_cursor_hz: Option<f64>,
pub persistent_state: Option<RcEq<PersistentOutputState>>,
}
pub struct ReadOnlyHeadState {
state: Rc<RefCell<HeadState>>,
}
impl ReadOnlyHeadState {
pub fn borrow(&self) -> Ref<'_, HeadState> {
self.state.borrow()
}
}
impl HeadState {
pub fn update_in_compositor_space(&mut self, state: &State, wl_output: Option<GlobalName>) {
self.in_compositor_space = false;
self.wl_output = None;
if !self.connector_enabled {
return;
}
let Some(mi) = &self.monitor_info else {
return;
};
if mi.non_desktop {
return;
}
if self.override_non_desktop == Some(true) {
return;
}
self.in_compositor_space = true;
self.wl_output = wl_output;
if self.persistent_state.is_none() {
let ds = state
.persistent_output_states
.get(&mi.output_id)
.unwrap_or_else(|| state.new_persistent_output_state());
self.position = ds.pos.get();
self.transform = ds.transform.get();
self.vrr_mode = ds.vrr_mode.get();
self.tearing_mode = ds.tearing_mode.get();
self.brightness = ds.brightness.get();
self.blend_space = ds.blend_space.get();
self.use_native_gamut = ds.use_native_gamut.get();
self.vrr_cursor_hz = ds.vrr_cursor_hz.get();
self.scale = ds.scale.get();
self.scaling_filter = ds.scaling_filter.get();
self.persistent_state = Some(RcEq(ds));
if let Some(c) = state.connectors.get(&self.connector_id) {
self.mode = c.state.borrow().mode;
}
self.update_size();
}
}
pub fn update_size(&mut self) {
self.size =
OutputNode::calculate_extents_(self.mode, self.transform, self.scale, self.position)
.size();
}
pub fn flush_persistent_state(&self, state: &State) {
if let Some(mi) = &self.monitor_info
&& let Some(ds) = &self.persistent_state
&& let Entry::Vacant(v) = state
.persistent_output_states
.lock()
.entry(mi.output_id.clone())
{
v.insert(ds.0.clone());
}
}
}
pub struct HeadManager {
pub name: HeadName,
state: Rc<RefCell<HeadState>>,
}
impl HeadManager {
pub fn new(name: HeadName, state: HeadState) -> Self {
Self {
name,
state: Rc::new(RefCell::new(state)),
}
}
pub fn state(&self) -> ReadOnlyHeadState {
ReadOnlyHeadState {
state: self.state.clone(),
}
}
pub fn handle_output_connected(&self, s: &State, output: &OutputData) {
let state = &mut *self.state.borrow_mut();
state.connected = true;
state.monitor_info = Some(RcEq(output.monitor_info.clone()));
state.persistent_state = None;
state.inherent_non_desktop = output.monitor_info.non_desktop;
state.update_in_compositor_space(s, output.node.as_ref().map(|n| n.global.name));
}
pub fn handle_output_disconnected(&self, s: &State) {
let state = &mut *self.state.borrow_mut();
state.connected = false;
state.monitor_info = None;
state.persistent_state = None;
state.update_in_compositor_space(s, None);
}
pub fn handle_position_size_change(&self, node: &OutputNode) {
let state = &mut *self.state.borrow_mut();
let pos = node.node_state[LiveTL].pos.get();
state.position = pos.position();
state.size = pos.size();
}
pub fn handle_mode_change(&self, mode: Mode) {
let state = &mut *self.state.borrow_mut();
state.mode = mode;
}
pub fn handle_transform_change(&self, transform: Transform) {
let state = &mut *self.state.borrow_mut();
state.transform = transform;
}
pub fn handle_scale_change(&self, scale: Scale) {
let state = &mut *self.state.borrow_mut();
state.scale = scale;
}
pub fn handle_scaling_filter_change(&self, scaling_filter: ScalingFilter) {
let state = &mut *self.state.borrow_mut();
state.scaling_filter = scaling_filter;
}
pub fn handle_enabled_change(&self, s: &State, enabled: bool) {
let state = &mut *self.state.borrow_mut();
state.connector_enabled = enabled;
state.update_in_compositor_space(s, state.wl_output);
}
pub fn handle_active_change(&self, active: bool) {
let state = &mut *self.state.borrow_mut();
state.active = active;
}
pub fn handle_non_desktop_override_changed(&self, overrd: Option<bool>) {
let state = &mut *self.state.borrow_mut();
state.override_non_desktop = overrd;
}
pub fn handle_vrr_change(&self, vrr: bool) {
let state = &mut *self.state.borrow_mut();
state.vrr = vrr;
}
pub fn handle_vrr_mode_change(&self, vrr_mode: &VrrMode) {
let state = &mut *self.state.borrow_mut();
state.vrr_mode = *vrr_mode;
}
pub fn handle_tearing_enabled_change(&self, enabled: bool) {
let state = &mut *self.state.borrow_mut();
state.tearing_enabled = enabled;
}
pub fn handle_tearing_active_change(&self, active: bool) {
let state = &mut *self.state.borrow_mut();
state.tearing_active = active;
}
pub fn handle_tearing_mode_change(&self, tearing_mode: &TearingMode) {
let state = &mut *self.state.borrow_mut();
state.tearing_mode = *tearing_mode;
}
pub fn handle_format_change(&self, format: &'static Format) {
let state = &mut *self.state.borrow_mut();
state.format = format;
}
pub fn handle_colors_change(&self, color_space: BackendColorSpace, eotf: BackendEotfs) {
let state = &mut *self.state.borrow_mut();
state.color_space = color_space;
state.eotf = eotf;
}
pub fn handle_formats_change(&self, formats: &Rc<Vec<&'static Format>>) {
let state = &mut *self.state.borrow_mut();
state.supported_formats.0 = formats.clone();
}
pub fn handle_brightness_change(&self, brightness: Option<f64>) {
let state = &mut *self.state.borrow_mut();
state.brightness = brightness;
}
pub fn handle_blend_space_change(&self, blend_space: BlendSpace) {
let state = &mut *self.state.borrow_mut();
state.blend_space = blend_space;
}
pub fn handle_use_native_gamut_change(&self, use_native_gamut: bool) {
let state = &mut *self.state.borrow_mut();
state.use_native_gamut = use_native_gamut;
}
pub fn handle_cursor_hz_change(&self, cursor_hz: Option<f64>) {
let state = &mut *self.state.borrow_mut();
state.vrr_cursor_hz = cursor_hz;
}
}