182 lines
4.3 KiB
Rust
182 lines
4.3 KiB
Rust
use std::{
|
|
fmt::{Display, Write},
|
|
str::FromStr,
|
|
};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use strum::IntoEnumIterator;
|
|
|
|
use super::{
|
|
rule::{Condition, RuleOperator},
|
|
StringParseError,
|
|
};
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize, strum::EnumIter, PartialEq)]
|
|
pub enum Window {
|
|
Urgent,
|
|
X11(i32),
|
|
/// references the minimized window on the focused tag
|
|
/// that has been minimized for the longest time
|
|
LongestMinimized,
|
|
/// references the minimized window on the focused tag
|
|
/// that has been minimized most recently
|
|
LastMinimized,
|
|
}
|
|
|
|
impl FromStr for Window {
|
|
type Err = StringParseError;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
if let Ok(val) = i32::from_str(s) {
|
|
Ok(Self::X11(val))
|
|
} else {
|
|
Window::iter()
|
|
.find(|w| w.to_string() == s)
|
|
.ok_or(StringParseError::UnknownValue)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for Window {
|
|
fn default() -> Self {
|
|
Self::Urgent
|
|
}
|
|
}
|
|
|
|
impl From<i32> for Window {
|
|
fn from(value: i32) -> Self {
|
|
Self::X11(value)
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Window {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Window::Urgent => f.write_str("urgent"),
|
|
Window::X11(id) => write!(f, "{id}"),
|
|
Window::LongestMinimized => f.write_str("longest-minimized"),
|
|
Window::LastMinimized => f.write_str("last-minimized"),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct TagStatus {
|
|
name: String,
|
|
state: TagState,
|
|
}
|
|
|
|
impl TagStatus {
|
|
pub fn name(&self) -> &str {
|
|
&self.name
|
|
}
|
|
|
|
pub fn state(&self) -> TagState {
|
|
self.state
|
|
}
|
|
}
|
|
|
|
impl FromStr for TagStatus {
|
|
type Err = StringParseError;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let mut parts = s.chars();
|
|
let state = parts
|
|
.next()
|
|
.ok_or(StringParseError::UnknownValue)?
|
|
.try_into()?;
|
|
let name = parts.collect();
|
|
|
|
Ok(Self { name, state })
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, strum::EnumIter)]
|
|
pub enum TagState {
|
|
Empty,
|
|
NotEmpty,
|
|
/// The tag contains an urgent window
|
|
Urgent,
|
|
/// The tag is viewed on the specified MONITOR and it is focused
|
|
SameMonitorFocused,
|
|
/// The tag is viewed on the specified MONITOR, but this monitor is not focused
|
|
SameMonitor,
|
|
/// The tag is viewed on a different MONITOR and it is focused
|
|
DifferentMonitorFocused,
|
|
/// The tag is viewed on a different MONITOR, but this monitor is not focused
|
|
DifferentMonitor,
|
|
}
|
|
|
|
impl TryFrom<char> for TagState {
|
|
type Error = StringParseError;
|
|
|
|
fn try_from(value: char) -> Result<Self, Self::Error> {
|
|
Self::iter()
|
|
.into_iter()
|
|
.find(|i| char::from(i) == value)
|
|
.ok_or(StringParseError::UnknownValue)
|
|
}
|
|
}
|
|
|
|
impl FromStr for TagState {
|
|
type Err = StringParseError;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
Self::iter()
|
|
.into_iter()
|
|
.find(|i| i.to_string() == s)
|
|
.ok_or(StringParseError::UnknownValue)
|
|
}
|
|
}
|
|
|
|
impl From<&TagState> for char {
|
|
fn from(value: &TagState) -> Self {
|
|
match value {
|
|
TagState::SameMonitorFocused => '#',
|
|
TagState::SameMonitor => '+',
|
|
TagState::DifferentMonitorFocused => '%',
|
|
TagState::DifferentMonitor => '-',
|
|
TagState::Empty => '.',
|
|
TagState::NotEmpty => ':',
|
|
TagState::Urgent => '!',
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for TagState {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_char(self.into())
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Copy, strum::Display)]
|
|
#[strum(serialize_all = "UPPERCASE")]
|
|
pub enum WindowType {
|
|
Dialog,
|
|
Utility,
|
|
Splash,
|
|
Notification,
|
|
Dock,
|
|
Desktop,
|
|
}
|
|
|
|
impl WindowType {
|
|
pub fn or<I: Iterator<Item = Self>>(types: I) -> Condition {
|
|
Condition::WindowType {
|
|
operator: RuleOperator::Regex,
|
|
value: format!(
|
|
"_NET_WM_WINDOW_TYPE_({})",
|
|
types.map(|t| t.to_string()).collect::<Vec<_>>().join("|")
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! window_types {
|
|
($($ty:tt),+) => {
|
|
crate::hlwm::window::WindowType::or([$(
|
|
crate::hlwm::window::WindowType::$ty
|
|
),+].into_iter())
|
|
};
|
|
}
|