jay-compositor 1.15.0

The Jay compositor
use crate::client::Client;
use crate::gfx_api::GfxContext;
use crate::leaks::Tracker;
use crate::object::BreakLoops;
use crate::object::Version;
use crate::utils::errorfmt::ErrorFmt;
use crate::wire::JayRenderCtxId;
use crate::wire::jay_render_ctx::*;
use jay_proc::Object;
use std::convert::Infallible;
use std::rc::Rc;

pub const FORMATS_SINCE: Version = Version(7);
pub const WRITE_MODIFIER_2_SINCE: Version = Version(9);

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

impl JayRenderCtx {
    pub fn send_render_ctx(&self, ctx: Option<Rc<dyn GfxContext>>) {
        let mut fd = None;
        if let Some(ctx) = ctx {
            if self.version >= FORMATS_SINCE {
                for format in ctx.formats().values() {
                    self.client.event(Format {
                        self_id: self.id,
                        format: format.format.drm,
                    });
                    for (modifier, gwm) in &format.write_modifiers {
                        if self.version >= WRITE_MODIFIER_2_SINCE {
                            self.client.event(WriteModifier2 {
                                self_id: self.id,
                                format: format.format.drm,
                                modifier: *modifier,
                                needs_render_usage: gwm.needs_render_usage,
                            });
                        } else {
                            self.client.event(WriteModifier {
                                self_id: self.id,
                                format: format.format.drm,
                                modifier: *modifier,
                            });
                        }
                    }
                    for modifier in &format.read_modifiers {
                        self.client.event(ReadModifier {
                            self_id: self.id,
                            format: format.format.drm,
                            modifier: *modifier,
                        });
                    }
                }
            }
            let allocator = ctx.allocator();
            match allocator.drm() {
                Some(drm) => match drm.dup_render() {
                    Ok(d) => fd = Some(d.fd().clone()),
                    Err(e) => {
                        log::error!("Could not dup drm fd: {}", ErrorFmt(e));
                    }
                },
                None => {
                    log::error!("Allocator does not have a DRM device");
                }
            }
        }
        match fd {
            Some(fd) => self.client.event(Device {
                self_id: self.id,
                fd,
            }),
            _ => self.client.event(NoDevice { self_id: self.id }),
        }
    }

    fn remove_from_state(&self) {
        self.client
            .state
            .render_ctx_watchers
            .remove(&(self.client.id, self.id));
    }
}

impl JayRenderCtxRequestHandler for JayRenderCtx {
    type Error = Infallible;

    fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        self.remove_from_state();
        self.client.remove_obj(self);
        Ok(())
    }
}

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