use async_trait::async_trait;
use std::fmt;
use crate::error::{DisplayError, DisplayResult};
use crate::traits::{OutputEditable, UniversalTopology};
use crate::types::{DisplayId, OutputState};
pub mod displmgr_wlr;
pub mod displmgr_drm;
pub mod displmgr_kde;
pub mod displmgr_udev;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinuxBackendVariant {
Wlr,
Drm,
Kde,
Udev,
}
impl LinuxBackendVariant {
pub fn detect() -> Self {
if std::env::var("WAYLAND_DISPLAY").is_ok() {
Self::Wlr
} else if std::env::var("KDE_FULL_SESSION").is_ok() {
Self::Kde
} else if std::path::Path::new("/sys/class/drm/").exists() {
Self::Udev
} else {
Self::Drm
}
}
}
pub enum LinuxTopology {
Wlr(displmgr_wlr::WlrTopology),
Drm(displmgr_drm::DrmTopology),
Kde(displmgr_kde::KdeTopology),
Udev(displmgr_udev::UdevTopology),
}
impl LinuxTopology {
pub fn acquire() -> DisplayResult<Self> {
let variant = LinuxBackendVariant::detect();
Self::with_backend(variant)
}
pub fn with_backend(variant: LinuxBackendVariant) -> DisplayResult<Self> {
match variant {
LinuxBackendVariant::Wlr => {
let inner = displmgr_wlr::WlrTopology::acquire()?;
Ok(Self::Wlr(inner))
}
LinuxBackendVariant::Drm => {
let inner = displmgr_drm::DrmTopology::acquire()?;
Ok(Self::Drm(inner))
}
LinuxBackendVariant::Kde => {
let inner = displmgr_kde::KdeTopology::acquire()?;
Ok(Self::Kde(inner))
}
LinuxBackendVariant::Udev => {
let inner = displmgr_udev::UdevTopology::acquire()?;
Ok(Self::Udev(inner))
}
}
}
pub fn variant(&self) -> LinuxBackendVariant {
match self {
Self::Wlr(_) => LinuxBackendVariant::Wlr,
Self::Drm(_) => LinuxBackendVariant::Drm,
Self::Kde(_) => LinuxBackendVariant::Kde,
Self::Udev(_) => LinuxBackendVariant::Udev,
}
}
}
impl fmt::Debug for LinuxTopology {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Wlr(inner) => f.debug_tuple("Wlr").field(inner).finish(),
Self::Drm(inner) => f.debug_tuple("Drm").field(inner).finish(),
Self::Kde(inner) => f.debug_tuple("Kde").field(inner).finish(),
Self::Udev(inner) => f.debug_tuple("Udev").field(inner).finish(),
}
}
}
#[async_trait]
impl UniversalTopology for LinuxTopology {
fn acquire() -> DisplayResult<Self> {
Self::acquire()
}
fn get_outputs(&self) -> Vec<OutputState> {
match self {
Self::Wlr(inner) => inner.get_outputs(),
Self::Drm(inner) => inner.get_outputs(),
Self::Kde(inner) => inner.get_outputs(),
Self::Udev(inner) => inner.get_outputs(),
}
}
fn edit_output(&mut self, id: &DisplayId) -> DisplayResult<Box<dyn OutputEditable + '_>> {
match self {
Self::Wlr(inner) => inner.edit_output(id),
Self::Drm(inner) => inner.edit_output(id),
Self::Kde(inner) => inner.edit_output(id),
Self::Udev(inner) => inner.edit_output(id),
}
}
fn set_persistence(&mut self, enabled: bool) -> &mut Self {
match self {
Self::Wlr(inner) => {
inner.set_persistence(enabled);
}
Self::Drm(inner) => {
inner.set_persistence(enabled);
}
Self::Kde(inner) => {
inner.set_persistence(enabled);
}
Self::Udev(inner) => {
inner.set_persistence(enabled);
}
}
self
}
async fn validate(&self) -> DisplayResult<()> {
match self {
Self::Wlr(inner) => inner.validate().await,
Self::Drm(inner) => inner.validate().await,
Self::Kde(inner) => inner.validate().await,
Self::Udev(inner) => inner.validate().await,
}
}
async fn commit(&mut self) -> DisplayResult<()> {
match self {
Self::Wlr(inner) => inner.commit().await,
Self::Drm(inner) => inner.commit().await,
Self::Kde(inner) => inner.commit().await,
Self::Udev(inner) => inner.commit().await,
}
}
}