use anyhow::Result;
use std::collections::HashMap;
use x11rb::connection::Connection;
use x11rb::protocol::xproto::*;
pub struct AtomCache {
atoms: HashMap<String, Atom>,
}
impl AtomCache {
pub fn new() -> Self {
Self {
atoms: HashMap::new(),
}
}
pub fn get_atom<C: Connection>(&mut self, conn: &C, name: &str) -> Result<Atom> {
if let Some(&atom) = self.atoms.get(name) {
return Ok(atom);
}
let atom = conn.intern_atom(false, name.as_bytes())?.reply()?.atom;
self.atoms.insert(name.to_string(), atom);
Ok(atom)
}
pub fn get_atoms<C: Connection>(&mut self, conn: &C, names: &[&str]) -> Result<Vec<Atom>> {
names.iter().map(|name| self.get_atom(conn, name)).collect()
}
}
impl Default for AtomCache {
fn default() -> Self {
Self::new()
}
}
pub struct CommonAtoms {
pub wm_protocols: Atom,
pub wm_delete_window: Atom,
pub wm_state: Atom,
pub wm_change_state: Atom,
pub net_wm_state: Atom,
pub net_wm_state_above: Atom,
pub net_wm_state_below: Atom,
pub net_wm_state_sticky: Atom,
pub net_wm_state_skip_taskbar: Atom,
pub net_wm_state_skip_pager: Atom,
pub net_wm_window_type: Atom,
pub net_wm_window_type_desktop: Atom,
pub net_wm_window_type_dock: Atom,
pub net_wm_window_type_toolbar: Atom,
pub net_wm_window_type_utility: Atom,
pub net_wm_window_type_dialog: Atom,
pub net_wm_window_type_normal: Atom,
pub net_wm_name: Atom,
pub net_wm_visible_name: Atom,
pub net_wm_desktop: Atom,
pub net_current_desktop: Atom,
pub net_number_of_desktops: Atom,
pub net_supporting_wm_check: Atom,
pub net_wm_pid: Atom,
pub utf8_string: Atom,
}
impl CommonAtoms {
pub fn new<C: Connection>(conn: &C) -> Result<Self> {
let atom_names = [
"WM_PROTOCOLS",
"WM_DELETE_WINDOW",
"WM_STATE",
"WM_CHANGE_STATE",
"_NET_WM_STATE",
"_NET_WM_STATE_ABOVE",
"_NET_WM_STATE_BELOW",
"_NET_WM_STATE_STICKY",
"_NET_WM_STATE_SKIP_TASKBAR",
"_NET_WM_STATE_SKIP_PAGER",
"_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_DESKTOP",
"_NET_WM_WINDOW_TYPE_DOCK",
"_NET_WM_WINDOW_TYPE_TOOLBAR",
"_NET_WM_WINDOW_TYPE_UTILITY",
"_NET_WM_WINDOW_TYPE_DIALOG",
"_NET_WM_WINDOW_TYPE_NORMAL",
"_NET_WM_NAME",
"_NET_WM_VISIBLE_NAME",
"_NET_WM_DESKTOP",
"_NET_CURRENT_DESKTOP",
"_NET_NUMBER_OF_DESKTOPS",
"_NET_SUPPORTING_WM_CHECK",
"_NET_WM_PID",
"UTF8_STRING",
];
let cookies: Result<Vec<_>, _> = atom_names
.iter()
.map(|name| conn.intern_atom(false, name.as_bytes()))
.collect();
let atoms: Vec<Atom> = cookies?
.into_iter()
.map(|cookie| cookie.reply().map(|reply| reply.atom))
.collect::<Result<Vec<_>, _>>()?;
Ok(Self {
wm_protocols: atoms[0],
wm_delete_window: atoms[1],
wm_state: atoms[2],
wm_change_state: atoms[3],
net_wm_state: atoms[4],
net_wm_state_above: atoms[5],
net_wm_state_below: atoms[6],
net_wm_state_sticky: atoms[7],
net_wm_state_skip_taskbar: atoms[8],
net_wm_state_skip_pager: atoms[9],
net_wm_window_type: atoms[10],
net_wm_window_type_desktop: atoms[11],
net_wm_window_type_dock: atoms[12],
net_wm_window_type_toolbar: atoms[13],
net_wm_window_type_utility: atoms[14],
net_wm_window_type_dialog: atoms[15],
net_wm_window_type_normal: atoms[16],
net_wm_name: atoms[17],
net_wm_visible_name: atoms[18],
net_wm_desktop: atoms[19],
net_current_desktop: atoms[20],
net_number_of_desktops: atoms[21],
net_supporting_wm_check: atoms[22],
net_wm_pid: atoms[23],
utf8_string: atoms[24],
})
}
}