jay-compositor 1.15.0

The Jay compositor
use crate::client::CAP_FOREIGN_TOPLEVEL_MANAGER;
use crate::client::Client;
use crate::client::ClientCaps;
use crate::globals::Global;
use crate::globals::GlobalName;
use crate::ifs::wl_surface::x_surface::xwindow::Xwindow;
use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel;
use crate::ifs::zwlr_foreign_toplevel_handle_v1::ZwlrForeignToplevelHandleV1;
use crate::leaks::Tracker;
use crate::object::BreakLoops;
use crate::object::Version;
use crate::tree::NodeVisitorBase;
use crate::tree::OutputNodeId;
use crate::tree::ToplevelOpt;
use crate::wire::ZwlrForeignToplevelManagerV1Id;
use crate::wire::zwlr_foreign_toplevel_manager_v1::*;
use jay_proc::Global;
use jay_proc::Object;
use std::cell::Cell;
use std::convert::Infallible;
use std::rc::Rc;

#[derive(Global)]
pub struct ZwlrForeignToplevelManagerV1Global {
    name: GlobalName,
}

impl ZwlrForeignToplevelManagerV1Global {
    pub fn new(name: GlobalName) -> Self {
        Self { name }
    }

    fn bind_(
        self: Rc<Self>,
        id: ZwlrForeignToplevelManagerV1Id,
        client: &Rc<Client>,
        version: Version,
    ) -> Result<(), Infallible> {
        let obj = Rc::new(ZwlrForeignToplevelManagerV1 {
            id,
            client: client.clone(),
            tracker: Default::default(),
            version,
        });
        track!(client, obj);
        client.add_client_obj(&obj);
        client
            .state
            .visit_all_nodes(&mut ZwlrToplevelVisitor { manager: &obj });
        client.state.toplevel_managers.set((client.id, id), obj);
        Ok(())
    }
}

struct ZwlrToplevelVisitor<'a> {
    manager: &'a ZwlrForeignToplevelManagerV1,
}

impl NodeVisitorBase for ZwlrToplevelVisitor<'_> {
    fn visit_toplevel(&mut self, node: &Rc<XdgToplevel>) {
        node.manager_send_to(self.manager);
    }

    fn visit_xwindow(&mut self, node: &Rc<Xwindow>) {
        node.toplevel_data.manager_send(node.clone(), self.manager);
    }
}

#[derive(Object)]
#[break_loops]
pub struct ZwlrForeignToplevelManagerV1 {
    id: ZwlrForeignToplevelManagerV1Id,
    client: Rc<Client>,
    tracker: Tracker<Self>,
    version: Version,
}

impl ZwlrForeignToplevelManagerV1 {
    fn detach(&self) {
        self.client
            .state
            .toplevel_managers
            .remove(&(self.client.id, self.id));
    }
}

impl ZwlrForeignToplevelManagerV1RequestHandler for ZwlrForeignToplevelManagerV1 {
    type Error = Infallible;

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

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

    fn send_handle(&self, handle: &ZwlrForeignToplevelHandleV1) {
        self.client.event(Toplevel {
            self_id: self.id,
            toplevel: handle.id,
        });
    }

    pub fn publish_toplevel(&self, tl: ToplevelOpt) -> Rc<ZwlrForeignToplevelHandleV1> {
        let id = self.client.new_id(self);
        let handle = Rc::new(ZwlrForeignToplevelHandleV1 {
            id,
            client: self.client.clone(),
            tracker: Default::default(),
            version: self.version,
            toplevel: tl,
            output: Cell::new(OutputNodeId::none()),
        });
        track!(self.client, handle);
        self.client.add_server_obj(&handle);
        self.send_handle(&handle);
        handle
    }
}

impl Global for ZwlrForeignToplevelManagerV1Global {
    fn version(&self) -> u32 {
        3
    }

    fn required_caps(&self) -> ClientCaps {
        CAP_FOREIGN_TOPLEVEL_MANAGER
    }
}

impl BreakLoops for ZwlrForeignToplevelManagerV1 {
    fn break_loops(self: Rc<Self>) {
        self.detach();
    }
}