use crate::{
pure::geometry::{Point, Rect},
Error, Result, Xid,
};
use bitflags::bitflags;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum Prop {
Atom(Vec<String>),
Bytes(Vec<u32>),
Cardinal(Vec<u32>),
UTF8String(Vec<String>),
Window(Vec<Xid>),
WmHints(WmHints),
WmNormalHints(WmNormalHints),
}
bitflags! {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Debug, PartialEq, Eq, Hash, Clone)]
pub struct WmHintsFlags: u32 {
const INPUT_HINT = 0b0000000001;
const STATE_HINT = 0b0000000010;
const ICON_PIXMAP_HINT = 0b0000000100;
const ICON_WINDOW_HINT = 0b0000001000;
const ICON_POSITION_HINT = 0b0000010000;
const ICON_MASK_HINT = 0b0000100000;
const WINDOW_GROUP_HINT = 0b0001000000;
const URGENCY_HINT = 0b0100000000;
}
}
bitflags! {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Default, Debug, PartialEq, Eq, Hash, Clone)]
pub struct WmNormalHintsFlags: u32 {
const U_POSITION = 0b0000000001;
const U_SIZE = 0b0000000010;
const P_POSITION = 0b0000000100;
const P_SIZE = 0b0000001000;
const P_MIN_SIZE = 0b0000010000;
const P_MAX_SIZE = 0b0000100000;
const P_RESIZE_INC = 0b0001000000;
const P_ASPECT = 0b0010000000;
const P_BASE_SIZE = 0b0100000000;
const P_WIN_GRAVITY = 0b1000000000;
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum WmState {
Withdrawn,
Normal,
Iconic,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum MapState {
Unmapped,
UnViewable,
Viewable,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum WindowClass {
CopyFromParent,
InputOutput,
InputOnly,
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct WmHints {
pub(crate) flags: WmHintsFlags,
pub(crate) accepts_input: bool,
pub(crate) initial_state: WmState,
pub(crate) icon_pixmap: u32,
pub(crate) icon_win: Xid,
pub(crate) icon_position: Point,
pub(crate) icon_mask: u32,
pub(crate) window_group: u32,
}
impl WmHints {
#[allow(clippy::too_many_arguments)]
pub fn new(
flags: WmHintsFlags,
accepts_input: bool,
initial_state: WmState,
icon_pixmap: u32,
icon_win: Xid,
icon_position: Point,
icon_mask: u32,
window_group: u32,
) -> Self {
Self {
flags,
accepts_input,
initial_state,
icon_pixmap,
icon_win,
icon_position,
icon_mask,
window_group,
}
}
pub fn try_from_bytes(raw: &[u32]) -> Result<Self> {
if raw.len() != 9 {
return Err(Error::InvalidHints {
reason: format!(
"raw bytes should be [u32; 9] for WmHints, got [u32; {}]",
raw.len()
),
});
}
let flags = WmHintsFlags::from_bits(raw[0]).unwrap();
let accepts_input = !flags.contains(WmHintsFlags::INPUT_HINT) || raw[1] > 0;
let initial_state = match (flags.contains(WmHintsFlags::STATE_HINT), raw[2]) {
(true, 0) => WmState::Withdrawn,
(true, 1) | (false, _) => WmState::Normal,
(true, 2) => WmState::Iconic,
_ => {
return Err(Error::InvalidHints {
reason: format!("initial state flag should be 0, 1, 2: got {}", raw[2]),
})
}
};
Ok(Self {
flags,
accepts_input,
initial_state,
icon_pixmap: raw[3],
icon_win: Xid(raw[4]),
icon_position: Point::new(raw[5] as i32, raw[6] as i32),
icon_mask: raw[7],
window_group: raw[8],
})
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct WmNormalHints {
pub(crate) flags: WmNormalHintsFlags,
pub(crate) base: Option<Rect>,
pub(crate) min: Option<Rect>,
pub(crate) max: Option<Rect>,
pub(crate) user_specified: Option<Rect>,
}
impl WmNormalHints {
pub fn new(
flags: WmNormalHintsFlags,
base: Option<Rect>,
min: Option<Rect>,
max: Option<Rect>,
user_specified: Option<Rect>,
) -> Self {
Self {
flags,
base,
min,
max,
user_specified,
}
}
pub fn apply_to(&self, mut r: Rect) -> Rect {
if let Some(max) = self.max {
if r.is_larger_than(&max) {
r.w = max.w;
r.h = max.h
}
}
if let Some(min) = self.min {
if min.is_larger_than(&r) {
r.w = min.w;
r.h = min.h;
}
}
r
}
pub fn try_from_bytes(raw: &[u32]) -> Result<Self> {
if raw.len() != 18 {
return Err(Error::InvalidHints {
reason: format!(
"raw bytes should be [u32; 18] for WmNormalHints, got [u32; {}]",
raw.len()
),
});
}
let flags = WmNormalHintsFlags::from_bits(raw[0]).unwrap();
let (x, y) = (raw[1] as i32, raw[2] as i32);
let (user_w, user_h) = (raw[3], raw[4]);
let (min_w, min_h) = (raw[5], raw[6]);
let (max_w, max_h) = (raw[7], raw[8]);
let (base_w, base_h) = (raw[15], raw[16]);
let if_set = |x, y, w, h| {
if w > 0 && h > 0 {
Some(Rect::new(x, y, w, h))
} else {
None
}
};
Ok(Self {
flags,
base: if_set(x, y, base_w, base_h),
min: if_set(x, y, min_w, min_h),
max: if_set(x, y, max_w, max_h),
user_specified: if_set(x, y, user_w, user_h),
})
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct WindowAttributes {
pub(crate) override_redirect: bool,
pub(crate) map_state: MapState,
pub(crate) window_class: WindowClass,
}
impl WindowAttributes {
pub fn new(override_redirect: bool, map_state: MapState, window_class: WindowClass) -> Self {
Self {
override_redirect,
map_state,
window_class,
}
}
}