jay-compositor 1.15.0

The Jay compositor
use crate::backend::KeyState;
use crate::client::Client;
use crate::clientmem::ClientMem;
use crate::clientmem::ClientMemError;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::ifs::wl_seat::wl_keyboard;
use crate::ifs::wl_seat::wl_keyboard::WlKeyboard;
use crate::ifs::wl_surface::WlSurface;
use crate::kbvm::KbvmError;
use crate::keyboard::KeyboardState;
use crate::leaks::Tracker;
use crate::object::Version;
use crate::wire::ZwpVirtualKeyboardV1Id;
use crate::wire::zwp_virtual_keyboard_v1::*;
use jay_proc::Object;
use std::cell::RefCell;
use std::rc::Rc;
use thiserror::Error;

#[derive(Object)]
pub struct ZwpVirtualKeyboardV1 {
    pub id: ZwpVirtualKeyboardV1Id,
    pub client: Rc<Client>,
    pub seat: Rc<WlSeatGlobal>,
    pub tracker: Tracker<Self>,
    pub version: Version,
    pub kb_state: Rc<RefCell<KeyboardState>>,
}

impl ZwpVirtualKeyboardV1 {
    fn for_each_kb<F>(&self, mut f: F)
    where
        F: FnMut(u64, &WlSurface, &Rc<WlKeyboard>),
    {
        let Some(surface) = self.seat.keyboard_node.get().node_into_surface() else {
            return;
        };
        let serial = surface.client.next_serial();
        self.seat.surface_kb_event(Version::ALL, &surface, |kb| {
            f(serial, &surface, kb);
        });
    }
}

impl ZwpVirtualKeyboardV1RequestHandler for ZwpVirtualKeyboardV1 {
    type Error = ZwpVirtualKeyboardV1Error;

    fn keymap(&self, req: Keymap, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        if req.format != wl_keyboard::XKB_V1 {
            return Err(ZwpVirtualKeyboardV1Error::UnsupportedFormat(req.format));
        }
        if req.size == 0 {
            return Err(ZwpVirtualKeyboardV1Error::InvalidKeymap);
        }
        const MAX_SIZE: u32 = 1024 * 1024;
        if req.size > MAX_SIZE {
            return Err(ZwpVirtualKeyboardV1Error::OversizedKeymap);
        }
        let size = req.size as usize - 1;
        let client_mem = ClientMem::new_private(&req.fd, size, true, Some(&self.client), None)
            .map(Rc::new)
            .map_err(ZwpVirtualKeyboardV1Error::MapKeymap)?;
        let mut map = vec![];
        client_mem
            .offset(0, size)
            .read(&mut map)
            .map_err(ZwpVirtualKeyboardV1Error::ReadKeymap)?;
        let map = self
            .client
            .state
            .kb_ctx
            .parse_keymap(&map, None)
            .map_err(ZwpVirtualKeyboardV1Error::ParseKeymap)?;
        *self.kb_state.borrow_mut() = KeyboardState {
            id: self.client.state.keyboard_state_ids.next(),
            map: map.clone(),
            pressed_keys: Default::default(),
            mods: Default::default(),
            leds: Default::default(),
            leds_changed: Default::default(),
        };
        Ok(())
    }

    fn key(&self, req: Key, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        let kb_state = &mut *self.kb_state.borrow_mut();
        let contains = kb_state.pressed_keys.contains(&req.key);
        let (state, valid) = match req.state {
            wl_keyboard::RELEASED => (KeyState::Released, contains),
            wl_keyboard::PRESSED => (KeyState::Pressed, !contains),
            _ => return Err(ZwpVirtualKeyboardV1Error::UnknownState(req.state)),
        };
        if valid {
            self.for_each_kb(|serial, surface, kb| {
                kb.on_key(serial, req.time, req.key, state, surface.id, kb_state);
            });
            match req.state {
                wl_keyboard::RELEASED => kb_state.pressed_keys.remove(&req.key),
                _ => kb_state.pressed_keys.insert(req.key),
            };
            self.seat.latest_kb_state_id.set(kb_state.id);
            self.seat.latest_kb_state.set(self.kb_state.clone());
        }
        Ok(())
    }

    fn modifiers(&self, req: Modifiers, _slf: &Rc<Self>) -> Result<(), Self::Error> {
        let kb_state = &mut *self.kb_state.borrow_mut();
        kb_state.mods.mods_pressed.0 = req.mods_depressed;
        kb_state.mods.mods_latched.0 = req.mods_latched;
        kb_state.mods.mods_locked.0 = req.mods_locked;
        kb_state.mods.group_locked.0 = req.group;
        kb_state.mods.update_effective();
        kb_state.update_leds();
        self.for_each_kb(|serial, surface, kb| {
            kb.on_mods_changed(serial, surface.id, &kb_state);
        });
        self.seat.latest_kb_state_id.set(kb_state.id);
        self.seat.latest_kb_state.set(self.kb_state.clone());
        Ok(())
    }

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

#[derive(Debug, Error)]
pub enum ZwpVirtualKeyboardV1Error {
    #[error("Unknown key state {0}")]
    UnknownState(u32),
    #[error("Unsupported keymap format {0}")]
    UnsupportedFormat(u32),
    #[error("Keymap is invalid")]
    InvalidKeymap,
    #[error("Keymap is too large")]
    OversizedKeymap,
    #[error("Could not map the keymap")]
    MapKeymap(#[source] ClientMemError),
    #[error("Could not read the keymap")]
    ReadKeymap(#[source] ClientMemError),
    #[error("Could not parse the keymap")]
    ParseKeymap(#[source] KbvmError),
}