use crate::backend::Mode;
use crate::client::CAP_HEAD_MANAGER;
use crate::client::Client;
use crate::client::ClientCaps;
use crate::globals::Global;
use crate::globals::GlobalName;
use crate::ifs::wlr_output_manager::zwlr_output_configuration_v1::ZwlrOutputConfigurationV1;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::ADAPTIVE_SYNC_SINCE;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::MAKE_SINCE;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::MODEL_SINCE;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::SERIAL_NUMBER_SINCE;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::WlrOutputHeadId;
use crate::ifs::wlr_output_manager::zwlr_output_head_v1::ZwlrOutputHeadV1;
use crate::ifs::wlr_output_manager::zwlr_output_mode_v1::ZwlrOutputModeV1;
use crate::leaks::Tracker;
use crate::object::BreakLoops;
use crate::object::Version;
use crate::state::OutputData;
use crate::tree::TreeTimeline::LiveTL;
use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::event_listener::EventListener;
use crate::utils::numcell::NumCell;
use crate::wire::ZwlrOutputHeadV1Id;
use crate::wire::ZwlrOutputManagerV1Id;
use crate::wire::zwlr_output_manager_v1::*;
use isnt::std_1::string::IsntStringExt;
use jay_proc::Global;
use jay_proc::Object;
use std::cell::Cell;
use std::convert::Infallible;
use std::rc::Rc;
use std::slice;
linear_ids!(WlrOutputManagerIds, WlrOutputManagerId, u64);
#[derive(Global)]
pub struct ZwlrOutputManagerV1Global {
name: GlobalName,
}
#[derive(Object)]
#[break_loops]
pub struct ZwlrOutputManagerV1 {
id: ZwlrOutputManagerV1Id,
manager_id: WlrOutputManagerId,
client: Rc<Client>,
version: Version,
tracker: Tracker<Self>,
pub(super) done_scheduled: Cell<bool>,
pub(super) serial: NumCell<u64>,
pub(super) destroyed: Cell<bool>,
}
impl ZwlrOutputManagerV1 {
fn detach(&self) {
self.client
.state
.wlr_output_managers
.managers
.remove(&self.manager_id);
}
}
impl ZwlrOutputManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: ZwlrOutputManagerV1Id,
client: &Rc<Client>,
version: Version,
) -> Result<(), Infallible> {
let obj = Rc::new(ZwlrOutputManagerV1 {
id,
manager_id: client.state.wlr_output_managers.ids.next(),
client: client.clone(),
tracker: Default::default(),
version,
done_scheduled: Cell::new(false),
serial: Default::default(),
destroyed: Cell::new(false),
});
track!(client, obj);
client.add_client_obj(&obj);
client
.state
.wlr_output_managers
.managers
.set(obj.manager_id, obj.clone());
for output in client.state.outputs.lock().values() {
obj.announce_head(output);
}
Ok(())
}
}
impl ZwlrOutputManagerV1RequestHandler for ZwlrOutputManagerV1 {
type Error = Infallible;
fn create_configuration(
&self,
req: CreateConfiguration,
slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let last_serial = self.serial.get();
let mut serial = (last_serial >> u32::BITS << u32::BITS) | (req.serial as u64);
if serial > last_serial {
serial = serial.saturating_sub(1 << u32::BITS);
}
let configuration = Rc::new(ZwlrOutputConfigurationV1 {
id: req.id,
client: self.client.clone(),
version: self.version,
tracker: Default::default(),
serial,
manager: slf.clone(),
used: Cell::new(false),
enabled_outputs: Default::default(),
configured_outputs: Default::default(),
});
track!(self.client, configuration);
self.client.add_client_obj(&configuration);
Ok(())
}
fn stop(&self, _req: Stop, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.destroyed.set(true);
self.detach();
self.send_finished();
self.client.remove_obj(self);
Ok(())
}
}
impl ZwlrOutputManagerV1 {
pub fn announce_head(self: &Rc<Self>, output: &Rc<OutputData>) {
let id = self.client.new_id(&**self);
let mi = &output.monitor_info;
let state_mode = output.connector.state.borrow().mode;
let head_id = self.client.state.wlr_output_managers.head_ids.next();
let mut modes_list = vec![];
let modes = CopyHashMap::new();
let mut have_current = false;
for (idx, mode) in mi
.modes
.as_deref()
.unwrap_or(slice::from_ref(&state_mode))
.iter()
.enumerate()
{
if modes.contains(mode) {
continue;
}
let current = !have_current && *mode == state_mode;
if current {
have_current = true;
}
let output_mode = self.create_mode(id, head_id, mode, idx == 0, current);
modes_list.push(output_mode.clone());
modes.set(*mode, output_mode);
}
let head = Rc::<ZwlrOutputHeadV1>::new_cyclic(|slf| ZwlrOutputHeadV1 {
id,
client: self.client.clone(),
tracker: Default::default(),
version: self.version,
manager: self.clone(),
head_id,
connector_id: output.connector.id,
modes,
output: output.clone(),
listener: EventListener::attached(slf.clone(), &output.connector.listeners),
});
track!(self.client, head);
self.client.add_server_obj(&head);
self.send_head(&head);
head.send_name(&output.connector.name);
let description = &*output.connector.description.borrow();
if description.is_not_empty() {
head.send_description(description);
}
head.send_enabled(!mi.non_desktop_effective);
head.announce_modes(&modes_list);
head.send_physical_size(mi.width_mm, mi.height_mm);
if mi.output_id.manufacturer.is_not_empty() && head.version >= MAKE_SINCE {
head.send_make(&mi.output_id.manufacturer);
}
if mi.output_id.model.is_not_empty() && head.version >= MODEL_SINCE {
head.send_model(&mi.output_id.model);
}
if mi.output_id.serial_number.is_not_empty() && head.version >= SERIAL_NUMBER_SINCE {
head.send_serial_number(&mi.output_id.serial_number);
}
if let Some(node) = &output.node {
let p = &node.global.persistent;
head.send_scale(node.node_state[LiveTL].scale.get());
head.send_position(p.pos.get().0, p.pos.get().1);
head.send_transform(node.node_state[LiveTL].transform.get());
if head.version >= ADAPTIVE_SYNC_SINCE {
head.send_adaptive_sync(&p.vrr_mode.get());
}
}
self.schedule_done();
}
fn send_head(&self, head: &ZwlrOutputHeadV1) {
self.client.event(Head {
self_id: self.id,
head: head.id,
});
}
pub fn send_done(&self) {
self.client.event(Done {
self_id: self.id,
serial: self.serial.get() as u32,
});
}
fn send_finished(&self) {
self.client.event(Finished { self_id: self.id });
}
pub(super) fn schedule_done(self: &Rc<Self>) {
if self.done_scheduled.replace(true) {
return;
}
self.serial.fetch_add(1);
self.client
.state
.wlr_output_managers
.queue
.push(self.clone());
}
pub(super) fn create_mode(
self: &Rc<Self>,
parent_id: ZwlrOutputHeadV1Id,
head_id: WlrOutputHeadId,
mode: &Mode,
preferred: bool,
initial_current: bool,
) -> Rc<ZwlrOutputModeV1> {
let id = self.client.new_id2(parent_id);
let output_mode = Rc::new(ZwlrOutputModeV1 {
id,
head_id,
client: self.client.clone(),
tracker: Default::default(),
version: self.version,
mode: *mode,
preferred,
initial_current,
destroyed: Cell::new(false),
});
track!(self.client, output_mode);
self.client.add_server_obj(&output_mode);
output_mode
}
}
impl Global for ZwlrOutputManagerV1Global {
fn version(&self) -> u32 {
4
}
fn required_caps(&self) -> ClientCaps {
CAP_HEAD_MANAGER
}
}
impl BreakLoops for ZwlrOutputManagerV1 {
fn break_loops(self: Rc<Self>) {
self.detach();
}
}