use niri_ipc::{LogicalOutput, Output};
use waybar_cffi::gtk::gdk::{Monitor, traits::MonitorExt};
#[derive(Debug, Clone)]
pub enum Filter {
ShowAll,
Only(String),
}
impl Filter {
pub fn should_show(&self, output: &str) -> bool {
match self {
Self::ShowAll => true,
Self::Only(only) => only == output,
}
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Matcher: u8 {
const GEOMETRY = 1 << 0;
const MODEL = 1 << 1;
const MANUFACTURER = 1 << 2;
}
}
impl Matcher {
pub fn new(monitor: &Monitor, output: &Output) -> Self {
let Some(logical) = &output.logical else {
tracing::info!(name = output.name, "output does not have a logical output");
return Self::empty();
};
let mut matches = Self::empty();
matches.set(
Matcher::GEOMETRY,
Geometry::from_gdk_monitor(monitor) == Geometry::from_niri_output(logical),
);
matches.set(
Matcher::MODEL,
match (monitor.model(), &output.model) {
(Some(gdk_model), niri_model) => gdk_model.as_str() == niri_model,
(None, niri_model) if niri_model.is_empty() => true,
_ => false,
},
);
matches.set(
Matcher::MANUFACTURER,
match (monitor.manufacturer(), &output.make) {
(Some(gdk_manufacturer), niri_make) => gdk_manufacturer.as_str() == niri_make,
(None, niri_make) if niri_make.is_empty() => true,
_ => false,
},
);
matches
}
}
#[derive(Debug, Clone, Copy)]
struct Geometry {
width: i32,
height: i32,
x: i32,
y: i32,
}
impl Geometry {
fn from_gdk_monitor(monitor: &Monitor) -> Self {
let geometry = monitor.geometry();
let scale = monitor.scale_factor();
Self {
width: geometry.width() * scale,
height: geometry.height() * scale,
x: geometry.x() * scale,
y: geometry.y() * scale,
}
}
fn from_niri_output(logical: &LogicalOutput) -> Self {
let LogicalOutput {
width,
height,
scale,
x,
y,
..
} = logical;
let scale = scale.ceil() as i32;
Self {
width: (*width as i32) * scale,
height: (*height as i32) * scale,
x: (*x) * scale,
y: (*y) * scale,
}
}
}
impl PartialEq for Geometry {
fn eq(&self, other: &Self) -> bool {
let x_delta = ((self.width as f64) / (other.width as f64)) - 1.0;
let y_delta = ((self.height as f64) / (other.height as f64)) - 1.0;
x_delta.abs() < 0.03 && y_delta.abs() < 0.03 && self.x == other.x && self.y == other.y
}
}