Begin work on window rules

This commit is contained in:
Ottatop 2023-09-04 22:14:18 -05:00
parent 6d3c6e2c62
commit d9ce324606
3 changed files with 110 additions and 1 deletions

View file

@ -3,6 +3,8 @@
// The MessagePack format for these is a one-element map where the element's key is the enum name and its
// value is a map of the enum's values
mod window_rules;
use crate::{
layout::Layout,
output::OutputName,

107
src/api/msg/window_rules.rs Normal file
View file

@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-3.0-or-later
use std::num::NonZeroU32;
use smithay::wayland::{compositor, shell::xdg::XdgToplevelSurfaceData};
use crate::{
output::OutputName,
state::{State, WithState},
tag::TagId,
window::{window_state::FullscreenOrMaximized, WindowElement},
};
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum WindowRuleCondition {
/// This condition is met when any of the conditions provided is met.
CondAny(Vec<WindowRuleCondition>),
/// This condition is met when all of the conditions provided are met.
CondAll(Vec<WindowRuleCondition>),
/// This condition is met when the class matches.
Class(String),
/// This condition is met when the title matches.
Title(String),
/// This condition is met when the tag matches.
Tag(TagId),
}
impl WindowRuleCondition {
/// RefCell Safety: This method uses RefCells on `window`.
pub fn is_met(&self, state: &State, window: &WindowElement) -> bool {
match self {
WindowRuleCondition::CondAny(conds) => {
conds.iter().any(|cond| Self::is_met(cond, state, window))
}
WindowRuleCondition::CondAll(conds) => {
conds.iter().all(|cond| Self::is_met(cond, state, window))
}
WindowRuleCondition::Class(class) => {
let Some(wl_surf) = window.wl_surface() else {
return false;
};
let current_class = compositor::with_states(&wl_surf, |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.app_id
.clone()
});
current_class.as_ref() == Some(class)
}
WindowRuleCondition::Title(title) => {
let Some(wl_surf) = window.wl_surface() else {
return false;
};
let current_title = compositor::with_states(&wl_surf, |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.expect("XdgToplevelSurfaceData wasn't in surface's data map")
.lock()
.expect("Failed to lock Mutex<XdgToplevelSurfaceData>")
.title
.clone()
});
current_title.as_ref() == Some(title)
}
WindowRuleCondition::Tag(tag) => {
let Some(tag) = tag.tag(state) else {
return false;
};
window.with_state(|state| state.tags.contains(&tag))
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum WindowRule {
/// Set the output the window will open on.
Output(OutputName),
/// Set the tags the output will have on open.
Tags(Vec<TagId>),
/// Set the window to floating or tiled on open.
FloatingOrTiled(FloatingOrTiled),
/// Set the window to fullscreen, maximized, or force it to neither.
FullscreenOrMaximized(FullscreenOrMaximized),
/// Set the window's initial size.
Size(NonZeroU32, NonZeroU32),
/// Set the window's initial location. If the window is tiled, it will snap to this position
/// when set to floating.
Location(i32, i32),
}
// TODO: just skip serializing fields on the other FloatingOrTiled
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum FloatingOrTiled {
Floating,
Tiled,
}

View file

@ -301,7 +301,7 @@ impl FloatingOrTiled {
}
}
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum FullscreenOrMaximized {
Neither,
Fullscreen,