From 5a7e0cf89ca4b14338ced37086a9f7520301f5b1 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Sat, 9 Dec 2023 00:43:54 +0100 Subject: [PATCH] formatting --- src/backend/consumer.rs | 2 +- src/backend/consumer/libei.rs | 213 +++++++++++++++------ src/backend/consumer/windows.rs | 73 ++++--- src/backend/consumer/wlroots.rs | 40 ++-- src/backend/consumer/x11.rs | 8 +- src/backend/consumer/xdg_desktop_portal.rs | 79 ++++++-- src/backend/producer/libei.rs | 15 +- src/backend/producer/wayland.rs | 188 +++++++++++------- src/backend/producer/windows.rs | 12 +- src/backend/producer/x11.rs | 12 +- src/client.rs | 59 +++--- src/config.rs | 51 ++--- src/consumer.rs | 34 ++-- src/event.rs | 41 +++- src/frontend.rs | 53 ++--- src/frontend/cli.rs | 142 ++++++++------ src/frontend/gtk.rs | 46 +++-- src/frontend/gtk/client_object.rs | 10 +- src/frontend/gtk/client_row.rs | 28 ++- src/frontend/gtk/client_row/imp.rs | 17 +- src/frontend/gtk/window.rs | 23 ++- src/frontend/gtk/window/imp.rs | 18 +- src/ioutils.rs | 7 +- src/main.rs | 25 +-- src/producer.rs | 15 +- src/server.rs | 167 +++++++++++----- 26 files changed, 881 insertions(+), 497 deletions(-) diff --git a/src/backend/consumer.rs b/src/backend/consumer.rs index 7c03040..c5f2a47 100644 --- a/src/backend/consumer.rs +++ b/src/backend/consumer.rs @@ -1,7 +1,7 @@ #[cfg(windows)] pub mod windows; -#[cfg(all(unix, feature="x11"))] +#[cfg(all(unix, feature = "x11"))] pub mod x11; #[cfg(all(unix, feature = "wayland"))] diff --git a/src/backend/consumer/libei.rs b/src/backend/consumer/libei.rs index 6b9f0a9..b26e2bb 100644 --- a/src/backend/consumer/libei.rs +++ b/src/backend/consumer/libei.rs @@ -1,13 +1,29 @@ -use std::{os::{fd::{RawFd, FromRawFd}, unix::net::UnixStream}, collections::HashMap, time::{UNIX_EPOCH, SystemTime}, io}; +use std::{ + collections::HashMap, + io, + os::{ + fd::{FromRawFd, RawFd}, + unix::net::UnixStream, + }, + time::{SystemTime, UNIX_EPOCH}, +}; use anyhow::{anyhow, Result}; -use futures::StreamExt; -use ashpd::desktop::remote_desktop::{RemoteDesktop, DeviceType}; +use ashpd::desktop::remote_desktop::{DeviceType, RemoteDesktop}; use async_trait::async_trait; +use futures::StreamExt; -use reis::{ei::{self, handshake::ContextType, keyboard::KeyState, button::ButtonState}, tokio::EiEventStream, PendingRequestResult}; +use reis::{ + ei::{self, button::ButtonState, handshake::ContextType, keyboard::KeyState}, + tokio::EiEventStream, + PendingRequestResult, +}; -use crate::{consumer::EventConsumer, event::Event, client::{ClientHandle, ClientEvent}}; +use crate::{ + client::{ClientEvent, ClientHandle}, + consumer::EventConsumer, + event::Event, +}; pub struct LibeiConsumer { handshake: bool, @@ -32,10 +48,17 @@ async fn get_ei_fd() -> Result { let session = proxy.create_session().await?; // I HATE EVERYTHING, THIS TOOK 8 HOURS OF DEBUGGING - proxy.select_devices(&session, - DeviceType::Pointer | DeviceType::Keyboard |DeviceType::Touchscreen).await?; + proxy + .select_devices( + &session, + DeviceType::Pointer | DeviceType::Keyboard | DeviceType::Touchscreen, + ) + .await?; - proxy.start(&session, &ashpd::WindowIdentifier::default()).await?.response()?; + proxy + .start(&session, &ashpd::WindowIdentifier::default()) + .await? + .response()?; proxy.connect_to_eis(&session).await } @@ -59,7 +82,8 @@ impl LibeiConsumer { let events = EiEventStream::new(context.clone())?; return Ok(Self { handshake: false, - context, events, + context, + events, pointer: None, button: None, scroll: None, @@ -72,32 +96,59 @@ impl LibeiConsumer { capability_mask: 0, sequence: 0, serial: 0, - }) + }); } } #[async_trait] impl EventConsumer for LibeiConsumer { async fn consume(&mut self, event: Event, _client_handle: ClientHandle) { - let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_micros() as u64; + let now = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_micros() as u64; match event { Event::Pointer(p) => match p { - crate::event::PointerEvent::Motion { time:_, relative_x, relative_y } => { - if !self.has_pointer { return } + crate::event::PointerEvent::Motion { + time: _, + relative_x, + relative_y, + } => { + if !self.has_pointer { + return; + } if let Some((d, p)) = self.pointer.as_mut() { p.motion_relative(relative_x as f32, relative_y as f32); d.frame(self.serial, now); } - }, - crate::event::PointerEvent::Button { time: _, button, state } => { - if !self.has_button { return } + } + crate::event::PointerEvent::Button { + time: _, + button, + state, + } => { + if !self.has_button { + return; + } if let Some((d, b)) = self.button.as_mut() { - b.button(button, match state { 0 => ButtonState::Released, _ => ButtonState::Press }); + b.button( + button, + match state { + 0 => ButtonState::Released, + _ => ButtonState::Press, + }, + ); d.frame(self.serial, now); } - }, - crate::event::PointerEvent::Axis { time: _, axis, value } => { - if !self.has_scroll { return } + } + crate::event::PointerEvent::Axis { + time: _, + axis, + value, + } => { + if !self.has_scroll { + return; + } if let Some((d, s)) = self.scroll.as_mut() { match axis { 0 => s.scroll(0., value as f32), @@ -105,18 +156,30 @@ impl EventConsumer for LibeiConsumer { } d.frame(self.serial, now); } - }, - crate::event::PointerEvent::Frame { } => {}, + } + crate::event::PointerEvent::Frame {} => {} }, Event::Keyboard(k) => match k { - crate::event::KeyboardEvent::Key { time: _, key, state } => { - if !self.has_keyboard { return } + crate::event::KeyboardEvent::Key { + time: _, + key, + state, + } => { + if !self.has_keyboard { + return; + } if let Some((d, k)) = &mut self.keyboard { - k.key(key, match state { 0 => KeyState::Released, _ => KeyState::Press }); + k.key( + key, + match state { + 0 => KeyState::Released, + _ => KeyState::Press, + }, + ); d.frame(self.serial, now); } - }, - crate::event::KeyboardEvent::Modifiers { .. } => { }, + } + crate::event::KeyboardEvent::Modifiers { .. } => {} }, _ => {} } @@ -130,13 +193,17 @@ impl EventConsumer for LibeiConsumer { }; let event = match event { PendingRequestResult::Request(result) => result, - PendingRequestResult::ProtocolError(e) => return Err(anyhow!("libei protocol violation: {e}")), + PendingRequestResult::ProtocolError(e) => { + return Err(anyhow!("libei protocol violation: {e}")) + } PendingRequestResult::InvalidObject(e) => return Err(anyhow!("invalid object {e}")), }; match event { ei::Event::Handshake(handshake, request) => match request { ei::handshake::Event::HandshakeVersion { version } => { - if self.handshake { return Ok(()) } + if self.handshake { + return Ok(()); + } log::info!("libei version {}", version); // sender means we are sending events _to_ the eis server handshake.handshake_version(version); // FIXME @@ -163,8 +230,8 @@ impl EventConsumer for LibeiConsumer { connection.sync(1); self.serial = serial; } - _ => unreachable!() - } + _ => unreachable!(), + }, ei::Event::Connection(_connection, request) => match request { ei::connection::Event::Seat { seat } => { log::debug!("connected to seat: {seat:?}"); @@ -172,20 +239,45 @@ impl EventConsumer for LibeiConsumer { ei::connection::Event::Ping { ping } => { ping.done(0); } - ei::connection::Event::Disconnected { last_serial: _, reason, explanation } => { + ei::connection::Event::Disconnected { + last_serial: _, + reason, + explanation, + } => { log::debug!("ei - disconnected: reason: {reason:?}: {explanation}") } - ei::connection::Event::InvalidObject { last_serial, invalid_id } => { - return Err(anyhow!("invalid object: id: {invalid_id}, serial: {last_serial}")); + ei::connection::Event::InvalidObject { + last_serial, + invalid_id, + } => { + return Err(anyhow!( + "invalid object: id: {invalid_id}, serial: {last_serial}" + )); } - _ => unreachable!() - } + _ => unreachable!(), + }, ei::Event::Device(device, request) => match request { - ei::device::Event::Destroyed { serial } => { log::debug!("device destroyed: {device:?} - serial: {serial}") }, - ei::device::Event::Name { name } => {log::debug!("device name: {name}")}, - ei::device::Event::DeviceType { device_type } => log::debug!("device type: {device_type:?}"), - ei::device::Event::Dimensions { width, height } => log::debug!("device dimensions: {width}x{height}"), - ei::device::Event::Region { offset_x, offset_y, width, hight, scale } => log::debug!("device region: {width}x{hight} @ ({offset_x},{offset_y}), scale: {scale}"), + ei::device::Event::Destroyed { serial } => { + log::debug!("device destroyed: {device:?} - serial: {serial}") + } + ei::device::Event::Name { name } => { + log::debug!("device name: {name}") + } + ei::device::Event::DeviceType { device_type } => { + log::debug!("device type: {device_type:?}") + } + ei::device::Event::Dimensions { width, height } => { + log::debug!("device dimensions: {width}x{height}") + } + ei::device::Event::Region { + offset_x, + offset_y, + width, + hight, + scale, + } => log::debug!( + "device region: {width}x{hight} @ ({offset_x},{offset_y}), scale: {scale}" + ), ei::device::Event::Interface { object } => { log::debug!("device interface: {object:?}"); if object.interface().eq("ei_pointer") { @@ -204,31 +296,31 @@ impl EventConsumer for LibeiConsumer { } ei::device::Event::Done => { log::debug!("device: done {device:?}"); - }, + } ei::device::Event::Resumed { serial } => { self.serial = serial; device.start_emulating(serial, self.sequence); self.sequence += 1; log::debug!("resumed: {device:?}"); - if let Some((d,_)) = &mut self.pointer { + if let Some((d, _)) = &mut self.pointer { if d == &device { log::debug!("pointer resumed {serial}"); self.has_pointer = true; } } - if let Some((d,_)) = &mut self.button { + if let Some((d, _)) = &mut self.button { if d == &device { log::debug!("button resumed {serial}"); self.has_button = true; } } - if let Some((d,_)) = &mut self.scroll { + if let Some((d, _)) = &mut self.scroll { if d == &device { log::debug!("scroll resumed {serial}"); self.has_scroll = true; } } - if let Some((d,_)) = &mut self.keyboard { + if let Some((d, _)) = &mut self.keyboard { if d == &device { log::debug!("keyboard resumed {serial}"); self.has_keyboard = true; @@ -239,38 +331,44 @@ impl EventConsumer for LibeiConsumer { self.has_pointer = false; self.has_button = false; self.serial = serial; - }, - ei::device::Event::StartEmulating { serial, sequence } => log::debug!("start emulating {serial}, {sequence}"), - ei::device::Event::StopEmulating { serial } => log::debug!("stop emulating {serial}"), + } + ei::device::Event::StartEmulating { serial, sequence } => { + log::debug!("start emulating {serial}, {sequence}") + } + ei::device::Event::StopEmulating { serial } => { + log::debug!("stop emulating {serial}") + } ei::device::Event::Frame { serial, timestamp } => { log::debug!("frame: {serial}, {timestamp}"); } - ei::device::Event::RegionMappingId { mapping_id } => log::debug!("RegionMappingId {mapping_id}"), + ei::device::Event::RegionMappingId { mapping_id } => { + log::debug!("RegionMappingId {mapping_id}") + } e => log::debug!("invalid event: {e:?}"), - } + }, ei::Event::Seat(seat, request) => match request { ei::seat::Event::Destroyed { serial } => { self.serial = serial; log::debug!("seat destroyed: {seat:?}"); - }, + } ei::seat::Event::Name { name } => { log::debug!("seat name: {name}"); - }, + } ei::seat::Event::Capability { mask, interface } => { log::debug!("seat capabilities: {mask}, interface: {interface:?}"); self.capabilities.insert(interface, mask); self.capability_mask |= mask; - }, + } ei::seat::Event::Done => { log::debug!("seat done"); log::debug!("binding capabilities: {}", self.capability_mask); seat.bind(self.capability_mask); - }, + } ei::seat::Event::Device { device } => { log::debug!("seat: new device - {device:?}"); - }, + } _ => todo!(), - } + }, e => log::debug!("unhandled event: {e:?}"), } self.context.flush()?; @@ -281,4 +379,3 @@ impl EventConsumer for LibeiConsumer { async fn destroy(&mut self) {} } - diff --git a/src/backend/consumer/windows.rs b/src/backend/consumer/windows.rs index f69f113..a664943 100644 --- a/src/backend/consumer/windows.rs +++ b/src/backend/consumer/windows.rs @@ -1,16 +1,15 @@ +use crate::{ + consumer::EventConsumer, + event::{KeyboardEvent, PointerEvent}, +}; use async_trait::async_trait; -use crate::{event::{KeyboardEvent, PointerEvent}, consumer::EventConsumer}; use winapi::{ self, - um::winuser::{INPUT, INPUT_MOUSE, LPINPUT, MOUSEEVENTF_MOVE, MOUSEINPUT, - MOUSEEVENTF_LEFTDOWN, - MOUSEEVENTF_RIGHTDOWN, - MOUSEEVENTF_MIDDLEDOWN, - MOUSEEVENTF_LEFTUP, - MOUSEEVENTF_RIGHTUP, - MOUSEEVENTF_MIDDLEUP, - MOUSEEVENTF_WHEEL, - MOUSEEVENTF_HWHEEL, INPUT_KEYBOARD, KEYBDINPUT, KEYEVENTF_SCANCODE, KEYEVENTF_KEYUP, + um::winuser::{ + INPUT, INPUT_KEYBOARD, INPUT_MOUSE, KEYBDINPUT, KEYEVENTF_KEYUP, KEYEVENTF_SCANCODE, + LPINPUT, MOUSEEVENTF_HWHEEL, MOUSEEVENTF_LEFTDOWN, MOUSEEVENTF_LEFTUP, + MOUSEEVENTF_MIDDLEDOWN, MOUSEEVENTF_MIDDLEUP, MOUSEEVENTF_MOVE, MOUSEEVENTF_RIGHTDOWN, + MOUSEEVENTF_RIGHTUP, MOUSEEVENTF_WHEEL, MOUSEINPUT, }, }; @@ -19,11 +18,12 @@ use crate::{ event::Event, }; - pub struct WindowsConsumer {} impl WindowsConsumer { - pub fn new() -> Self { Self { } } + pub fn new() -> Self { + Self {} + } } #[async_trait] @@ -38,12 +38,24 @@ impl EventConsumer for WindowsConsumer { } => { rel_mouse(relative_x as i32, relative_y as i32); } - PointerEvent::Button { time:_, button, state } => { mouse_button(button, state)} - PointerEvent::Axis { time:_, axis, value } => { scroll(axis, value) } + PointerEvent::Button { + time: _, + button, + state, + } => mouse_button(button, state), + PointerEvent::Axis { + time: _, + axis, + value, + } => scroll(axis, value), PointerEvent::Frame {} => {} }, Event::Keyboard(keyboard_event) => match keyboard_event { - KeyboardEvent::Key { time:_, key, state } => { key_event(key, state) } + KeyboardEvent::Key { + time: _, + key, + state, + } => key_event(key, state), KeyboardEvent::Modifiers { .. } => {} }, _ => {} @@ -53,7 +65,7 @@ impl EventConsumer for WindowsConsumer { async fn notify(&mut self, _: ClientEvent) { // nothing to do } - + async fn destroy(&mut self) {} } @@ -90,18 +102,19 @@ fn mouse_button(button: u32, state: u32) { 0x110 => MOUSEEVENTF_LEFTUP, 0x111 => MOUSEEVENTF_RIGHTUP, 0x112 => MOUSEEVENTF_MIDDLEUP, - _ => return - } + _ => return, + }, 1 => match button { 0x110 => MOUSEEVENTF_LEFTDOWN, 0x111 => MOUSEEVENTF_RIGHTDOWN, 0x112 => MOUSEEVENTF_MIDDLEDOWN, - _ => return - } - _ => return + _ => return, + }, + _ => return, }; let mi = MOUSEINPUT { - dx: 0, dy: 0, // no movement + dx: 0, + dy: 0, // no movement mouseData: 0, dwFlags: dw_flags, time: 0, @@ -114,10 +127,11 @@ fn scroll(axis: u8, value: f64) { let event_type = match axis { 0 => MOUSEEVENTF_WHEEL, 1 => MOUSEEVENTF_HWHEEL, - _ => return + _ => return, }; let mi = MOUSEINPUT { - dx: 0, dy: 0, + dx: 0, + dy: 0, mouseData: (-value * 15.0) as i32 as u32, dwFlags: event_type, time: 0, @@ -130,11 +144,12 @@ fn key_event(key: u32, state: u8) { let ki = KEYBDINPUT { wVk: 0, wScan: key as u16, - dwFlags: KEYEVENTF_SCANCODE | match state { - 0 => KEYEVENTF_KEYUP, - 1 => 0u32, - _ => return - }, + dwFlags: KEYEVENTF_SCANCODE + | match state { + 0 => KEYEVENTF_KEYUP, + 1 => 0u32, + _ => return, + }, time: 0, dwExtraInfo: 0, }; diff --git a/src/backend/consumer/wlroots.rs b/src/backend/consumer/wlroots.rs index bdd5ace..6b042d9 100644 --- a/src/backend/consumer/wlroots.rs +++ b/src/backend/consumer/wlroots.rs @@ -1,17 +1,17 @@ -use async_trait::async_trait; -use wayland_client::WEnum; -use wayland_client::backend::WaylandError; -use crate::client::{ClientHandle, ClientEvent}; +use crate::client::{ClientEvent, ClientHandle}; use crate::consumer::EventConsumer; +use async_trait::async_trait; use std::collections::HashMap; use std::io; use std::os::fd::OwnedFd; use std::os::unix::prelude::AsRawFd; +use wayland_client::backend::WaylandError; +use wayland_client::WEnum; -use anyhow::{Result, anyhow}; +use anyhow::{anyhow, Result}; use wayland_client::globals::BindError; -use wayland_client::protocol::wl_pointer::{Axis, ButtonState}; use wayland_client::protocol::wl_keyboard::{self, WlKeyboard}; +use wayland_client::protocol::wl_pointer::{Axis, ButtonState}; use wayland_client::protocol::wl_seat::WlSeat; use wayland_protocols_wlr::virtual_pointer::v1::client::{ zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager, @@ -104,7 +104,10 @@ impl WlrootsConsumer { queue, }; while consumer.state.keymap.is_none() { - consumer.queue.blocking_dispatch(&mut consumer.state).unwrap(); + consumer + .queue + .blocking_dispatch(&mut consumer.state) + .unwrap(); } // let fd = unsafe { &File::from_raw_fd(consumer.state.keymap.unwrap().1.as_raw_fd()) }; // let mmap = unsafe { MmapOptions::new().map_copy(fd).unwrap() }; @@ -153,8 +156,10 @@ impl EventConsumer for WlrootsConsumer { * will overwhelm the output buffer and leave the * wayland connection in a broken state */ - log::warn!("can't keep up, discarding event: ({client_handle}) - {event:?}"); - return + log::warn!( + "can't keep up, discarding event: ({client_handle}) - {event:?}" + ); + return; } } } @@ -166,13 +171,13 @@ impl EventConsumer for WlrootsConsumer { } Err(WaylandError::Io(e)) => { log::error!("{e}") - }, + } Err(WaylandError::Protocol(e)) => { panic!("wayland protocol violation: {e}") } Ok(()) => { self.last_flush_failed = false; - }, + } } } } @@ -186,17 +191,16 @@ impl EventConsumer for WlrootsConsumer { } } - async fn destroy(&mut self) { } + async fn destroy(&mut self) {} } - enum VirtualInput { Wlroots { pointer: Vp, keyboard: Vk }, Kde { fake_input: OrgKdeKwinFakeInput }, } impl VirtualInput { - fn consume_event(&self, event: Event) -> Result<(),()> { + fn consume_event(&self, event: Event) -> Result<(), ()> { match event { Event::Pointer(e) => { match e { @@ -263,9 +267,9 @@ impl VirtualInput { // insert a frame event after each mouse event pointer.frame(); } - _ => {}, + _ => {} } - }, + } Event::Keyboard(e) => match e { KeyboardEvent::Key { time, key, state } => match self { VirtualInput::Wlroots { @@ -293,7 +297,7 @@ impl VirtualInput { VirtualInput::Kde { fake_input: _ } => {} }, }, - _ => {}, + _ => {} } Ok(()) } @@ -330,7 +334,7 @@ impl Dispatch for State { wl_keyboard::Event::Keymap { format, fd, size } => { state.keymap = Some((u32::from(format), fd, size)); } - _ => {}, + _ => {} } } } diff --git a/src/backend/consumer/x11.rs b/src/backend/consumer/x11.rs index 7b5482c..e22a44e 100644 --- a/src/backend/consumer/x11.rs +++ b/src/backend/consumer/x11.rs @@ -1,11 +1,8 @@ -use std::ptr; use async_trait::async_trait; +use std::ptr; use x11::{xlib, xtest}; -use crate::{ - client::ClientHandle, - event::Event, consumer::EventConsumer, -}; +use crate::{client::ClientHandle, consumer::EventConsumer, event::Event}; pub struct X11Consumer { display: *mut xlib::Display, @@ -60,4 +57,3 @@ impl EventConsumer for X11Consumer { async fn destroy(&mut self) {} } - diff --git a/src/backend/consumer/xdg_desktop_portal.rs b/src/backend/consumer/xdg_desktop_portal.rs index ea47173..92f302a 100644 --- a/src/backend/consumer/xdg_desktop_portal.rs +++ b/src/backend/consumer/xdg_desktop_portal.rs @@ -1,6 +1,12 @@ -use async_trait::async_trait; use anyhow::Result; -use ashpd::{desktop::{remote_desktop::{RemoteDesktop, DeviceType, KeyState, Axis}, Session}, WindowIdentifier}; +use ashpd::{ + desktop::{ + remote_desktop::{Axis, DeviceType, KeyState, RemoteDesktop}, + Session, + }, + WindowIdentifier, +}; +use async_trait::async_trait; use crate::consumer::EventConsumer; @@ -32,55 +38,86 @@ impl<'a> EventConsumer for DesktopPortalConsumer<'a> { match event { crate::event::Event::Pointer(p) => { match p { - crate::event::PointerEvent::Motion { time: _, relative_x, relative_y } => { - if let Err(e) = self.proxy.notify_pointer_motion(&self.session, relative_x, relative_y).await { + crate::event::PointerEvent::Motion { + time: _, + relative_x, + relative_y, + } => { + if let Err(e) = self + .proxy + .notify_pointer_motion(&self.session, relative_x, relative_y) + .await + { log::warn!("{e}"); } - }, - crate::event::PointerEvent::Button { time: _, button, state } => { + } + crate::event::PointerEvent::Button { + time: _, + button, + state, + } => { let state = match state { 0 => KeyState::Released, _ => KeyState::Pressed, }; - if let Err(e) = self.proxy.notify_pointer_button(&self.session, button as i32, state).await { + if let Err(e) = self + .proxy + .notify_pointer_button(&self.session, button as i32, state) + .await + { log::warn!("{e}"); } - }, - crate::event::PointerEvent::Axis { time: _, axis, value } => { + } + crate::event::PointerEvent::Axis { + time: _, + axis, + value, + } => { let axis = match axis { 0 => Axis::Vertical, _ => Axis::Horizontal, }; // TODO smooth scrolling - if let Err(e) = self.proxy.notify_pointer_axis_discrete(&self.session, axis, value as i32).await { + if let Err(e) = self + .proxy + .notify_pointer_axis_discrete(&self.session, axis, value as i32) + .await + { log::warn!("{e}"); } - - }, - crate::event::PointerEvent::Frame { } => {}, + } + crate::event::PointerEvent::Frame {} => {} } - }, + } crate::event::Event::Keyboard(k) => { match k { - crate::event::KeyboardEvent::Key { time: _, key, state } => { + crate::event::KeyboardEvent::Key { + time: _, + key, + state, + } => { let state = match state { 0 => KeyState::Released, _ => KeyState::Pressed, }; - if let Err(e) = self.proxy.notify_keyboard_keycode(&self.session, key as i32, state).await { + if let Err(e) = self + .proxy + .notify_keyboard_keycode(&self.session, key as i32, state) + .await + { log::warn!("{e}"); } - }, + } crate::event::KeyboardEvent::Modifiers { .. } => { // ignore - }, + } } - }, - _ => {}, + } + _ => {} } } - async fn notify(&mut self, _client: crate::client::ClientEvent) { } + async fn notify(&mut self, _client: crate::client::ClientEvent) {} async fn destroy(&mut self) { log::debug!("closing remote desktop session"); diff --git a/src/backend/producer/libei.rs b/src/backend/producer/libei.rs index 8511d2f..060eca3 100644 --- a/src/backend/producer/libei.rs +++ b/src/backend/producer/libei.rs @@ -3,28 +3,29 @@ use std::{io, task::Poll}; use futures_core::Stream; -use crate::{producer::EventProducer, event::Event, client::ClientHandle}; +use crate::{client::ClientHandle, event::Event, producer::EventProducer}; pub struct LibeiProducer {} impl LibeiProducer { pub fn new() -> Result { - Ok(Self { }) + Ok(Self {}) } } impl EventProducer for LibeiProducer { - fn notify(&mut self, _event: crate::client::ClientEvent) { - } + fn notify(&mut self, _event: crate::client::ClientEvent) {} - fn release(&mut self) { - } + fn release(&mut self) {} } impl Stream for LibeiProducer { type Item = io::Result<(ClientHandle, Event)>; - fn poll_next(self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> std::task::Poll> { + fn poll_next( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { Poll::Pending } } diff --git a/src/backend/producer/wayland.rs b/src/backend/producer/wayland.rs index 04155a3..65c62d9 100644 --- a/src/backend/producer/wayland.rs +++ b/src/backend/producer/wayland.rs @@ -1,9 +1,19 @@ -use crate::{client::{ClientHandle, Position, ClientEvent}, producer::EventProducer}; +use crate::{ + client::{ClientEvent, ClientHandle, Position}, + producer::EventProducer, +}; -use std::{os::fd::{OwnedFd, RawFd}, io::{ErrorKind, self}, env, pin::Pin, task::{Context, Poll, ready}, collections::VecDeque}; +use anyhow::{anyhow, Result}; use futures_core::Stream; use memmap::MmapOptions; -use anyhow::{anyhow, Result}; +use std::{ + collections::VecDeque, + env, + io::{self, ErrorKind}, + os::fd::{OwnedFd, RawFd}, + pin::Pin, + task::{ready, Context, Poll}, +}; use tokio::io::unix::AsyncFd; use std::{ @@ -13,20 +23,26 @@ use std::{ rc::Rc, }; -use wayland_protocols::{wp::{ - keyboard_shortcuts_inhibit::zv1::client::{ - zwp_keyboard_shortcuts_inhibit_manager_v1::ZwpKeyboardShortcutsInhibitManagerV1, - zwp_keyboard_shortcuts_inhibitor_v1::ZwpKeyboardShortcutsInhibitorV1, +use wayland_protocols::{ + wp::{ + keyboard_shortcuts_inhibit::zv1::client::{ + zwp_keyboard_shortcuts_inhibit_manager_v1::ZwpKeyboardShortcutsInhibitManagerV1, + zwp_keyboard_shortcuts_inhibitor_v1::ZwpKeyboardShortcutsInhibitorV1, + }, + pointer_constraints::zv1::client::{ + zwp_locked_pointer_v1::ZwpLockedPointerV1, + zwp_pointer_constraints_v1::{Lifetime, ZwpPointerConstraintsV1}, + }, + relative_pointer::zv1::client::{ + zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, + zwp_relative_pointer_v1::{self, ZwpRelativePointerV1}, + }, }, - pointer_constraints::zv1::client::{ - zwp_locked_pointer_v1::ZwpLockedPointerV1, - zwp_pointer_constraints_v1::{Lifetime, ZwpPointerConstraintsV1}, + xdg::xdg_output::zv1::client::{ + zxdg_output_manager_v1::ZxdgOutputManagerV1, + zxdg_output_v1::{self, ZxdgOutputV1}, }, - relative_pointer::zv1::client::{ - zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1, - zwp_relative_pointer_v1::{self, ZwpRelativePointerV1}, - }, -}, xdg::xdg_output::zv1::client::{zxdg_output_manager_v1::ZxdgOutputManagerV1, zxdg_output_v1::{self, ZxdgOutputV1}}}; +}; use wayland_protocols_wlr::layer_shell::v1::client::{ zwlr_layer_shell_v1::{Layer, ZwlrLayerShellV1}, @@ -34,14 +50,15 @@ use wayland_protocols_wlr::layer_shell::v1::client::{ }; use wayland_client::{ - backend::{WaylandError, ReadEventsGuard}, + backend::{ReadEventsGuard, WaylandError}, delegate_noop, globals::{registry_queue_init, GlobalListContents}, protocol::{ - wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_region, wl_registry, wl_seat, wl_shm, - wl_shm_pool, wl_surface, wl_output::{self, WlOutput}, + wl_buffer, wl_compositor, wl_keyboard, + wl_output::{self, WlOutput}, + wl_pointer, wl_region, wl_registry, wl_seat, wl_shm, wl_shm_pool, wl_surface, }, - Connection, Dispatch, DispatchError, QueueHandle, WEnum, EventQueue, + Connection, Dispatch, DispatchError, EventQueue, QueueHandle, WEnum, }; use tempfile; @@ -71,8 +88,8 @@ impl OutputInfo { fn new() -> Self { Self { name: "".to_string(), - position: (0,0), - size: (0,0), + position: (0, 0), + size: (0, 0), } } } @@ -111,7 +128,13 @@ struct Window { } impl Window { - fn new(state: &State, qh: &QueueHandle, output: &WlOutput, pos: Position, size: (i32, i32)) -> Window { + fn new( + state: &State, + qh: &QueueHandle, + output: &WlOutput, + pos: Position, + size: (i32, i32), + ) -> Window { let g = &state.g; let (width, height) = match pos { @@ -152,7 +175,7 @@ impl Window { layer_surface.set_anchor(anchor); layer_surface.set_size(width, height); layer_surface.set_exclusive_zone(-1); - layer_surface.set_margin(0,0,0,0); + layer_surface.set_margin(0, 0, 0, 0); surface.set_input_region(None); surface.commit(); Window { @@ -173,15 +196,20 @@ impl Drop for Window { } fn get_edges(outputs: &[(WlOutput, OutputInfo)], pos: Position) -> Vec<(WlOutput, i32)> { - outputs.iter().map(|(o, i)| { - (o.clone(), - match pos { - Position::Left => i.position.0, - Position::Right => i.position.0 + i.size.0, - Position::Top => i.position.1, - Position::Bottom => i.position.1 + i.size.1, + outputs + .iter() + .map(|(o, i)| { + ( + o.clone(), + match pos { + Position::Left => i.position.0, + Position::Right => i.position.0 + i.size.0, + Position::Top => i.position.1, + Position::Bottom => i.position.1 + i.size.1, + }, + ) }) - }).collect() + .collect() } fn get_output_configuration(state: &State, pos: Position) -> Vec<(WlOutput, OutputInfo)> { @@ -191,12 +219,21 @@ fn get_output_configuration(state: &State, pos: Position) -> Vec<(WlOutput, Outp // remove those edges that are at the same position // as an opposite edge of a different output - let outputs: Vec = edges.iter().filter(|(_,edge)| { - opposite_edges.iter().map(|(_,e)| *e).find(|e| e == edge).is_none() - }).map(|(o,_)| o.clone()).collect(); - state.output_info + let outputs: Vec = edges .iter() - .filter(|(o,_)| outputs.contains(o)) + .filter(|(_, edge)| { + opposite_edges + .iter() + .map(|(_, e)| *e) + .find(|e| e == edge) + .is_none() + }) + .map(|(o, _)| o.clone()) + .collect(); + state + .output_info + .iter() + .filter(|(o, _)| outputs.contains(o)) .map(|(o, i)| (o.clone(), i.clone())) .collect() } @@ -265,10 +302,15 @@ impl WaylandEventProducer { Err(_) => return Err(anyhow!("zwp_relative_pointer_manager_v1 not supported")), }; - let shortcut_inhibit_manager: ZwpKeyboardShortcutsInhibitManagerV1 = match g.bind(&qh, 1..=1, ()) { - Ok(shortcut_inhibit_manager) => shortcut_inhibit_manager, - Err(_) => return Err(anyhow!("zwp_keyboard_shortcuts_inhibit_manager_v1 not supported")), - }; + let shortcut_inhibit_manager: ZwpKeyboardShortcutsInhibitManagerV1 = + match g.bind(&qh, 1..=1, ()) { + Ok(shortcut_inhibit_manager) => shortcut_inhibit_manager, + Err(_) => { + return Err(anyhow!( + "zwp_keyboard_shortcuts_inhibit_manager_v1 not supported" + )) + } + }; let outputs = vec![]; @@ -316,7 +358,10 @@ impl WaylandEventProducer { // read outputs for output in state.g.outputs.iter() { - state.g.xdg_output_manager.get_xdg_output(output, &state.qh, output.clone()); + state + .g + .xdg_output_manager + .get_xdg_output(output, &state.qh, output.clone()); } // roundtrip to read xdg_output events @@ -420,7 +465,6 @@ impl State { } fn add_client(&mut self, client: ClientHandle, pos: Position) { - let outputs = get_output_configuration(self, pos); outputs.iter().for_each(|(o, i)| { @@ -428,7 +472,6 @@ impl State { let window = Rc::new(window); self.client_for_window.push((window, client)); }); - } } @@ -485,17 +528,16 @@ impl Inner { Err(e) => match e { WaylandError::Io(e) => { log::error!("error writing to wayland socket: {e}") - }, + } WaylandError::Protocol(e) => { panic!("wayland protocol violation: {e}") - }, + } }, } } } impl EventProducer for WaylandEventProducer { - fn notify(&mut self, client_event: ClientEvent) { match client_event { ClientEvent::Create(handle, pos) => { @@ -509,11 +551,12 @@ impl EventProducer for WaylandEventProducer { .state .client_for_window .iter() - .position(|(_,c)| *c == handle) { + .position(|(_, c)| *c == handle) + { inner.state.client_for_window.remove(i); inner.state.focused = None; } else { - break + break; } } } @@ -605,7 +648,6 @@ impl Dispatch for State { _: &Connection, qh: &QueueHandle, ) { - match event { wl_pointer::Event::Enter { serial, @@ -618,7 +660,8 @@ impl Dispatch for State { if let Some((window, client)) = app .client_for_window .iter() - .find(|(w, _c)| w.surface == surface) { + .find(|(w, _c)| w.surface == surface) + { app.focused = Some((window.clone(), *client)); app.grab(&surface, pointer, serial.clone(), qh); } else { @@ -786,7 +829,8 @@ impl Dispatch for State { if let Some((window, _client)) = app .client_for_window .iter() - .find(|(w, _c)| &w.layer_surface == layer_surface) { + .find(|(w, _c)| &w.layer_surface == layer_surface) + { // client corresponding to the layer_surface let surface = &window.surface; let buffer = &window.buffer; @@ -821,17 +865,22 @@ impl Dispatch for State { qh: &QueueHandle, ) { match event { - wl_registry::Event::Global { name, interface, version: _ } => { - match interface.as_str() { - "wl_output" => { - log::debug!("wl_output global"); - state.g.outputs.push(registry.bind::(name, 4, qh, ())) - } - _ => {} + wl_registry::Event::Global { + name, + interface, + version: _, + } => match interface.as_str() { + "wl_output" => { + log::debug!("wl_output global"); + state + .g + .outputs + .push(registry.bind::(name, 4, qh, ())) } + _ => {} }, - wl_registry::Event::GlobalRemove { .. } => {}, - _ => {}, + wl_registry::Event::GlobalRemove { .. } => {} + _ => {} } } } @@ -846,11 +895,8 @@ impl Dispatch for State { _: &QueueHandle, ) { log::debug!("xdg-output - {event:?}"); - let output_info = match state - .output_info - .iter_mut() - .find(|(o, _)| o == wl_output) { - Some((_,c)) => c, + let output_info = match state.output_info.iter_mut().find(|(o, _)| o == wl_output) { + Some((_, c)) => c, None => { let output_info = OutputInfo::new(); state.output_info.push((wl_output.clone(), output_info)); @@ -861,16 +907,16 @@ impl Dispatch for State { match event { zxdg_output_v1::Event::LogicalPosition { x, y } => { output_info.position = (x, y); - }, + } zxdg_output_v1::Event::LogicalSize { width, height } => { output_info.size = (width, height); - }, - zxdg_output_v1::Event::Done => {}, + } + zxdg_output_v1::Event::Done => {} zxdg_output_v1::Event::Name { name } => { output_info.name = name; - }, - zxdg_output_v1::Event::Description { .. } => {}, - _ => {}, + } + zxdg_output_v1::Event::Description { .. } => {} + _ => {} } } } diff --git a/src/backend/producer/windows.rs b/src/backend/producer/windows.rs index 6d3cac8..998572b 100644 --- a/src/backend/producer/windows.rs +++ b/src/backend/producer/windows.rs @@ -1,20 +1,20 @@ +use core::task::{Context, Poll}; +use futures::Stream; use std::io::Result; use std::pin::Pin; -use futures::Stream; -use core::task::{Context, Poll}; use crate::{ - client::{ClientHandle, ClientEvent}, + client::{ClientEvent, ClientHandle}, event::Event, producer::EventProducer, }; -pub struct WindowsProducer { } +pub struct WindowsProducer {} impl EventProducer for WindowsProducer { - fn notify(&mut self, _: ClientEvent) { } + fn notify(&mut self, _: ClientEvent) {} - fn release(&mut self) { } + fn release(&mut self) {} } impl WindowsProducer { diff --git a/src/backend/producer/x11.rs b/src/backend/producer/x11.rs index 6de4382..7b775f7 100644 --- a/src/backend/producer/x11.rs +++ b/src/backend/producer/x11.rs @@ -1,7 +1,6 @@ use std::io; use std::task::Poll; - use futures_core::Stream; use crate::event::Event; @@ -9,16 +8,16 @@ use crate::producer::EventProducer; use crate::client::{ClientEvent, ClientHandle}; -pub struct X11Producer { } +pub struct X11Producer {} impl X11Producer { pub fn new() -> Self { - Self { } + Self {} } } impl EventProducer for X11Producer { - fn notify(&mut self, _: ClientEvent) { } + fn notify(&mut self, _: ClientEvent) {} fn release(&mut self) {} } @@ -26,7 +25,10 @@ impl EventProducer for X11Producer { impl Stream for X11Producer { type Item = io::Result<(ClientHandle, Event)>; - fn poll_next(self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> std::task::Poll> { + fn poll_next( + self: std::pin::Pin<&mut Self>, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { Poll::Pending } } diff --git a/src/client.rs b/src/client.rs index a2a90ee..7007af2 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,6 +1,11 @@ -use std::{net::{SocketAddr, IpAddr}, collections::HashSet, fmt::Display, time::Instant}; +use std::{ + collections::HashSet, + fmt::Display, + net::{IpAddr, SocketAddr}, + time::Instant, +}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Eq, Hash, PartialEq, Clone, Copy, Serialize, Deserialize)] pub enum Position { @@ -29,12 +34,16 @@ impl Position { impl Display for Position { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - Position::Left => "left", - Position::Right => "right", - Position::Top => "top", - Position::Bottom => "bottom", - }) + write!( + f, + "{}", + match self { + Position::Left => "left", + Position::Right => "right", + Position::Top => "top", + Position::Bottom => "bottom", + } + ) } } @@ -82,9 +91,7 @@ pub struct ClientManager { impl ClientManager { pub fn new() -> Self { - Self { - clients: vec![], - } + Self { clients: vec![] } } /// add a new client to this manager @@ -102,14 +109,17 @@ impl ClientManager { let active_addr = None; // map ip addresses to socket addresses - let addrs = HashSet::from_iter( - addrs - .into_iter() - .map(|ip| SocketAddr::new(ip, port)) - ); + let addrs = HashSet::from_iter(addrs.into_iter().map(|ip| SocketAddr::new(ip, port))); // store the client - let client = Client { hostname, handle, active_addr, addrs, port, pos }; + let client = Client { + hostname, + handle, + active_addr, + addrs, + port, + pos, + }; // client was never seen, nor pinged let client_state = ClientState { @@ -135,10 +145,12 @@ impl ClientManager { // time this is likely faster than using a HashMap self.clients .iter() - .position(|c| if let Some(c) = c { - c.active && c.client.addrs.contains(&addr) - } else { - false + .position(|c| { + if let Some(c) = c { + c.active && c.client.addrs.contains(&addr) + } else { + false + } }) .map(|p| p as ClientHandle) } @@ -153,7 +165,8 @@ impl ClientManager { fn free_id(&mut self) -> ClientHandle { for i in 0..u32::MAX { if self.clients.get(i as usize).is_none() - || self.clients.get(i as usize).unwrap().is_none() { + || self.clients.get(i as usize).unwrap().is_none() + { return i; } } @@ -173,7 +186,7 @@ impl ClientManager { pub fn enumerate(&self) -> Vec<(Client, bool)> { self.clients .iter() - .filter_map(|s|s.as_ref()) + .filter_map(|s| s.as_ref()) .map(|s| (s.client.clone(), s.active)) .collect() } diff --git a/src/config.rs b/src/config.rs index 27365a7..767a133 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,11 +1,11 @@ use anyhow::Result; +use clap::Parser; use serde::{Deserialize, Serialize}; use std::collections::HashSet; +use std::env; use std::net::IpAddr; use std::{error::Error, fs}; -use std::env; use toml; -use clap::Parser; use crate::client::Position; @@ -74,15 +74,17 @@ impl Config { pub fn new() -> Result { let args = CliArgs::parse(); let config_file = "config.toml"; - #[cfg(unix)] let config_path = { - let xdg_config_home = env::var("XDG_CONFIG_HOME") - .unwrap_or(format!("{}/.config", env::var("HOME")?)); + #[cfg(unix)] + let config_path = { + let xdg_config_home = + env::var("XDG_CONFIG_HOME").unwrap_or(format!("{}/.config", env::var("HOME")?)); format!("{xdg_config_home}/lan-mouse/{config_file}") }; - #[cfg(not(unix))] let config_path = { - let app_data = env::var("LOCALAPPDATA") - .unwrap_or(format!("{}/.config", env::var("USERPROFILE")?)); + #[cfg(not(unix))] + let config_path = { + let app_data = + env::var("LOCALAPPDATA").unwrap_or(format!("{}/.config", env::var("USERPROFILE")?)); format!("{app_data}\\lan-mouse\\{config_file}") }; @@ -94,7 +96,7 @@ impl Config { log::error!("{config_path}: {e}"); log::warn!("Continuing without config file ..."); None - }, + } Ok(c) => Some(c), }; @@ -114,8 +116,8 @@ impl Config { Some(s) => match s.as_str() { "cli" => Frontend::Cli, "gtk" => Frontend::Gtk, - _ => Frontend::Cli, - } + _ => Frontend::Cli, + }, }; let port = match args.port { @@ -123,7 +125,7 @@ impl Config { None => match &config_toml { Some(c) => c.port.unwrap_or(DEFAULT_PORT), None => DEFAULT_PORT, - } + }, }; let mut clients: Vec<(Client, Position)> = vec![]; @@ -153,16 +155,19 @@ impl Config { }) } - pub fn get_clients(&self) -> Vec<(HashSet, Option, u16, Position)> { - self.clients.iter().map(|(c,p)| { - let port = c.port.unwrap_or(DEFAULT_PORT); - let ips: HashSet = if let Some(ips) = c.ips.as_ref() { - HashSet::from_iter(ips.iter().cloned()) - } else { - HashSet::new() - }; - let host_name = c.host_name.clone(); - (ips, host_name, port, *p) - }).collect() + pub fn get_clients(&self) -> Vec<(HashSet, Option, u16, Position)> { + self.clients + .iter() + .map(|(c, p)| { + let port = c.port.unwrap_or(DEFAULT_PORT); + let ips: HashSet = if let Some(ips) = c.ips.as_ref() { + HashSet::from_iter(ips.iter().cloned()) + } else { + HashSet::new() + }; + let host_name = c.host_name.clone(); + (ips, host_name, port, *p) + }) + .collect() } } diff --git a/src/consumer.rs b/src/consumer.rs index eafb938..3bb28fe 100644 --- a/src/consumer.rs +++ b/src/consumer.rs @@ -1,11 +1,15 @@ -use std::future; use async_trait::async_trait; +use std::future; #[cfg(unix)] use std::env; +use crate::{ + backend::consumer, + client::{ClientEvent, ClientHandle}, + event::Event, +}; use anyhow::Result; -use crate::{backend::consumer, client::{ClientHandle, ClientEvent}, event::Event}; #[cfg(unix)] #[derive(Debug)] @@ -49,7 +53,9 @@ pub async fn create() -> Result> { Backend::Libei } "KDE" => { - log::info!("XDG_CURRENT_DESKTOP = KDE -> using xdg_desktop_portal backend"); + log::info!( + "XDG_CURRENT_DESKTOP = KDE -> using xdg_desktop_portal backend" + ); Backend::RemoteDesktopPortal } "sway" => { @@ -61,10 +67,12 @@ pub async fn create() -> Result> { Backend::Wlroots } _ => { - log::warn!("unknown XDG_CURRENT_DESKTOP -> defaulting to wlroots backend"); + 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"); @@ -74,7 +82,9 @@ pub async fn create() -> Result> { } _ => panic!("unknown XDG_SESSION_TYPE"), }, - Err(_) => panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!"), + Err(_) => { + panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!") + } }; #[cfg(unix)] @@ -84,24 +94,26 @@ pub async fn create() -> Result> { panic!("feature libei not enabled"); #[cfg(feature = "libei")] Ok(Box::new(consumer::libei::LibeiConsumer::new().await?)) - }, + } 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?)) - }, + Ok(Box::new( + consumer::xdg_desktop_portal::DesktopPortalConsumer::new().await?, + )) + } Backend::Wlroots => { #[cfg(not(feature = "wayland"))] panic!("feature wayland not enabled"); #[cfg(feature = "wayland")] Ok(Box::new(consumer::wlroots::WlrootsConsumer::new()?)) - }, + } Backend::X11 => { #[cfg(not(feature = "x11"))] panic!("feature x11 not enabled"); #[cfg(feature = "x11")] Ok(Box::new(consumer::x11::X11Consumer::new())) - }, + } } } diff --git a/src/event.rs b/src/event.rs index 7b516f4..00032da 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,4 +1,7 @@ -use std::{error::Error, fmt::{self, Display}}; +use std::{ + error::Error, + fmt::{self, Display}, +}; #[derive(Debug, Clone, Copy)] pub enum PointerEvent { @@ -47,10 +50,22 @@ pub enum Event { impl Display for PointerEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - PointerEvent::Motion { time: _ , relative_x, relative_y } => write!(f, "motion({relative_x},{relative_y})"), - PointerEvent::Button { time: _ , button, state } => write!(f, "button({button}, {state})"), - PointerEvent::Axis { time: _, axis, value } => write!(f, "scroll({axis}, {value})"), - PointerEvent::Frame { } => write!(f, "frame()"), + PointerEvent::Motion { + time: _, + relative_x, + relative_y, + } => write!(f, "motion({relative_x},{relative_y})"), + PointerEvent::Button { + time: _, + button, + state, + } => write!(f, "button({button}, {state})"), + PointerEvent::Axis { + time: _, + axis, + value, + } => write!(f, "scroll({axis}, {value})"), + PointerEvent::Frame {} => write!(f, "frame()"), } } } @@ -58,8 +73,20 @@ impl Display for PointerEvent { impl Display for KeyboardEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - KeyboardEvent::Key { time: _, key, state } => write!(f, "key({key}, {state})"), - KeyboardEvent::Modifiers { mods_depressed, mods_latched, mods_locked, group } => write!(f, "modifiers({mods_depressed},{mods_latched},{mods_locked},{group})"), + KeyboardEvent::Key { + time: _, + key, + state, + } => write!(f, "key({key}, {state})"), + KeyboardEvent::Modifiers { + mods_depressed, + mods_latched, + mods_locked, + group, + } => write!( + f, + "modifiers({mods_depressed},{mods_latched},{mods_locked},{group})" + ), } } } diff --git a/src/frontend.rs b/src/frontend.rs index 937ac1a..5f21c7d 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -1,25 +1,31 @@ -use anyhow::{Result, anyhow}; -use std::{str, io::ErrorKind, time::Duration, cmp::min}; +use anyhow::{anyhow, Result}; +use std::{cmp::min, io::ErrorKind, str, time::Duration}; #[cfg(unix)] -use std::{env, path::{Path, PathBuf}}; +use std::{ + env, + path::{Path, PathBuf}, +}; -use tokio::io::{AsyncReadExt, WriteHalf, AsyncWriteExt}; use tokio::io::ReadHalf; +use tokio::io::{AsyncReadExt, AsyncWriteExt, WriteHalf}; -#[cfg(unix)] -use tokio::net::UnixStream; #[cfg(unix)] use tokio::net::UnixListener; +#[cfg(unix)] +use tokio::net::UnixStream; -#[cfg(windows)] -use tokio::net::TcpStream; #[cfg(windows)] use tokio::net::TcpListener; +#[cfg(windows)] +use tokio::net::TcpStream; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; -use crate::{client::{Position, ClientHandle, Client}, config::{Config, Frontend}}; +use crate::{ + client::{Client, ClientHandle, Position}, + config::{Config, Frontend}, +}; /// cli frontend pub mod cli; @@ -28,14 +34,17 @@ pub mod cli; #[cfg(all(unix, feature = "gtk"))] pub mod gtk; - pub fn run_frontend(config: &Config) -> Result<()> { match config.frontend { #[cfg(all(unix, feature = "gtk"))] - Frontend::Gtk => { gtk::run(); } + Frontend::Gtk => { + gtk::run(); + } #[cfg(any(not(feature = "gtk"), not(unix)))] Frontend::Gtk => panic!("gtk frontend requested but feature not enabled!"), - Frontend::Cli => { cli::run()?; } + Frontend::Cli => { + cli::run()?; + } }; Ok(()) } @@ -54,7 +63,7 @@ pub fn wait_for_service() -> Result { loop { use std::os::unix::net::UnixStream; if let Ok(stream) = UnixStream::connect(&socket_path) { - break Ok(stream) + break Ok(stream); } // a signaling mechanism or inotify could be used to // improve this @@ -68,7 +77,7 @@ pub fn wait_for_service() -> Result { loop { use std::net::TcpStream; if let Ok(stream) = TcpStream::connect("127.0.0.1:5252") { - break Ok(stream) + break Ok(stream); } std::thread::sleep(*exponential_back_off(&mut duration)); } @@ -146,7 +155,7 @@ impl FrontendListener { Err(e) => { log::debug!("{socket_path:?}: {e} - removing left behind socket"); let _ = std::fs::remove_file(&socket_path); - }, + } } } let listener = match UnixListener::bind(&socket_path) { @@ -160,10 +169,10 @@ impl FrontendListener { #[cfg(windows)] let listener = match TcpListener::bind("127.0.0.1:5252").await { - Ok(ls) => ls, - // some other lan-mouse instance has bound the socket in the meantime - Err(e) if e.kind() == ErrorKind::AddrInUse => return None, - Err(e) => return Some(Err(anyhow!("failed to bind lan-mouse-socket: {e}"))), + Ok(ls) => ls, + // some other lan-mouse instance has bound the socket in the meantime + Err(e) if e.kind() == ErrorKind::AddrInUse => return None, + Err(e) => return Some(Err(anyhow!("failed to bind lan-mouse-socket: {e}"))), }; let adapter = Self { @@ -194,7 +203,6 @@ impl FrontendListener { Ok(rx) } - pub(crate) async fn notify_all(&mut self, notify: FrontendNotify) -> Result<()> { // encode event let json = serde_json::to_string(¬ify).unwrap(); @@ -207,7 +215,7 @@ impl FrontendListener { // TODO do simultaneously for tx in self.tx_streams.iter_mut() { // write len + payload - if let Err(_) = tx.write(&len).await { + if let Err(_) = tx.write(&len).await { keep.push(false); continue; } @@ -249,4 +257,3 @@ pub async fn read_event(stream: &mut ReadHalf) -> Result Result<()> { let reader = thread::Builder::new() .name("cli-frontend".to_string()) .spawn(move || { - // all further prompts - prompt(); - loop { - let mut buf = String::new(); - match std::io::stdin().read_line(&mut buf) { - Ok(0) => break, - Ok(len) => { - if let Some(events) = parse_cmd(buf, len) { - for event in events.iter() { - let json = serde_json::to_string(&event).unwrap(); - let bytes = json.as_bytes(); - let len = bytes.len().to_be_bytes(); - if let Err(e) = tx.write(&len) { - log::error!("error sending message: {e}"); - }; - if let Err(e) = tx.write(bytes) { - log::error!("error sending message: {e}"); - }; - if *event == FrontendEvent::Shutdown() { - return; + // all further prompts + prompt(); + loop { + let mut buf = String::new(); + match std::io::stdin().read_line(&mut buf) { + Ok(0) => break, + Ok(len) => { + if let Some(events) = parse_cmd(buf, len) { + for event in events.iter() { + let json = serde_json::to_string(&event).unwrap(); + let bytes = json.as_bytes(); + let len = bytes.len().to_be_bytes(); + if let Err(e) = tx.write(&len) { + log::error!("error sending message: {e}"); + }; + if let Err(e) = tx.write(bytes) { + log::error!("error sending message: {e}"); + }; + if *event == FrontendEvent::Shutdown() { + return; + } } + // prompt is printed after the server response is received + } else { + prompt(); } - // prompt is printed after the server response is received - } else { - prompt(); + } + Err(e) => { + log::error!("error reading from stdin: {e}"); + break; } } - Err(e) => { - log::error!("error reading from stdin: {e}"); - break - } } - } - })?; + })?; let writer = thread::Builder::new() .name("cli-frontend-notify".to_string()) @@ -93,35 +97,43 @@ pub fn run() -> Result<()> { }; match notify { FrontendNotify::NotifyClientCreate(client, host, port, pos) => { - log::info!("new client ({client}): {}:{port} - {pos}", host.as_deref().unwrap_or("")); - }, + log::info!( + "new client ({client}): {}:{port} - {pos}", + host.as_deref().unwrap_or("") + ); + } FrontendNotify::NotifyClientUpdate(client, host, port, pos) => { - log::info!("client ({client}) updated: {}:{port} - {pos}", host.as_deref().unwrap_or("")); - }, + log::info!( + "client ({client}) updated: {}:{port} - {pos}", + host.as_deref().unwrap_or("") + ); + } FrontendNotify::NotifyClientDelete(client) => { log::info!("client ({client}) deleted."); - }, + } FrontendNotify::NotifyError(e) => { log::warn!("{e}"); - }, + } FrontendNotify::Enumerate(clients) => { for (client, active) in clients.into_iter() { - log::info!("client ({}) [{}]: active: {}, associated addresses: [{}]", + log::info!( + "client ({}) [{}]: active: {}, associated addresses: [{}]", client.handle, client.hostname.as_deref().unwrap_or(""), if active { "yes" } else { "no" }, - client.addrs.into_iter().map(|a| a.to_string()) - .collect::>() - .join(", ") + client + .addrs + .into_iter() + .map(|a| a.to_string()) + .collect::>() + .join(", ") ); } - }, - FrontendNotify::NotifyPortChange(port, msg) => { - match msg { - Some(msg) => log::info!("could not change port: {msg}"), - None => log::info!("port changed: {port}"), - } } + FrontendNotify::NotifyPortChange(port, msg) => match msg { + Some(msg) => log::info!("could not change port: {msg}"), + None => log::info!("port changed: {port}"), + }, } prompt(); } @@ -132,10 +144,10 @@ pub fn run() -> Result<()> { let msg = match (e.downcast_ref::<&str>(), e.downcast_ref::()) { (Some(&s), _) => s, (_, Some(s)) => s, - _ => "no panic info" + _ => "no panic info", }; log::error!("reader thread paniced: {msg}"); - }, + } } match writer.join() { Ok(_) => (), @@ -143,10 +155,10 @@ pub fn run() -> Result<()> { let msg = match (e.downcast_ref::<&str>(), e.downcast_ref::()) { (Some(&s), _) => s, (_, Some(s)) => s, - _ => "no panic info" + _ => "no panic info", }; log::error!("writer thread paniced: {msg}"); - }, + } } Ok(()) } @@ -158,7 +170,7 @@ fn prompt() { fn parse_cmd(s: String, len: usize) -> Option> { if len == 0 { - return Some(vec![FrontendEvent::Shutdown()]) + return Some(vec![FrontendEvent::Shutdown()]); } let mut l = s.split_whitespace(); let cmd = l.next()?; @@ -191,7 +203,7 @@ fn parse_cmd(s: String, len: usize) -> Option> { log::warn!("{e}"); None } - _ => None + _ => None, } } @@ -209,22 +221,34 @@ fn parse_connect(mut l: SplitWhitespace) -> Result> { } else { DEFAULT_PORT }; - Ok(vec![FrontendEvent::AddClient(Some(host), port, pos), FrontendEvent::Enumerate()]) + Ok(vec![ + FrontendEvent::AddClient(Some(host), port, pos), + FrontendEvent::Enumerate(), + ]) } fn parse_disconnect(mut l: SplitWhitespace) -> Result> { let client = l.next().context("usage: disconnect ")?.parse()?; - Ok(vec![FrontendEvent::DelClient(client), FrontendEvent::Enumerate()]) + Ok(vec![ + FrontendEvent::DelClient(client), + FrontendEvent::Enumerate(), + ]) } fn parse_activate(mut l: SplitWhitespace) -> Result> { let client = l.next().context("usage: activate ")?.parse()?; - Ok(vec![FrontendEvent::ActivateClient(client, true), FrontendEvent::Enumerate()]) + Ok(vec![ + FrontendEvent::ActivateClient(client, true), + FrontendEvent::Enumerate(), + ]) } fn parse_deactivate(mut l: SplitWhitespace) -> Result> { let client = l.next().context("usage: deactivate ")?.parse()?; - Ok(vec![FrontendEvent::ActivateClient(client, false), FrontendEvent::Enumerate()]) + Ok(vec![ + FrontendEvent::ActivateClient(client, false), + FrontendEvent::Enumerate(), + ]) } fn parse_port(mut l: SplitWhitespace) -> Result> { diff --git a/src/frontend/gtk.rs b/src/frontend/gtk.rs index 81c521e..5f67e41 100644 --- a/src/frontend/gtk.rs +++ b/src/frontend/gtk.rs @@ -1,13 +1,24 @@ -mod window; mod client_object; mod client_row; +mod window; -use std::{io::{Read, ErrorKind}, env, process, str}; +use std::{ + env, + io::{ErrorKind, Read}, + process, str, +}; -use crate::{frontend::gtk::window::Window, config::DEFAULT_PORT}; +use crate::{config::DEFAULT_PORT, frontend::gtk::window::Window}; -use gtk::{prelude::*, IconTheme, gdk::Display, gio::{SimpleAction, SimpleActionGroup}, glib::{clone, MainContext, Priority}, CssProvider, subclass::prelude::ObjectSubclassIsExt}; use adw::Application; +use gtk::{ + gdk::Display, + gio::{SimpleAction, SimpleActionGroup}, + glib::{clone, MainContext, Priority}, + prelude::*, + subclass::prelude::ObjectSubclassIsExt, + CssProvider, IconTheme, +}; use gtk::{gio, glib, prelude::ApplicationExt}; use self::client_object::ClientObject; @@ -22,8 +33,7 @@ pub fn run() -> glib::ExitCode { } fn gtk_main() -> glib::ExitCode { - gio::resources_register_include!("lan-mouse.gresource") - .expect("Failed to register resources."); + gio::resources_register_include!("lan-mouse.gresource").expect("Failed to register resources."); let app = Application::builder() .application_id("de.feschber.lan-mouse") @@ -41,14 +51,15 @@ fn load_css() { let provider = CssProvider::new(); provider.load_from_resource("de/feschber/LanMouse/style.css"); gtk::style_context_add_provider_for_display( - &Display::default().expect("Could not connect to a display."), + &Display::default().expect("Could not connect to a display."), &provider, gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, ); } fn load_icons() { - let icon_theme = IconTheme::for_display(&Display::default().expect("Could not connect to a display.")); + let icon_theme = + IconTheme::for_display(&Display::default().expect("Could not connect to a display.")); icon_theme.add_resource_path("/de/feschber/LanMouse/icons"); } @@ -69,7 +80,7 @@ fn build_ui(app: &Application) { } }; log::debug!("connected to lan-mouse-socket"); - + let (sender, receiver) = MainContext::channel::(Priority::default()); gio::spawn_blocking(move || { @@ -92,14 +103,13 @@ fn build_ui(app: &Application) { }; // parse json - let json = str::from_utf8(&buf) - .unwrap(); + let json = str::from_utf8(&buf).unwrap(); match serde_json::from_str(json) { Ok(notify) => sender.send(notify).unwrap(), Err(e) => log::error!("{e}"), } } { - Ok(()) => {}, + Ok(()) => {} Err(e) => log::error!("{e}"), } }); @@ -152,16 +162,12 @@ fn build_ui(app: &Application) { } )); - let action_request_client_update = SimpleAction::new( - "request-client-update", - Some(&u32::static_variant_type()), - ); + let action_request_client_update = + SimpleAction::new("request-client-update", Some(&u32::static_variant_type())); // remove client - let action_client_delete = SimpleAction::new( - "request-client-delete", - Some(&u32::static_variant_type()), - ); + let action_client_delete = + SimpleAction::new("request-client-delete", Some(&u32::static_variant_type())); // update client state action_request_client_update.connect_activate(clone!(@weak window => move |_action, param| { diff --git a/src/frontend/gtk/client_object.rs b/src/frontend/gtk/client_object.rs index 1037b33..b8325a1 100644 --- a/src/frontend/gtk/client_object.rs +++ b/src/frontend/gtk/client_object.rs @@ -1,7 +1,7 @@ mod imp; -use gtk::glib::{self, Object}; use adw::subclass::prelude::*; +use gtk::glib::{self, Object}; use crate::client::ClientHandle; @@ -10,7 +10,13 @@ glib::wrapper! { } impl ClientObject { - pub fn new(handle: ClientHandle, hostname: Option, port: u32, position: String, active: bool) -> Self { + pub fn new( + handle: ClientHandle, + hostname: Option, + port: u32, + position: String, + active: bool, + ) -> Self { Object::builder() .property("handle", handle) .property("hostname", hostname) diff --git a/src/frontend/gtk/client_row.rs b/src/frontend/gtk/client_row.rs index 1cb2645..b0897d4 100644 --- a/src/frontend/gtk/client_row.rs +++ b/src/frontend/gtk/client_row.rs @@ -16,8 +16,7 @@ glib::wrapper! { impl ClientRow { pub fn new(_client_object: &ClientObject) -> Self { - Object::builder() - .build() + Object::builder().build() } pub fn bind(&self, client_object: &ClientObject) { @@ -86,24 +85,19 @@ impl ClientRow { .sync_create() .build(); - let position_binding = client_object .bind_property("position", &self.imp().position.get(), "selected") - .transform_from(|_, v: u32| { - match v { - 1 => Some("right"), - 2 => Some("top"), - 3 => Some("bottom"), - _ => Some("left"), - } + .transform_from(|_, v: u32| match v { + 1 => Some("right"), + 2 => Some("top"), + 3 => Some("bottom"), + _ => Some("left"), }) - .transform_to(|_, v: String| { - match v.as_str() { - "right" => Some(1), - "top" => Some(2u32), - "bottom" => Some(3u32), - _ => Some(0u32), - } + .transform_to(|_, v: String| match v.as_str() { + "right" => Some(1), + "top" => Some(2u32), + "bottom" => Some(3u32), + _ => Some(0u32), }) .bidirectional() .sync_create() diff --git a/src/frontend/gtk/client_row/imp.rs b/src/frontend/gtk/client_row/imp.rs index cd8fa1a..befd167 100644 --- a/src/frontend/gtk/client_row/imp.rs +++ b/src/frontend/gtk/client_row/imp.rs @@ -1,10 +1,10 @@ use std::cell::RefCell; -use glib::{Binding, subclass::InitializingObject}; -use adw::{prelude::*, ComboRow, ActionRow}; use adw::subclass::prelude::*; +use adw::{prelude::*, ActionRow, ComboRow}; +use glib::{subclass::InitializingObject, Binding}; use gtk::glib::clone; -use gtk::{glib, CompositeTemplate, Switch, Button}; +use gtk::{glib, Button, CompositeTemplate, Switch}; #[derive(CompositeTemplate, Default)] #[template(resource = "/de/feschber/LanMouse/client_row.ui")] @@ -44,9 +44,10 @@ impl ObjectSubclass for ClientRow { impl ObjectImpl for ClientRow { fn constructed(&self) { self.parent_constructed(); - self.delete_button.connect_clicked(clone!(@weak self as row => move |button| { - row.handle_client_delete(button); - })); + self.delete_button + .connect_clicked(clone!(@weak self as row => move |button| { + row.handle_client_delete(button); + })); } } @@ -55,7 +56,9 @@ impl ClientRow { #[template_callback] fn handle_client_set_state(&self, state: bool, switch: &Switch) -> bool { let idx = self.obj().index() as u32; - switch.activate_action("win.request-client-update", Some(&idx.to_variant())).unwrap(); + switch + .activate_action("win.request-client-update", Some(&idx.to_variant())) + .unwrap(); switch.set_state(state); true // dont run default handler diff --git a/src/frontend/gtk/window.rs b/src/frontend/gtk/window.rs index 0bf2d48..066e39f 100644 --- a/src/frontend/gtk/window.rs +++ b/src/frontend/gtk/window.rs @@ -4,10 +4,14 @@ use std::io::Write; use adw::prelude::*; use adw::subclass::prelude::*; -use gtk::{glib, gio, NoSelection}; use glib::{clone, Object}; +use gtk::{gio, glib, NoSelection}; -use crate::{frontend::{gtk::client_object::ClientObject, FrontendEvent}, client::{Position, ClientHandle}, config::DEFAULT_PORT}; +use crate::{ + client::{ClientHandle, Position}, + config::DEFAULT_PORT, + frontend::{gtk::client_object::ClientObject, FrontendEvent}, +}; use super::client_row::ClientRow; @@ -67,7 +71,14 @@ impl Window { row } - pub fn new_client(&self, handle: ClientHandle, hostname: Option, port: u16, position: Position, active: bool) { + pub fn new_client( + &self, + handle: ClientHandle, + hostname: Option, + port: u16, + position: Position, + active: bool, + ) { let client = ClientObject::new(handle, hostname, port as u32, position.to_string(), active); self.clients().append(&client); self.set_placeholder_visible(false); @@ -122,7 +133,7 @@ impl Window { "bottom" => Position::Bottom, _ => { log::error!("invalid position: {}", data.position); - return + return; } }; let hostname = data.hostname; @@ -133,7 +144,7 @@ impl Window { let event = FrontendEvent::ActivateClient(client.handle(), !client.active()); self.request(event); } - + pub fn request_client_delete(&self, idx: u32) { if let Some(obj) = self.clients().item(idx) { let client_object: &ClientObject = obj @@ -145,7 +156,7 @@ impl Window { } } - fn request(&self, event: FrontendEvent) { + fn request(&self, event: FrontendEvent) { let json = serde_json::to_string(&event).unwrap(); log::debug!("requesting {json}"); let mut stream = self.imp().stream.borrow_mut(); diff --git a/src/frontend/gtk/window/imp.rs b/src/frontend/gtk/window/imp.rs index fd2524e..ae328de 100644 --- a/src/frontend/gtk/window/imp.rs +++ b/src/frontend/gtk/window/imp.rs @@ -1,9 +1,15 @@ -use std::{cell::{Cell, RefCell}, os::unix::net::UnixStream}; +use std::{ + cell::{Cell, RefCell}, + os::unix::net::UnixStream, +}; -use glib::subclass::InitializingObject; -use adw::{ActionRow, ToastOverlay, prelude::{WidgetExt, EditableExt}}; use adw::subclass::prelude::*; -use gtk::{glib, Button, CompositeTemplate, ListBox, gio, Entry}; +use adw::{ + prelude::{EditableExt, WidgetExt}, + ActionRow, ToastOverlay, +}; +use glib::subclass::InitializingObject; +use gtk::{gio, glib, Button, CompositeTemplate, Entry, ListBox}; use crate::config::DEFAULT_PORT; @@ -65,7 +71,8 @@ impl Window { #[template_callback] fn handle_port_edit_cancel(&self) { log::debug!("cancel port edit"); - self.port_entry.set_text(self.port.get().to_string().as_str()); + self.port_entry + .set_text(self.port.get().to_string().as_str()); self.port_edit_apply.set_visible(false); self.port_edit_cancel.set_visible(false); } @@ -82,7 +89,6 @@ impl Window { } } - impl ObjectImpl for Window { fn constructed(&self) { self.parent_constructed(); diff --git a/src/ioutils.rs b/src/ioutils.rs index ec03cfe..0c54172 100644 --- a/src/ioutils.rs +++ b/src/ioutils.rs @@ -2,9 +2,8 @@ use std::io::{self, Write}; use crate::client::Position; - pub fn ask_confirmation(default: bool) -> Result { - eprint!("{}", if default {" [Y,n] "} else { " [y,N] "}); + eprint!("{}", if default { " [Y,n] " } else { " [y,N] " }); io::stderr().flush()?; let answer = loop { let mut buffer = String::new(); @@ -18,7 +17,7 @@ pub fn ask_confirmation(default: bool) -> Result { _ => { eprint!("Enter y for Yes or n for No: "); io::stderr().flush()?; - continue + continue; } } }; @@ -41,7 +40,7 @@ pub fn ask_position() -> Result { _ => { eprint!("Invalid position: {answer} - enter top (t) | bottom (b) | left(l) | right(r): "); io::stderr().flush()?; - continue + continue; } }; }; diff --git a/src/main.rs b/src/main.rs index 11c91af..c608417 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,18 @@ use anyhow::Result; -use std::process::{self, Command, Child}; +use std::process::{self, Child, Command}; use env_logger::Env; use lan_mouse::{ - consumer, producer, - config::Config, server::Server, - frontend::{FrontendListener, self}, + config::Config, + consumer, + frontend::{self, FrontendListener}, + producer, + server::Server, }; -use tokio::{task::LocalSet, join}; +use tokio::{join, task::LocalSet}; pub fn main() { - // init logging let env = Env::default().filter_or("LAN_MOUSE_LOG_LEVEL", "info"); env_logger::init_from_env(env); @@ -30,7 +31,6 @@ pub fn start_service() -> Result { Ok(child) } - pub fn run() -> Result<()> { // parse config file + cli args let config = Config::new()?; @@ -40,13 +40,12 @@ pub fn run() -> Result<()> { // if daemon is specified we run the service run_service(&config)?; } else { - // otherwise start the service as a child process and + // otherwise start the service as a child process and // run a frontend start_service()?; frontend::run_frontend(&config)?; } - anyhow::Ok(()) } @@ -66,16 +65,12 @@ fn run_service(config: &Config) -> Result<()> { None => { // none means some other instance is already running log::info!("service already running, exiting"); - return anyhow::Ok(()) + return anyhow::Ok(()); } -, }; // create event producer and consumer - let (producer, consumer) = join!( - producer::create(), - consumer::create(), - ); + let (producer, consumer) = join!(producer::create(), consumer::create(),); let (producer, consumer) = (producer?, consumer?); // create server diff --git a/src/producer.rs b/src/producer.rs index 68d268e..e4340dc 100644 --- a/src/producer.rs +++ b/src/producer.rs @@ -3,8 +3,11 @@ use std::io; use futures_core::Stream; -use crate::{client::{ClientHandle, ClientEvent}, event::Event}; use crate::backend::producer; +use crate::{ + client::{ClientEvent, ClientHandle}, + event::Event, +}; #[cfg(unix)] use std::env; @@ -26,7 +29,7 @@ pub async fn create() -> Result> { "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") { @@ -39,7 +42,7 @@ pub async fn create() -> Result> { 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 @@ -48,7 +51,9 @@ pub async fn create() -> Result> { } _ => panic!("unknown XDG_SESSION_TYPE"), }, - Err(_) => panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!"), + Err(_) => { + panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!") + } }; #[cfg(unix)] @@ -70,7 +75,7 @@ pub async fn create() -> Result> { panic!("feature libei not enabled"); #[cfg(feature = "libei")] Ok(Box::new(producer::libei::LibeiProducer::new()?)) - }, + } } } diff --git a/src/server.rs b/src/server.rs index af216c9..ce56a32 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,7 +1,18 @@ -use std::{error::Error, io::Result, collections::HashSet, time::{Duration, Instant}, net::IpAddr}; -use log; -use tokio::{net::UdpSocket, io::ReadHalf, signal, sync::mpsc::{Sender, Receiver}}; use futures::stream::StreamExt; +use log; +use std::{ + collections::HashSet, + error::Error, + io::Result, + net::IpAddr, + time::{Duration, Instant}, +}; +use tokio::{ + io::ReadHalf, + net::UdpSocket, + signal, + sync::mpsc::{Receiver, Sender}, +}; #[cfg(unix)] use tokio::net::UnixStream; @@ -9,10 +20,17 @@ use tokio::net::UnixStream; #[cfg(windows)] use tokio::net::TcpStream; -use std::{net::SocketAddr, io::ErrorKind}; +use std::{io::ErrorKind, net::SocketAddr}; -use crate::{client::{ClientEvent, ClientManager, Position, ClientHandle}, consumer::EventConsumer, producer::EventProducer, frontend::{FrontendEvent, FrontendListener, FrontendNotify, self}, dns::{self, DnsResolver}, config::Config}; use crate::event::Event; +use crate::{ + client::{ClientEvent, ClientHandle, ClientManager, Position}, + config::Config, + consumer::EventConsumer, + dns::{self, DnsResolver}, + frontend::{self, FrontendEvent, FrontendListener, FrontendNotify}, + producer::EventProducer, +}; /// keeps track of state to prevent a feedback loop /// of continuously sending and receiving the same event. @@ -41,7 +59,6 @@ impl Server { consumer: Box, producer: Box, ) -> anyhow::Result { - // create dns resolver let resolver = dns::DnsResolver::new().await?; @@ -65,7 +82,7 @@ impl Server { }; // add clients from config - for (c,h,port,p) in config.get_clients().into_iter() { + for (c, h, port, p) in config.get_clients().into_iter() { server.add_client(h, c, port, p).await; } @@ -73,7 +90,6 @@ impl Server { } pub async fn run(&mut self) -> anyhow::Result<()> { - loop { log::trace!("polling ..."); tokio::select! { @@ -127,14 +143,20 @@ impl Server { } } } - + // destroy consumer self.consumer.destroy().await; Ok(()) } - pub async fn add_client(&mut self, hostname: Option, mut addr: HashSet, port: u16, pos: Position) -> ClientHandle { + pub async fn add_client( + &mut self, + hostname: Option, + mut addr: HashSet, + port: u16, + pos: Position, + ) -> ClientHandle { let ips = if let Some(hostname) = hostname.as_ref() { match self.resolver.resolve(hostname.as_str()).await { Ok(ips) => HashSet::from_iter(ips.iter().cloned()), @@ -147,8 +169,15 @@ impl Server { HashSet::new() }; addr.extend(ips.iter()); - log::info!("adding client [{}]{} @ {:?}", pos, hostname.as_deref().unwrap_or(""), &ips); - let client = self.client_manager.add_client(hostname.clone(), addr, port, pos); + log::info!( + "adding client [{}]{} @ {:?}", + pos, + hostname.as_deref().unwrap_or(""), + &ips + ); + let client = self + .client_manager + .add_client(hostname.clone(), addr, port, pos); log::debug!("add_client {client}"); let notify = FrontendNotify::NotifyClientCreate(client, hostname, port, pos); if let Err(e) = self.frontend.notify_all(notify).await { @@ -161,8 +190,11 @@ impl Server { if let Some(state) = self.client_manager.get_mut(client) { state.active = active; if state.active { - self.producer.notify(ClientEvent::Create(client, state.client.pos)); - self.consumer.notify(ClientEvent::Create(client, state.client.pos)).await; + self.producer + .notify(ClientEvent::Create(client, state.client.pos)); + self.consumer + .notify(ClientEvent::Create(client, state.client.pos)) + .await; } else { self.producer.notify(ClientEvent::Destroy(client)); self.consumer.notify(ClientEvent::Destroy(client)).await; @@ -173,7 +205,11 @@ impl Server { pub async fn remove_client(&mut self, client: ClientHandle) -> Option { self.producer.notify(ClientEvent::Destroy(client)); self.consumer.notify(ClientEvent::Destroy(client)).await; - if let Some(client) = self.client_manager.remove_client(client).map(|s| s.client.handle) { + if let Some(client) = self + .client_manager + .remove_client(client) + .map(|s| s.client.handle) + { let notify = FrontendNotify::NotifyClientDelete(client); log::debug!("{notify:?}"); if let Err(e) = self.frontend.notify_all(notify).await { @@ -194,7 +230,7 @@ impl Server { ) { // retrieve state let Some(state) = self.client_manager.get_mut(client) else { - return + return; }; // update pos @@ -209,12 +245,20 @@ impl Server { // update port if state.client.port != port { state.client.port = port; - state.client.addrs = state.client.addrs + state.client.addrs = state + .client + .addrs .iter() .cloned() - .map(|mut a| { a.set_port(port); a }) + .map(|mut a| { + a.set_port(port); + a + }) .collect(); - state.client.active_addr.map(|a| { SocketAddr::new(a.ip(), port) }); + state + .client + .active_addr + .map(|a| SocketAddr::new(a.ip(), port)); } // update hostname @@ -258,12 +302,12 @@ impl Server { } }; - // reset ttl for client and + // reset ttl for client and state.last_seen = Some(Instant::now()); // set addr as new default for this client state.client.active_addr = Some(addr); match (event, addr) { - (Event::Pong(), _) => {}, + (Event::Pong(), _) => {} (Event::Ping(), addr) => { if let Err(e) = send_event(&self.socket, Event::Pong(), addr).await { log::error!("udp send: {}", e); @@ -291,16 +335,17 @@ impl Server { // let the server know we are still alive once every second let last_replied = state.last_replied; - if last_replied.is_none() - || last_replied.is_some() - && last_replied.unwrap().elapsed() > Duration::from_secs(1) { + if last_replied.is_none() + || last_replied.is_some() + && last_replied.unwrap().elapsed() > Duration::from_secs(1) + { state.last_replied = Some(Instant::now()); if let Err(e) = send_event(&self.socket, Event::Pong(), addr).await { log::error!("udp send: {}", e); } } } - } + }, } } @@ -317,7 +362,7 @@ impl Server { Some(state) => state, None => { log::warn!("unknown client!"); - return + return; } }; // otherwise we should have an address to send to @@ -331,20 +376,21 @@ impl Server { // if client last responded > 2 seconds ago // and we have not sent a ping since 500 milliseconds, // send a ping - if state.last_seen.is_some() - && state.last_seen.unwrap().elapsed() < Duration::from_secs(2) { - return + if state.last_seen.is_some() && state.last_seen.unwrap().elapsed() < Duration::from_secs(2) + { + return; } // client last seen > 500ms ago if state.last_ping.is_some() - && state.last_ping.unwrap().elapsed() < Duration::from_millis(500) { - return + && state.last_ping.unwrap().elapsed() < Duration::from_millis(500) + { + return; } // release mouse if client didnt respond to the first ping - if state.last_ping.is_some() - && state.last_ping.unwrap().elapsed() < Duration::from_secs(1) { + if state.last_ping.is_some() && state.last_ping.unwrap().elapsed() < Duration::from_secs(1) + { should_release = true; } @@ -414,12 +460,20 @@ impl Server { async fn handle_frontend_event(&mut self, event: FrontendEvent) -> bool { log::debug!("frontend: {event:?}"); match event { - FrontendEvent::AddClient(hostname, port, pos) => { self.add_client(hostname, HashSet::new(), port, pos).await; }, - FrontendEvent::ActivateClient(client, active) => self.activate_client(client, active).await, + FrontendEvent::AddClient(hostname, port, pos) => { + self.add_client(hostname, HashSet::new(), port, pos).await; + } + FrontendEvent::ActivateClient(client, active) => { + self.activate_client(client, active).await + } FrontendEvent::ChangePort(port) => { let current_port = self.socket.local_addr().unwrap().port(); if current_port == port { - if let Err(e) = self.frontend.notify_all(FrontendNotify::NotifyPortChange(port, None)).await { + if let Err(e) = self + .frontend + .notify_all(FrontendNotify::NotifyPortChange(port, None)) + .await + { log::warn!("error notifying frontend: {e}"); } return false; @@ -428,39 +482,60 @@ impl Server { match UdpSocket::bind(listen_addr).await { Ok(socket) => { self.socket = socket; - if let Err(e) = self.frontend.notify_all(FrontendNotify::NotifyPortChange(port, None)).await { + if let Err(e) = self + .frontend + .notify_all(FrontendNotify::NotifyPortChange(port, None)) + .await + { log::warn!("error notifying frontend: {e}"); } - }, + } Err(e) => { log::warn!("could not change port: {e}"); let port = self.socket.local_addr().unwrap().port(); - if let Err(e) = self.frontend.notify_all(FrontendNotify::NotifyPortChange(port, Some(format!("could not change port: {e}")))).await { + if let Err(e) = self + .frontend + .notify_all(FrontendNotify::NotifyPortChange( + port, + Some(format!("could not change port: {e}")), + )) + .await + { log::error!("error notifying frontend: {e}"); } } } - }, - FrontendEvent::DelClient(client) => { self.remove_client(client).await; }, + } + FrontendEvent::DelClient(client) => { + self.remove_client(client).await; + } FrontendEvent::Enumerate() => self.enumerate().await, FrontendEvent::Shutdown() => { log::info!("terminating gracefully..."); return true; - }, - FrontendEvent::UpdateClient(client, hostname, port, pos) => self.update_client(client, hostname, port, pos).await, + } + FrontendEvent::UpdateClient(client, hostname, port, pos) => { + self.update_client(client, hostname, port, pos).await + } } false } async fn enumerate(&mut self) { let clients = self.client_manager.enumerate(); - if let Err(e) = self.frontend.notify_all(FrontendNotify::Enumerate(clients)).await { + if let Err(e) = self + .frontend + .notify_all(FrontendNotify::Enumerate(clients)) + .await + { log::error!("error notifying frontend: {e}"); } } } -async fn receive_event(socket: &UdpSocket) -> std::result::Result<(Event, SocketAddr), Box> { +async fn receive_event( + socket: &UdpSocket, +) -> std::result::Result<(Event, SocketAddr), Box> { log::trace!("receive_event"); let mut buf = vec![0u8; 22]; match socket.recv_from(&mut buf).await { @@ -469,7 +544,6 @@ async fn receive_event(socket: &UdpSocket) -> std::result::Result<(Event, Socket } } - async fn send_event(sock: &UdpSocket, e: Event, addr: SocketAddr) -> Result { log::trace!("{:20} ------>->->-> {addr}", e.to_string()); let data: Vec = (&e).into(); @@ -477,4 +551,3 @@ async fn send_event(sock: &UdpSocket, e: Event, addr: SocketAddr) -> Result