From d73ced7b16a85c651bbb90006fbc2643ecf35259 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Thu, 11 Jul 2024 15:12:59 +0200 Subject: [PATCH] wire frontend --- input-capture/src/dummy.rs | 7 +- input-capture/src/lib.rs | 8 +- input-capture/src/libei.rs | 11 +- input-capture/src/macos.rs | 6 +- input-capture/src/wayland.rs | 12 +-- input-capture/src/windows.rs | 6 +- input-capture/src/x11.rs | 7 +- resources/window.ui | 8 +- src/frontend.rs | 19 ++++ src/frontend/cli.rs | 6 ++ src/frontend/gtk.rs | 6 ++ src/frontend/gtk/window.rs | 21 ++++ src/frontend/gtk/window/imp.rs | 11 +- src/server.rs | 37 +++---- src/server/capture_task.rs | 179 ++++++++++++++++++++++++--------- src/server/emulation_task.rs | 76 +++++++++++--- src/server/frontend_task.rs | 16 ++- 17 files changed, 315 insertions(+), 121 deletions(-) diff --git a/input-capture/src/dummy.rs b/input-capture/src/dummy.rs index d525db5..8bd2f65 100644 --- a/input-capture/src/dummy.rs +++ b/input-capture/src/dummy.rs @@ -1,4 +1,3 @@ -use std::io; use std::pin::Pin; use std::task::{Context, Poll}; @@ -27,15 +26,15 @@ impl Default for DummyInputCapture { #[async_trait] impl InputCapture for DummyInputCapture { - async fn create(&mut self, _handle: CaptureHandle, _pos: Position) -> io::Result<()> { + async fn create(&mut self, _handle: CaptureHandle, _pos: Position) -> Result<(), CaptureError> { Ok(()) } - async fn destroy(&mut self, _handle: CaptureHandle) -> io::Result<()> { + async fn destroy(&mut self, _handle: CaptureHandle) -> Result<(), CaptureError> { Ok(()) } - async fn release(&mut self) -> io::Result<()> { + async fn release(&mut self) -> Result<(), CaptureError> { Ok(()) } diff --git a/input-capture/src/lib.rs b/input-capture/src/lib.rs index 9e72160..ec041cd 100644 --- a/input-capture/src/lib.rs +++ b/input-capture/src/lib.rs @@ -1,4 +1,4 @@ -use std::{fmt::Display, io}; +use std::fmt::Display; use async_trait::async_trait; use futures_core::Stream; @@ -98,13 +98,13 @@ pub trait InputCapture: Stream> + Unpin { /// create a new client with the given id - async fn create(&mut self, id: CaptureHandle, pos: Position) -> io::Result<()>; + async fn create(&mut self, id: CaptureHandle, pos: Position) -> Result<(), CaptureError>; /// destroy the client with the given id, if it exists - async fn destroy(&mut self, id: CaptureHandle) -> io::Result<()>; + async fn destroy(&mut self, id: CaptureHandle) -> Result<(), CaptureError>; /// release mouse - async fn release(&mut self) -> io::Result<()>; + async fn release(&mut self) -> Result<(), CaptureError>; /// destroy the input acpture async fn terminate(&mut self) -> Result<(), CaptureError>; diff --git a/input-capture/src/libei.rs b/input-capture/src/libei.rs index aa947e8..5a19d27 100644 --- a/input-capture/src/libei.rs +++ b/input-capture/src/libei.rs @@ -37,10 +37,9 @@ use once_cell::sync::Lazy; use input_event::{Event, KeyboardEvent, PointerEvent}; -use crate::error::{CaptureError, ReisConvertEventStreamError}; - use super::{ - error::LibeiCaptureCreationError, CaptureHandle, InputCapture as LanMouseInputCapture, Position, + error::{CaptureError, LibeiCaptureCreationError, ReisConvertEventStreamError}, + CaptureHandle, InputCapture as LanMouseInputCapture, Position, }; /* there is a bug in xdg-remote-desktop-portal-gnome / mutter that @@ -648,7 +647,7 @@ fn to_input_events(ei_event: EiEvent) -> Events { #[async_trait] impl<'a> LanMouseInputCapture for LibeiInputCapture<'a> { - async fn create(&mut self, handle: CaptureHandle, pos: Position) -> io::Result<()> { + async fn create(&mut self, handle: CaptureHandle, pos: Position) -> Result<(), CaptureError> { let _ = self .notify_capture .send(CaptureEvent::Create(handle, pos)) @@ -656,7 +655,7 @@ impl<'a> LanMouseInputCapture for LibeiInputCapture<'a> { Ok(()) } - async fn destroy(&mut self, handle: CaptureHandle) -> io::Result<()> { + async fn destroy(&mut self, handle: CaptureHandle) -> Result<(), CaptureError> { let _ = self .notify_capture .send(CaptureEvent::Destroy(handle)) @@ -664,7 +663,7 @@ impl<'a> LanMouseInputCapture for LibeiInputCapture<'a> { Ok(()) } - async fn release(&mut self) -> io::Result<()> { + async fn release(&mut self) -> Result<(), CaptureError> { let _ = self.notify_capture_session.send(ReleaseCaptureEvent).await; Ok(()) } diff --git a/input-capture/src/macos.rs b/input-capture/src/macos.rs index 31a6ca7..e2909a3 100644 --- a/input-capture/src/macos.rs +++ b/input-capture/src/macos.rs @@ -25,15 +25,15 @@ impl Stream for MacOSInputCapture { #[async_trait] impl InputCapture for MacOSInputCapture { - async fn create(&mut self, _id: CaptureHandle, _pos: Position) -> io::Result<()> { + async fn create(&mut self, _id: CaptureHandle, _pos: Position) -> Result<(), CaptureError> { Ok(()) } - async fn destroy(&mut self, _id: CaptureHandle) -> io::Result<()> { + async fn destroy(&mut self, _id: CaptureHandle) -> Result<(), CaptureError> { Ok(()) } - async fn release(&mut self) -> io::Result<()> { + async fn release(&mut self) -> Result<(), CaptureError> { Ok(()) } diff --git a/input-capture/src/wayland.rs b/input-capture/src/wayland.rs index cbaf1d9..90974ee 100644 --- a/input-capture/src/wayland.rs +++ b/input-capture/src/wayland.rs @@ -566,23 +566,23 @@ impl Inner { #[async_trait] impl InputCapture for WaylandInputCapture { - async fn create(&mut self, handle: CaptureHandle, pos: Position) -> io::Result<()> { + async fn create(&mut self, handle: CaptureHandle, pos: Position) -> Result<(), CaptureError> { self.add_client(handle, pos); let inner = self.0.get_mut(); - inner.flush_events() + Ok(inner.flush_events()?) } - async fn destroy(&mut self, handle: CaptureHandle) -> io::Result<()> { + async fn destroy(&mut self, handle: CaptureHandle) -> Result<(), CaptureError> { self.delete_client(handle); let inner = self.0.get_mut(); - inner.flush_events() + Ok(inner.flush_events()?) } - async fn release(&mut self) -> io::Result<()> { + async fn release(&mut self) -> Result<(), CaptureError> { log::debug!("releasing pointer"); let inner = self.0.get_mut(); inner.state.ungrab(); - inner.flush_events() + Ok(inner.flush_events()?) } async fn terminate(&mut self) -> Result<(), CaptureError> { diff --git a/input-capture/src/windows.rs b/input-capture/src/windows.rs index 54bee50..17f37ab 100644 --- a/input-capture/src/windows.rs +++ b/input-capture/src/windows.rs @@ -65,7 +65,7 @@ unsafe fn signal_message_thread(event_type: EventType) { #[async_trait] impl InputCapture for WindowsInputCapture { - async fn create(&mut self, handle: CaptureHandle, pos: Position) -> io::Result<()> { + async fn create(&mut self, handle: CaptureHandle, pos: Position) -> Result<(), CaptureError> { unsafe { { let mut requests = REQUEST_BUFFER.lock().unwrap(); @@ -76,7 +76,7 @@ impl InputCapture for WindowsInputCapture { Ok(()) } - async fn destroy(&mut self, handle: CaptureHandle) -> io::Result<()> { + async fn destroy(&mut self, handle: CaptureHandle) -> Result<(), CaptureError> { unsafe { { let mut requests = REQUEST_BUFFER.lock().unwrap(); @@ -87,7 +87,7 @@ impl InputCapture for WindowsInputCapture { Ok(()) } - async fn release(&mut self) -> io::Result<()> { + async fn release(&mut self) -> Result<(), CaptureError> { unsafe { signal_message_thread(EventType::Release) }; Ok(()) } diff --git a/input-capture/src/x11.rs b/input-capture/src/x11.rs index b7eb485..1473d0f 100644 --- a/input-capture/src/x11.rs +++ b/input-capture/src/x11.rs @@ -1,4 +1,3 @@ -use std::io; use std::task::Poll; use async_trait::async_trait; @@ -22,15 +21,15 @@ impl X11InputCapture { #[async_trait] impl InputCapture for X11InputCapture { - async fn create(&mut self, _id: CaptureHandle, _pos: Position) -> io::Result<()> { + async fn create(&mut self, _id: CaptureHandle, _pos: Position) -> Result<(), CaptureError> { Ok(()) } - async fn destroy(&mut self, _id: CaptureHandle) -> io::Result<()> { + async fn destroy(&mut self, _id: CaptureHandle) -> Result<(), CaptureError> { Ok(()) } - async fn release(&mut self) -> io::Result<()> { + async fn release(&mut self) -> Result<(), CaptureError> { Ok(()) } diff --git a/resources/window.ui b/resources/window.ui index 9d698c7..bb10b69 100644 --- a/resources/window.ui +++ b/resources/window.ui @@ -45,11 +45,12 @@ vertical 12 - + Capture / Emulation Status - + input capture is disabled + required for outgoing and incoming connections dialog-warning-symbolic @@ -73,8 +74,9 @@ - + input emulation is disabled + required for incoming connections dialog-warning-symbolic diff --git a/src/frontend.rs b/src/frontend.rs index 5e1083c..4c38d3c 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -115,6 +115,21 @@ pub enum FrontendRequest { EnableEmulation, } +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum Status { + Enabled, + Disabled, +} + +impl From for bool { + fn from(status: Status) -> Self { + match status { + Status::Enabled => true, + Status::Disabled => false, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub enum FrontendEvent { /// a client was created @@ -131,6 +146,10 @@ pub enum FrontendEvent { Enumerate(Vec<(ClientHandle, ClientConfig, ClientState)>), /// an error occured Error(String), + /// capture status + CaptureStatus(Status), + /// emulation status + EmulationStatus(Status), } pub struct FrontendListener { diff --git a/src/frontend/cli.rs b/src/frontend/cli.rs index 89fc010..4224bb4 100644 --- a/src/frontend/cli.rs +++ b/src/frontend/cli.rs @@ -273,6 +273,12 @@ impl<'a> Cli<'a> { FrontendEvent::Error(e) => { eprintln!("ERROR: {e}"); } + FrontendEvent::CaptureStatus(s) => { + eprintln!("capture status: {s:?}") + } + FrontendEvent::EmulationStatus(s) => { + eprintln!("emulation status: {s:?}") + } } } diff --git a/src/frontend/gtk.rs b/src/frontend/gtk.rs index a3dad8c..87dccd1 100644 --- a/src/frontend/gtk.rs +++ b/src/frontend/gtk.rs @@ -150,6 +150,12 @@ fn build_ui(app: &Application) { } window.imp().set_port(port); } + FrontendEvent::CaptureStatus(s) => { + window.set_capture(s.into()); + } + FrontendEvent::EmulationStatus(s) => { + window.set_emulation(s.into()); + } } } })); diff --git a/src/frontend/gtk/window.rs b/src/frontend/gtk/window.rs index 5f371ee..b69855e 100644 --- a/src/frontend/gtk/window.rs +++ b/src/frontend/gtk/window.rs @@ -222,6 +222,7 @@ impl Window { pub fn request_emulation(&self) { self.request(FrontendRequest::EnableEmulation); } + pub fn request_client_state(&self, client: &ClientObject) { let handle = client.handle(); let event = FrontendRequest::GetState(handle); @@ -286,4 +287,24 @@ impl Window { let toast_overlay = &self.imp().toast_overlay; toast_overlay.add_toast(toast); } + + pub fn set_capture(&self, active: bool) { + self.imp().capture_active.replace(active); + self.update_capture_emulation_status(); + } + + pub fn set_emulation(&self, active: bool) { + self.imp().emulation_active.replace(active); + self.update_capture_emulation_status(); + } + + fn update_capture_emulation_status(&self) { + let capture = self.imp().capture_active.get(); + let emulation = self.imp().emulation_active.get(); + self.imp().capture_status_row.set_visible(!capture); + self.imp().emulation_status_row.set_visible(!emulation); + self.imp() + .capture_emulation_group + .set_visible(!capture || !emulation); + } } diff --git a/src/frontend/gtk/window/imp.rs b/src/frontend/gtk/window/imp.rs index f79f031..9b846ae 100644 --- a/src/frontend/gtk/window/imp.rs +++ b/src/frontend/gtk/window/imp.rs @@ -6,7 +6,7 @@ use std::net::TcpStream; use std::os::unix::net::UnixStream; use adw::subclass::prelude::*; -use adw::{prelude::*, ActionRow, ToastOverlay}; +use adw::{prelude::*, ActionRow, PreferencesGroup, ToastOverlay}; use glib::subclass::InitializingObject; use gtk::glib::clone; use gtk::{gdk, gio, glib, Button, CompositeTemplate, Entry, Label, ListBox}; @@ -31,6 +31,12 @@ pub struct Window { #[template_child] pub toast_overlay: TemplateChild, #[template_child] + pub capture_emulation_group: TemplateChild, + #[template_child] + pub capture_status_row: TemplateChild, + #[template_child] + pub emulation_status_row: TemplateChild, + #[template_child] pub input_emulation_button: TemplateChild