1
0
Fork 0
forked from wry/wry

Add blur to vulkan and opengl render pipelines

This commit is contained in:
entailz 2026-05-03 02:16:59 -07:00
parent 6d3bff952e
commit 0701c4e4cf
41 changed files with 1990 additions and 47 deletions

View file

@ -365,6 +365,34 @@ pub struct WindowMatch {
pub content_types: Option<ContentType>,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum LayerKind {
Background,
Bottom,
Top,
Overlay,
}
#[derive(Default, Debug, Clone)]
pub struct LayerMatch {
pub namespace: Option<String>,
pub layer: Option<LayerKind>,
}
#[derive(Debug, Clone)]
pub struct LayerRule {
pub match_: LayerMatch,
pub blur: Option<bool>,
pub blur_popups: Option<bool>,
pub ignore_alpha: Option<f32>,
}
#[derive(Debug, Clone, Copy)]
pub struct BlurConfig {
pub passes: Option<u8>,
pub size: Option<f32>,
}
#[derive(Debug, Clone)]
pub enum DrmDeviceMatch {
Any(Vec<DrmDeviceMatch>),
@ -577,6 +605,8 @@ pub struct Config {
pub max_action_depth: u64,
pub client_rules: Vec<ClientRule>,
pub window_rules: Vec<WindowRule>,
pub layer_rules: Vec<LayerRule>,
pub blur: Option<BlurConfig>,
pub pointer_revert_key: Option<KeySym>,
pub use_hardware_cursor: Option<bool>,
pub show_bar: Option<bool>,

View file

@ -8,6 +8,7 @@ use {
pub mod action;
mod actions;
mod blur;
mod capabilities;
mod clean_logs_older_than;
mod client_match;
@ -32,6 +33,8 @@ mod input;
mod input_match;
pub mod input_mode;
pub mod keymap;
mod layer_match;
mod layer_rule;
mod libei;
mod log_level;
pub mod mark_id;

View file

@ -0,0 +1,45 @@
use {
crate::{
config::{
BlurConfig,
context::Context,
extractor::{Extractor, ExtractorError, fltorint, int, opt},
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
},
toml::{
toml_span::{DespanExt, Span, Spanned},
toml_value::Value,
},
},
indexmap::IndexMap,
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum BlurConfigParserError {
#[error(transparent)]
Expected(#[from] UnexpectedDataType),
#[error(transparent)]
Extract(#[from] ExtractorError),
}
pub struct BlurConfigParser<'a>(pub &'a Context<'a>);
impl Parser for BlurConfigParser<'_> {
type Value = BlurConfig;
type Error = BlurConfigParserError;
const EXPECTED: &'static [DataType] = &[DataType::Table];
fn parse_table(
&mut self,
span: Span,
table: &IndexMap<Spanned<String>, Spanned<Value>>,
) -> ParseResult<Self> {
let mut ext = Extractor::new(self.0, span, table);
let (passes_val, size_val) =
ext.extract((opt(int("passes")), opt(fltorint("size"))))?;
let passes = passes_val.despan().and_then(|v| u8::try_from(v).ok());
let size = size_val.despan().map(|v| v as f32);
Ok(BlurConfig { passes, size })
}
}

View file

@ -23,6 +23,8 @@ use {
input::InputsParser,
input_mode::InputModesParser,
keymap::KeymapParser,
blur::BlurConfigParser,
layer_rule::LayerRulesParser,
libei::LibeiParser,
log_level::LogLevelParser,
output::OutputsParser,
@ -153,7 +155,9 @@ impl Parser for ConfigParser<'_> {
fallback_output_mode_val,
clean_logs_older_than_val,
mouse_follows_focus,
layer_rules_val,
),
(blur_val,),
) = ext.extract((
(
opt(val("keymap")),
@ -213,7 +217,9 @@ impl Parser for ConfigParser<'_> {
opt(val("fallback-output-mode")),
opt(val("clean-logs-older-than")),
recover(opt(bol("unstable-mouse-follows-focus"))),
opt(val("layers")),
),
(opt(val("blur")),),
))?;
let mut keymap = None;
if let Some(value) = keymap_val {
@ -495,6 +501,20 @@ impl Parser for ConfigParser<'_> {
Err(e) => log::warn!("Could not parse the window rules: {}", self.0.error(e)),
}
}
let mut layer_rules = vec![];
if let Some(value) = layer_rules_val {
match value.parse(&mut LayerRulesParser(self.0)) {
Ok(v) => layer_rules = v,
Err(e) => log::warn!("Could not parse the layer rules: {}", self.0.error(e)),
}
}
let mut blur = None;
if let Some(value) = blur_val {
match value.parse(&mut BlurConfigParser(self.0)) {
Ok(v) => blur = Some(v),
Err(e) => log::warn!("Could not parse the blur config: {}", self.0.error(e)),
}
}
let mut pointer_revert_key = None;
if let Some(value) = pointer_revert_key_str {
match Keysym::from_str(value.value) {
@ -594,6 +614,8 @@ impl Parser for ConfigParser<'_> {
max_action_depth,
client_rules,
window_rules,
layer_rules,
blur,
pointer_revert_key,
use_hardware_cursor: use_hardware_cursor.despan(),
show_bar: show_bar.despan(),

View file

@ -0,0 +1,70 @@
use {
crate::{
config::{
LayerKind, LayerMatch,
context::Context,
extractor::{Extractor, ExtractorError, opt, str, val},
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
},
toml::{
toml_span::{DespanExt, Span, Spanned, SpannedExt},
toml_value::Value,
},
},
indexmap::IndexMap,
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum LayerMatchParserError {
#[error(transparent)]
Expected(#[from] UnexpectedDataType),
#[error(transparent)]
Extract(#[from] ExtractorError),
#[error("Unknown layer `{0}` (expected background, bottom, top, or overlay)")]
UnknownLayer(String),
}
pub struct LayerMatchParser<'a>(pub &'a Context<'a>);
impl Parser for LayerMatchParser<'_> {
type Value = LayerMatch;
type Error = LayerMatchParserError;
const EXPECTED: &'static [DataType] = &[DataType::Table];
fn parse_table(
&mut self,
span: Span,
table: &IndexMap<Spanned<String>, Spanned<Value>>,
) -> ParseResult<Self> {
let mut ext = Extractor::new(self.0, span, table);
let (namespace, layer_val) = ext.extract((opt(str("namespace")), opt(val("layer"))))?;
let mut layer = None;
if let Some(value) = layer_val {
layer = Some(value.parse(&mut LayerKindParser)?);
}
Ok(LayerMatch {
namespace: namespace.despan_into(),
layer,
})
}
}
pub struct LayerKindParser;
impl Parser for LayerKindParser {
type Value = LayerKind;
type Error = LayerMatchParserError;
const EXPECTED: &'static [DataType] = &[DataType::String];
fn parse_string(&mut self, span: Span, string: &str) -> ParseResult<Self> {
let kind = match string {
"background" => LayerKind::Background,
"bottom" => LayerKind::Bottom,
"top" => LayerKind::Top,
"overlay" => LayerKind::Overlay,
_ => return Err(LayerMatchParserError::UnknownLayer(string.to_string()).spanned(span)),
};
Ok(kind)
}
}

View file

@ -0,0 +1,81 @@
use {
crate::{
config::{
LayerMatch, LayerRule,
context::Context,
extractor::{Extractor, ExtractorError, bol, fltorint, opt, val},
parser::{DataType, ParseResult, Parser, UnexpectedDataType},
parsers::layer_match::{LayerMatchParser, LayerMatchParserError},
},
toml::{
toml_span::{DespanExt, Span, Spanned},
toml_value::Value,
},
},
indexmap::IndexMap,
thiserror::Error,
};
#[derive(Debug, Error)]
pub enum LayerRuleParserError {
#[error(transparent)]
Expected(#[from] UnexpectedDataType),
#[error(transparent)]
Extract(#[from] ExtractorError),
#[error(transparent)]
Match(#[from] LayerMatchParserError),
}
pub struct LayerRuleParser<'a>(pub &'a Context<'a>);
impl Parser for LayerRuleParser<'_> {
type Value = LayerRule;
type Error = LayerRuleParserError;
const EXPECTED: &'static [DataType] = &[DataType::Table];
fn parse_table(
&mut self,
span: Span,
table: &IndexMap<Spanned<String>, Spanned<Value>>,
) -> ParseResult<Self> {
let mut ext = Extractor::new(self.0, span, table);
let (match_val, blur, blur_popups, ignore_alpha) = ext.extract((
opt(val("match")),
opt(bol("blur")),
opt(bol("blur-popups")),
opt(fltorint("ignore-alpha")),
))?;
let match_ = match match_val {
None => LayerMatch::default(),
Some(m) => m.parse_map(&mut LayerMatchParser(self.0))?,
};
let ignore_alpha = ignore_alpha.map(|s| s.value.clamp(0.0, 1.0) as f32);
Ok(LayerRule {
match_,
blur: blur.despan(),
blur_popups: blur_popups.despan(),
ignore_alpha,
})
}
}
pub struct LayerRulesParser<'a>(pub &'a Context<'a>);
impl Parser for LayerRulesParser<'_> {
type Value = Vec<LayerRule>;
type Error = LayerRuleParserError;
const EXPECTED: &'static [DataType] = &[DataType::Array];
fn parse_array(&mut self, _span: Span, array: &[Spanned<Value>]) -> ParseResult<Self> {
let mut res = vec![];
for el in array {
match el.parse(&mut LayerRuleParser(self.0)) {
Ok(o) => res.push(o),
Err(e) => {
log::warn!("Could not parse layer rule: {}", self.0.error(e));
}
}
}
Ok(res)
}
}

View file

@ -14,8 +14,9 @@ use {
crate::{
config::{
Action, ClientRule, Config, ConfigConnector, ConfigDrmDevice, ConfigKeymap,
ConnectorMatch, DrmDeviceMatch, Exec, Input, InputMatch, Output, OutputMatch,
SimpleCommand, Status, Theme, WindowRule, parse_config,
BlurConfig, ConnectorMatch, DrmDeviceMatch, Exec, Input, InputMatch, LayerKind,
LayerRule, Output,
OutputMatch, SimpleCommand, Status, Theme, WindowRule, parse_config,
},
rules::{MatcherTemp, RuleMapper},
shortcuts::ModeState,
@ -37,6 +38,8 @@ use {
is_reload,
keyboard::Keymap,
logging::{clean_logs_older_than, set_log_level},
_set_blur_config, _set_layer_rules,
_private::{BlurConfigIpc, LayerKindIpc, LayerMatchIpc, LayerRuleIpc},
on_devices_enumerated, on_idle, on_unload, quit, reload, set_autotile,
set_color_management_enabled, set_corner_radius, set_default_workspace_capture,
set_explicit_sync_enabled, set_float_above_fullscreen, set_floating_titles, set_idle,
@ -1470,6 +1473,8 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
*state.persistent.client_rule_mapper.borrow_mut() = Some(client_rule_mapper);
let (window_rules, _) = state.create_rules(&config.window_rules);
persistent.window_rules.set(window_rules);
push_layer_rules(&config.layer_rules);
push_blur_config(config.blur);
state.set_status(&config.status);
persistent.actions.borrow_mut().clear();
for a in config.named_actions {
@ -1719,6 +1724,39 @@ fn load_config(initial_load: bool, auto_reload: bool, persistent: &Rc<Persistent
}
}
fn push_blur_config(blur: Option<BlurConfig>) {
let default = BlurConfigIpc::default();
let cfg = match blur {
Some(b) => BlurConfigIpc {
passes: b.passes.unwrap_or(default.passes).clamp(1, 8),
size: b.size.unwrap_or(default.size).max(0.0),
},
None => default,
};
_set_blur_config(cfg);
}
fn push_layer_rules(rules: &[LayerRule]) {
let ipc: Vec<LayerRuleIpc> = rules
.iter()
.map(|r| LayerRuleIpc {
match_: LayerMatchIpc {
namespace: r.match_.namespace.clone(),
layer: r.match_.layer.map(|k| match k {
LayerKind::Background => LayerKindIpc::Background,
LayerKind::Bottom => LayerKindIpc::Bottom,
LayerKind::Top => LayerKindIpc::Top,
LayerKind::Overlay => LayerKindIpc::Overlay,
}),
},
blur: r.blur,
blur_popups: r.blur_popups,
ignore_alpha: r.ignore_alpha,
})
.collect();
_set_layer_rules(ipc);
}
fn create_command(exec: &Exec) -> Command {
let mut command = Command::new(&exec.prog);
for arg in &exec.args {