From 858400ecc6afc73ea2962f213f16bca057ccdfe1 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Sun, 17 Dec 2023 19:06:27 +0100 Subject: [PATCH] Add a dummy backend --- src/backend/consumer.rs | 3 + src/backend/consumer/dummy.rs | 21 ++++++ src/backend/consumer/x11.rs | 20 +++--- src/backend/producer.rs | 7 ++ src/backend/producer/dummy.rs | 41 +++++++++++ src/backend/producer/libei.rs | 4 +- src/backend/producer/x11.rs | 11 +-- src/client.rs | 1 + src/consumer.rs | 129 +++++++++++----------------------- src/main.rs | 3 +- src/producer.rs | 87 +++++++---------------- 11 files changed, 152 insertions(+), 175 deletions(-) create mode 100644 src/backend/consumer/dummy.rs create mode 100644 src/backend/producer/dummy.rs diff --git a/src/backend/consumer.rs b/src/backend/consumer.rs index 2aae0fc1..5970d08c 100644 --- a/src/backend/consumer.rs +++ b/src/backend/consumer.rs @@ -15,3 +15,6 @@ pub mod libei; #[cfg(target_os = "macos")] pub mod macos; + +/// fallback consumer +pub mod dummy; diff --git a/src/backend/consumer/dummy.rs b/src/backend/consumer/dummy.rs new file mode 100644 index 00000000..7101a2b6 --- /dev/null +++ b/src/backend/consumer/dummy.rs @@ -0,0 +1,21 @@ +use async_trait::async_trait; +use crate::{consumer::EventConsumer, event::Event, client::{ClientHandle, ClientEvent}}; + +pub struct DummyConsumer; + +impl DummyConsumer { + pub fn new() -> Self { + Self {} + } +} + +#[async_trait] +impl EventConsumer for DummyConsumer { + async fn consume(&mut self, event: Event, client_handle: ClientHandle) { + log::info!("received event: ({client_handle}) {event}"); + } + async fn notify(&mut self, client_event: ClientEvent) { + log::info!("{client_event:?}"); + } + async fn destroy(&mut self) {} +} diff --git a/src/backend/consumer/x11.rs b/src/backend/consumer/x11.rs index 7695fa56..1319031e 100644 --- a/src/backend/consumer/x11.rs +++ b/src/backend/consumer/x11.rs @@ -1,3 +1,4 @@ +use anyhow::{anyhow, Result}; use async_trait::async_trait; use std::ptr; use x11::{xlib::{self, XCloseDisplay}, xtest}; @@ -11,15 +12,16 @@ pub struct X11Consumer { unsafe impl Send for X11Consumer {} impl X11Consumer { - pub fn new() -> Self { + pub fn new() -> Result { let display = unsafe { match xlib::XOpenDisplay(ptr::null()) { - d if d == ptr::null::() as *mut xlib::Display => None, - display => Some(display), + d if d == ptr::null::() as *mut xlib::Display => { + Err(anyhow!("could not open display")) + } + display => Ok(display), } - }; - let display = display.expect("could not open display"); - Self { display } + }?; + Ok(Self { display }) } fn relative_motion(&self, dx: i32, dy: i32) { @@ -68,12 +70,6 @@ impl X11Consumer { } } -impl Default for X11Consumer { - fn default() -> Self { - Self::new() - } -} - impl Drop for X11Consumer { fn drop(&mut self) { unsafe { diff --git a/src/backend/producer.rs b/src/backend/producer.rs index eac1f69a..4b171bd2 100644 --- a/src/backend/producer.rs +++ b/src/backend/producer.rs @@ -1,10 +1,17 @@ #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] pub mod libei; + #[cfg(target_os = "macos")] pub mod macos; + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] pub mod wayland; + #[cfg(windows)] pub mod windows; + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] pub mod x11; + +/// fallback event producer +pub mod dummy; diff --git a/src/backend/producer/dummy.rs b/src/backend/producer/dummy.rs new file mode 100644 index 00000000..dc802b45 --- /dev/null +++ b/src/backend/producer/dummy.rs @@ -0,0 +1,41 @@ +use std::io; +use std::pin::Pin; +use std::task::{Poll, Context}; + +use futures_core::Stream; + +use crate::event::Event; +use crate::producer::EventProducer; + +use crate::client::{ClientEvent, ClientHandle}; + +pub struct DummyProducer {} + +impl DummyProducer { + pub fn new() -> Self { + Self {} + } +} + +impl Default for DummyProducer { + fn default() -> Self { + Self::new() + } +} + +impl EventProducer for DummyProducer { + fn notify(&mut self, _: ClientEvent) {} + + fn release(&mut self) {} +} + +impl Stream for DummyProducer { + type Item = io::Result<(ClientHandle, Event)>; + + fn poll_next( + self: Pin<&mut Self>, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Pending + } +} diff --git a/src/backend/producer/libei.rs b/src/backend/producer/libei.rs index 060eca37..16c0eb05 100644 --- a/src/backend/producer/libei.rs +++ b/src/backend/producer/libei.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; use std::{io, task::Poll}; use futures_core::Stream; @@ -9,7 +9,7 @@ pub struct LibeiProducer {} impl LibeiProducer { pub fn new() -> Result { - Ok(Self {}) + Err(anyhow!("not implemented")) } } diff --git a/src/backend/producer/x11.rs b/src/backend/producer/x11.rs index ad697d11..7c4e921e 100644 --- a/src/backend/producer/x11.rs +++ b/src/backend/producer/x11.rs @@ -1,3 +1,4 @@ +use anyhow::{anyhow, Result}; use std::io; use std::task::Poll; @@ -11,14 +12,8 @@ use crate::client::{ClientEvent, ClientHandle}; pub struct X11Producer {} impl X11Producer { - pub fn new() -> Self { - Self {} - } -} - -impl Default for X11Producer { - fn default() -> Self { - Self::new() + pub fn new() -> Result { + return Err(anyhow!("not implemented")); } } diff --git a/src/client.rs b/src/client.rs index 81285baa..2f1f8ec5 100644 --- a/src/client.rs +++ b/src/client.rs @@ -69,6 +69,7 @@ pub struct Client { pub pos: Position, } +#[derive(Debug)] pub enum ClientEvent { Create(ClientHandle, Position), Destroy(ClientHandle), diff --git a/src/consumer.rs b/src/consumer.rs index 1c1b6abb..b4320d3b 100644 --- a/src/consumer.rs +++ b/src/consumer.rs @@ -1,9 +1,6 @@ use async_trait::async_trait; use std::future; -#[cfg(all(unix, not(target_os = "macos")))] -use std::env; - use crate::{ backend::consumer, client::{ClientEvent, ClientHandle}, @@ -11,15 +8,6 @@ use crate::{ }; use anyhow::Result; -#[cfg(all(unix, not(target_os = "macos")))] -#[derive(Debug)] -enum Backend { - Wlroots, - X11, - RemoteDesktopPortal, - Libei, -} - #[async_trait] pub trait EventConsumer: Send { async fn consume(&mut self, event: Event, client_handle: ClientHandle); @@ -33,90 +21,55 @@ pub trait EventConsumer: Send { async fn destroy(&mut self); } -pub async fn create() -> Result> { +pub async fn create() -> Box { #[cfg(windows)] - return Ok(Box::new(consumer::windows::WindowsConsumer::new())); + return Box::new(consumer::windows::WindowsConsumer::new()); #[cfg(target_os = "macos")] - return Ok(Box::new(consumer::macos::MacOSConsumer::new()?)); - - #[cfg(all(unix, not(target_os = "macos")))] - let backend = match env::var("XDG_SESSION_TYPE") { - Ok(session_type) => match session_type.as_str() { - "x11" => { - log::info!("XDG_SESSION_TYPE = x11 -> using x11 event consumer"); - Backend::X11 - } - "wayland" => { - log::info!("XDG_SESSION_TYPE = wayland -> using wayland event consumer"); - match env::var("XDG_CURRENT_DESKTOP") { - Ok(current_desktop) => match current_desktop.as_str() { - "GNOME" => { - log::info!("XDG_CURRENT_DESKTOP = GNOME -> using libei backend"); - Backend::Libei - } - "KDE" => { - log::info!( - "XDG_CURRENT_DESKTOP = KDE -> using xdg_desktop_portal backend" - ); - Backend::RemoteDesktopPortal - } - "sway" => { - log::info!("XDG_CURRENT_DESKTOP = sway -> using wlroots backend"); - Backend::Wlroots - } - "Hyprland" => { - log::info!("XDG_CURRENT_DESKTOP = Hyprland -> using wlroots backend"); - Backend::Wlroots - } - _ => { - log::warn!( - "unknown XDG_CURRENT_DESKTOP -> defaulting to wlroots backend" - ); - Backend::Wlroots - } - }, - // default to wlroots backend for now - _ => { - log::warn!("unknown XDG_CURRENT_DESKTOP -> defaulting to wlroots backend"); - Backend::Wlroots - } - } - } - _ => panic!("unknown XDG_SESSION_TYPE"), - }, - Err(_) => { - panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!") + match consumer::macos::MacOSConsumer::new() { + Ok(c) => { + log::info!("using macos event consumer"); + return Box::new(c); } - }; + Err(e) => log::error!("macos consumer not available: {e}"), + } - #[cfg(all(unix, not(target_os = "macos")))] - match backend { - Backend::Libei => { - #[cfg(not(feature = "libei"))] - panic!("feature libei not enabled"); - #[cfg(feature = "libei")] - Ok(Box::new(consumer::libei::LibeiConsumer::new().await?)) + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + match consumer::wlroots::WlrootsConsumer::new() { + Ok(c) => { + log::info!("using wlroots event consumer"); + return Box::new(c); } - Backend::RemoteDesktopPortal => { - #[cfg(not(feature = "xdg_desktop_portal"))] - panic!("feature xdg_desktop_portal not enabled"); - #[cfg(feature = "xdg_desktop_portal")] - Ok(Box::new( - consumer::xdg_desktop_portal::DesktopPortalConsumer::new().await?, - )) + Err(e) => log::info!("wayland backend not available: {e}"), + } + + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + match consumer::libei::LibeiConsumer::new().await { + Ok(c) => { + log::info!("using libei event consumer"); + return Box::new(c); } - Backend::Wlroots => { - #[cfg(not(feature = "wayland"))] - panic!("feature wayland not enabled"); - #[cfg(feature = "wayland")] - Ok(Box::new(consumer::wlroots::WlrootsConsumer::new()?)) + Err(e) => log::info!("libei not available: {e}"), + } + + #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] + match consumer::xdg_desktop_portal::DesktopPortalConsumer::new().await { + Ok(c) => { + log::info!("using xdg-remote-desktop-portal event consumer"); + return Box::new(c); } - Backend::X11 => { - #[cfg(not(feature = "x11"))] - panic!("feature x11 not enabled"); - #[cfg(feature = "x11")] - Ok(Box::new(consumer::x11::X11Consumer::new())) + Err(e) => log::info!("remote desktop portal not available: {e}"), + } + + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + match consumer::x11::X11Consumer::new() { + Ok(c) => { + log::info!("using x11 event consumer"); + return Box::new(c); } + Err(e) => log::info!("x11 consumer not available: {e}"), } + + log::error!("falling back to dummy event consumer"); + Box::new(consumer::dummy::DummyConsumer::new()) } diff --git a/src/main.rs b/src/main.rs index c608417a..f03b1195 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,8 +70,7 @@ fn run_service(config: &Config) -> Result<()> { }; // create event producer and consumer - let (producer, consumer) = join!(producer::create(), consumer::create(),); - let (producer, consumer) = (producer?, consumer?); + let (producer, consumer) = join!(producer::create(), consumer::create()); // create server let mut event_server = Server::new(config, frontend_adapter, consumer, producer).await?; diff --git a/src/producer.rs b/src/producer.rs index 8213f60a..368fb734 100644 --- a/src/producer.rs +++ b/src/producer.rs @@ -1,4 +1,3 @@ -use anyhow::Result; use std::io; use futures_core::Stream; @@ -9,77 +8,39 @@ use crate::{ event::Event, }; -#[cfg(all(unix, not(target_os = "macos")))] -use std::env; - -#[cfg(all(unix, not(target_os = "macos")))] -enum Backend { - LayerShell, - Libei, - X11, -} - -pub async fn create() -> Result> { +pub async fn create() -> Box { #[cfg(target_os = "macos")] - return Ok(Box::new(producer::macos::MacOSProducer::new())); + return Box::new(producer::macos::MacOSProducer::new()); #[cfg(windows)] - return Ok(Box::new(producer::windows::WindowsProducer::new())); + return Box::new(producer::windows::WindowsProducer::new()); - #[cfg(all(unix, not(target_os = "macos")))] - let backend = match env::var("XDG_SESSION_TYPE") { - Ok(session_type) => match session_type.as_str() { - "x11" => { - log::info!("XDG_SESSION_TYPE = x11 -> using X11 event producer"); - Backend::X11 - } - "wayland" => { - log::info!("XDG_SESSION_TYPE = wayland -> using wayland event producer"); - match env::var("XDG_CURRENT_DESKTOP") { - Ok(desktop) => match desktop.as_str() { - "GNOME" => { - log::info!("XDG_CURRENT_DESKTOP = GNOME -> using libei backend"); - Backend::Libei - } - d => { - log::info!("XDG_CURRENT_DESKTOP = {d} -> using layer_shell backend"); - Backend::LayerShell - } - }, - Err(_) => { - log::warn!("XDG_CURRENT_DESKTOP not set! Assuming layer_shell support -> using layer_shell backend"); - Backend::LayerShell - } - } - } - _ => panic!("unknown XDG_SESSION_TYPE"), - }, - Err(_) => { - panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!") + match producer::libei::LibeiProducer::new() { + Ok(p) => { + log::info!("using libei event producer"); + return Box::new(p); } - }; + Err(e) => log::info!("libei event producer not available: {e}"), + } - #[cfg(all(unix, not(target_os = "macos")))] - match backend { - Backend::X11 => { - #[cfg(not(feature = "x11"))] - panic!("feature x11 not enabled"); - #[cfg(feature = "x11")] - Ok(Box::new(producer::x11::X11Producer::new())) + match producer::wayland::WaylandEventProducer::new() { + Ok(p) => { + log::info!("using layer-shell event producer"); + return Box::new(p); } - Backend::LayerShell => { - #[cfg(not(feature = "wayland"))] - panic!("feature wayland not enabled"); - #[cfg(feature = "wayland")] - Ok(Box::new(producer::wayland::WaylandEventProducer::new()?)) - } - Backend::Libei => { - #[cfg(not(feature = "libei"))] - panic!("feature libei not enabled"); - #[cfg(feature = "libei")] - Ok(Box::new(producer::libei::LibeiProducer::new()?)) + Err(e) => log::info!("layer_shell event producer not available: {e}"), + } + + match producer::x11::X11Producer::new() { + Ok(p) => { + log::info!("using x11 event producer"); + return Box::new(p); } + Err(e) => log::info!("x11 event producer not available: {e}"), } + + log::error!("falling back to dummy event producer"); + Box::new(producer::dummy::DummyProducer::new()) } pub trait EventProducer: Stream> + Unpin {