jay-compositor 1.15.0

The Jay compositor
use crate::backend;
use crate::backend::ConnectorId;
use crate::client::Client;
use crate::fixed::Fixed;
use crate::ifs::wlr_output_manager::zwlr_output_manager_v1::ZwlrOutputManagerV1;
use crate::ifs::wlr_output_manager::zwlr_output_mode_v1::ZwlrOutputModeV1;
use crate::leaks::Tracker;
use crate::object::Version;
use crate::scale;
use crate::state::OutputData;
use crate::state::OutputEventListener;
use crate::tree;
use crate::tree::OutputNode;
use crate::tree::VrrMode;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::event_listener::EventListener;
use crate::wire::ZwlrOutputHeadV1Id;
use crate::wire::zwlr_output_head_v1::*;
use jay_proc::Object;
use std::convert::Infallible;
use std::rc::Rc;

pub const MAKE_SINCE: Version = Version(2);
pub const MODEL_SINCE: Version = Version(2);
pub const SERIAL_NUMBER_SINCE: Version = Version(2);
#[expect(unused)]
pub const RELEASE_SINCE: Version = Version(3);
pub const ADAPTIVE_SYNC_SINCE: Version = Version(4);

pub const HEAD_DISABLED: i32 = 0;
pub const HEAD_ENABLED: i32 = 1;

pub const ADAPTIVE_SYNC_STATE_DISABLED: u32 = 0;
pub const ADAPTIVE_SYNC_STATE_ENABLED: u32 = 1;

linear_ids!(WlrOutputHeadIds, WlrOutputHeadId, u64);

#[derive(Object)]
pub struct ZwlrOutputHeadV1 {
    pub(super) id: ZwlrOutputHeadV1Id,
    pub(super) version: Version,
    pub(super) client: Rc<Client>,
    pub(super) tracker: Tracker<Self>,
    pub(super) output: Rc<OutputData>,
    pub(super) manager: Rc<ZwlrOutputManagerV1>,
    pub(super) head_id: WlrOutputHeadId,
    pub(super) connector_id: ConnectorId,
    pub(super) modes: CopyHashMap<backend::Mode, Rc<ZwlrOutputModeV1>>,
    pub(super) listener: EventListener<dyn OutputEventListener>,
}

impl ZwlrOutputHeadV1 {
    pub fn send_name(&self, name: &str) {
        self.client.event(Name {
            self_id: self.id,
            name,
        });
    }

    pub fn send_description(&self, description: &str) {
        self.client.event(Description {
            self_id: self.id,
            description,
        });
    }

    pub fn send_physical_size(&self, width: i32, height: i32) {
        self.client.event(PhysicalSize {
            self_id: self.id,
            width,
            height,
        });
    }

    fn send_mode(&self, mode: &ZwlrOutputModeV1) {
        self.client.event(Mode {
            self_id: self.id,
            mode: mode.id,
        });
    }

    pub fn send_enabled(&self, enabled: bool) {
        let enabled = if enabled { HEAD_ENABLED } else { HEAD_DISABLED };
        self.client.event(Enabled {
            self_id: self.id,
            enabled,
        });
    }

    fn send_current_mode(&self, mode: &ZwlrOutputModeV1) {
        self.client.event(CurrentMode {
            self_id: self.id,
            mode: mode.id,
        });
    }

    pub fn send_position(&self, x: i32, y: i32) {
        self.client.event(Position {
            self_id: self.id,
            x,
            y,
        });
    }

    pub fn send_transform(&self, transform: tree::Transform) {
        self.client.event(Transform {
            self_id: self.id,
            transform: transform.to_wl(),
        });
    }

    pub fn send_scale(&self, scale: scale::Scale) {
        let scale = Fixed::from_f64(scale.to_f64());
        self.client.event(Scale {
            self_id: self.id,
            scale,
        });
    }

    fn send_finished(&self) {
        self.client.event(Finished { self_id: self.id });
    }

    pub fn send_make(&self, make: &str) {
        self.client.event(Make {
            self_id: self.id,
            make,
        });
    }

    pub fn send_model(&self, model: &str) {
        self.client.event(Model {
            self_id: self.id,
            model,
        });
    }

    pub fn send_serial_number(&self, serial_number: &str) {
        self.client.event(SerialNumber {
            self_id: self.id,
            serial_number,
        });
    }

    pub fn send_adaptive_sync(&self, mode: &VrrMode) {
        let state = if *mode == VrrMode::Always {
            ADAPTIVE_SYNC_STATE_ENABLED
        } else {
            ADAPTIVE_SYNC_STATE_DISABLED
        };
        self.client.event(AdaptiveSync {
            self_id: self.id,
            state,
        });
    }

    pub fn announce_modes(&self, modes: &[Rc<ZwlrOutputModeV1>]) {
        for mode in modes {
            self.send_mode(mode);
            mode.send();
            if mode.initial_current {
                self.send_current_mode(mode);
            }
        }
    }
}

impl OutputEventListener for ZwlrOutputHeadV1 {
    fn disconnected(self: Rc<Self>) {
        self.listener.detach();
        self.send_finished();
        for mode in self.modes.lock().values() {
            if !mode.destroyed.get() {
                mode.send_finished();
            }
        }
        self.manager.schedule_done();
    }

    fn position_changed(self: Rc<Self>, _on: &Rc<OutputNode>, x: i32, y: i32) {
        self.send_position(x, y);
        self.manager.schedule_done();
    }

    fn vrr_mode_changed(self: Rc<Self>, _on: &Rc<OutputNode>, mode: &VrrMode) {
        if self.version < ADAPTIVE_SYNC_SINCE {
            return;
        }
        self.send_adaptive_sync(mode);
        self.manager.schedule_done();
    }

    fn mode_changed(self: Rc<Self>, new: backend::Mode) {
        let mode = self.modes.get(&new).unwrap_or_else(|| {
            let mode = self
                .manager
                .create_mode(self.id, self.head_id, &new, false, false);
            self.modes.set(new, mode.clone());
            self.send_mode(&mode);
            mode.send();
            mode
        });
        if mode.destroyed.get() {
            return;
        }
        self.send_current_mode(&mode);
        self.manager.schedule_done();
    }

    fn scale_changed(self: Rc<Self>, _on: &Rc<OutputNode>, scale: scale::Scale) {
        self.send_scale(scale);
        self.manager.schedule_done();
    }

    fn transform_changed(self: Rc<Self>, _on: &Rc<OutputNode>, transform: tree::Transform) {
        self.send_transform(transform);
        self.manager.schedule_done();
    }
}

impl ZwlrOutputHeadV1RequestHandler for ZwlrOutputHeadV1 {
    type Error = Infallible;

    fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        self.send_finished();
        self.listener.detach();
        self.client.remove_obj(self);
        Ok(())
    }
}