From 639e86d95e69b6a035591c93e5298e968faac554 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Fri, 14 Mar 2025 11:45:16 +0100 Subject: [PATCH] remove changed signal --- lan-mouse-cli/src/lib.rs | 22 ----- lan-mouse-gtk/resources/client_row.ui | 3 +- lan-mouse-gtk/src/client_object/imp.rs | 2 + lan-mouse-gtk/src/client_row.rs | 38 +++---- lan-mouse-gtk/src/client_row/imp.rs | 50 ++++++++-- lan-mouse-gtk/src/lib.rs | 5 +- lan-mouse-gtk/src/window.rs | 132 ++++++++++++++----------- lan-mouse-ipc/src/lib.rs | 4 - src/service.rs | 15 ++- 9 files changed, 141 insertions(+), 130 deletions(-) diff --git a/lan-mouse-cli/src/lib.rs b/lan-mouse-cli/src/lib.rs index f74a406..2c1db0d 100644 --- a/lan-mouse-cli/src/lib.rs +++ b/lan-mouse-cli/src/lib.rs @@ -30,7 +30,6 @@ pub fn run() -> Result<(), IpcError> { struct Cli { clients: Vec<(ClientHandle, ClientConfig, ClientState)>, - changed: Option, rx: AsyncFrontendEventReader, tx: AsyncFrontendRequestWriter, } @@ -39,7 +38,6 @@ impl Cli { fn new(rx: AsyncFrontendEventReader, tx: AsyncFrontendRequestWriter) -> Cli { Self { clients: vec![], - changed: None, rx, tx, } @@ -87,23 +85,9 @@ impl Cli { } } } - if let Some(handle) = self.changed.take() { - self.update_client(handle).await?; - } } } - async fn update_client(&mut self, handle: ClientHandle) -> Result<(), IpcError> { - self.tx.request(FrontendRequest::GetState(handle)).await?; - while let Some(Ok(event)) = self.rx.next().await { - self.handle_event(event.clone()); - if let FrontendEvent::State(_, _, _) | FrontendEvent::NoSuchClient(_) = event { - break; - } - } - Ok(()) - } - async fn execute(&mut self, cmd: Command) -> Result<(), IpcError> { match cmd { Command::None => {} @@ -131,7 +115,6 @@ impl Cli { ] { self.tx.request(request).await?; } - self.update_client(handle).await?; } Command::Disconnect(id) => { self.tx.request(FrontendRequest::Delete(id)).await?; @@ -147,13 +130,11 @@ impl Cli { } Command::Activate(id) => { self.tx.request(FrontendRequest::Activate(id, true)).await?; - self.update_client(id).await?; } Command::Deactivate(id) => { self.tx .request(FrontendRequest::Activate(id, false)) .await?; - self.update_client(id).await?; } Command::List => { self.tx.request(FrontendRequest::Enumerate()).await?; @@ -168,12 +149,10 @@ impl Cli { Command::SetHost(handle, host) => { let request = FrontendRequest::UpdateHostname(handle, Some(host.clone())); self.tx.request(request).await?; - self.update_client(handle).await?; } Command::SetPort(handle, port) => { let request = FrontendRequest::UpdatePort(handle, port.unwrap_or(DEFAULT_PORT)); self.tx.request(request).await?; - self.update_client(handle).await?; } Command::Help => { for cmd_type in [ @@ -209,7 +188,6 @@ impl Cli { fn handle_event(&mut self, event: FrontendEvent) { match event { - FrontendEvent::Changed(h) => self.changed = Some(h), FrontendEvent::Created(h, c, s) => { eprint!("client added ({h}): "); print_config(&c); diff --git a/lan-mouse-gtk/resources/client_row.ui b/lan-mouse-gtk/resources/client_row.ui index 7ef7219..70d439b 100644 --- a/lan-mouse-gtk/resources/client_row.ui +++ b/lan-mouse-gtk/resources/client_row.ui @@ -5,7 +5,7 @@ - + center end enable @@ -68,6 +68,7 @@ + diff --git a/lan-mouse-gtk/src/client_object/imp.rs b/lan-mouse-gtk/src/client_object/imp.rs index fbcd5db..a3f37f6 100644 --- a/lan-mouse-gtk/src/client_object/imp.rs +++ b/lan-mouse-gtk/src/client_object/imp.rs @@ -1,3 +1,4 @@ +use std::cell::Cell; use std::cell::RefCell; use glib::Properties; @@ -20,6 +21,7 @@ pub struct ClientObject { #[property(name = "resolving", get, set, type = bool, member = resolving)] #[property(name = "ips", get, set, type = Vec, member = ips)] pub data: RefCell, + pub ignore_next_update: Cell, } #[glib::object_subclass] diff --git a/lan-mouse-gtk/src/client_row.rs b/lan-mouse-gtk/src/client_row.rs index bcbad7e..6fa608a 100644 --- a/lan-mouse-gtk/src/client_row.rs +++ b/lan-mouse-gtk/src/client_row.rs @@ -22,18 +22,19 @@ impl ClientRow { pub fn bind(&self, client_object: &ClientObject) { let mut bindings = self.imp().bindings.borrow_mut(); + // bind client active to switch state let active_binding = client_object .bind_property("active", &self.imp().enable_switch.get(), "state") - .bidirectional() .sync_create() .build(); + // bind client active to switch position let switch_position_binding = client_object .bind_property("active", &self.imp().enable_switch.get(), "active") - .bidirectional() .sync_create() .build(); + // bind hostname to hostname edit field let hostname_binding = client_object .bind_property("hostname", &self.imp().hostname.get(), "text") .transform_to(|_, v: Option| { @@ -43,17 +44,10 @@ impl ClientRow { Some("".to_string()) } }) - .transform_from(|_, v: String| { - if v.as_str().trim() == "" { - Some(None) - } else { - Some(Some(v)) - } - }) - .bidirectional() .sync_create() .build(); + // bind hostname to title let title_binding = client_object .bind_property("hostname", self, "title") .transform_to(|_, v: Option| { @@ -66,49 +60,38 @@ impl ClientRow { .sync_create() .build(); + // bind port to port edit field let port_binding = client_object .bind_property("port", &self.imp().port.get(), "text") - .transform_from(|_, v: String| { - if v.is_empty() { - Some(DEFAULT_PORT as u32) - } else { - Some(v.parse::().unwrap_or(DEFAULT_PORT) as u32) - } - }) .transform_to(|_, v: u32| { - if v == 4242 { + if v == DEFAULT_PORT as u32 { Some("".to_string()) } else { Some(v.to_string()) } }) - .bidirectional() .sync_create() .build(); + // bind port to subtitle let subtitle_binding = client_object .bind_property("port", self, "subtitle") .sync_create() .build(); + // bind position to selected position 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_to(|_, v: String| match v.as_str() { - "right" => Some(1), + "right" => Some(1u32), "top" => Some(2u32), "bottom" => Some(3u32), _ => Some(0u32), }) - .bidirectional() .sync_create() .build(); + // bind resolving status to spinner visibility let resolve_binding = client_object .bind_property( "resolving", @@ -118,6 +101,7 @@ impl ClientRow { .sync_create() .build(); + // bind ips to tooltip-text let ip_binding = client_object .bind_property("ips", &self.imp().dns_button.get(), "tooltip-text") .transform_to(|_, ips: Vec| { diff --git a/lan-mouse-gtk/src/client_row/imp.rs b/lan-mouse-gtk/src/client_row/imp.rs index 1e8b711..549b0ea 100644 --- a/lan-mouse-gtk/src/client_row/imp.rs +++ b/lan-mouse-gtk/src/client_row/imp.rs @@ -5,7 +5,7 @@ use adw::{prelude::*, ActionRow, ComboRow}; use glib::{subclass::InitializingObject, Binding}; use gtk::glib::clone; use gtk::glib::subclass::Signal; -use gtk::{glib, Button, CompositeTemplate, Switch}; +use gtk::{glib, Button, CompositeTemplate, Entry, Switch}; use std::sync::OnceLock; #[derive(CompositeTemplate, Default)] @@ -59,17 +59,33 @@ impl ObjectImpl for ClientRow { row.handle_client_delete(button); } )); + self.hostname.connect_changed(clone!( + #[weak(rename_to = row)] + self, + move |entry| { + row.handle_hostname_changed(entry); + } + )); } fn signals() -> &'static [glib::subclass::Signal] { static SIGNALS: OnceLock> = OnceLock::new(); SIGNALS.get_or_init(|| { vec![ - Signal::builder("request-dns").build(), - Signal::builder("request-update") + Signal::builder("request-activate") .param_types([bool::static_type()]) .build(), Signal::builder("request-delete").build(), + Signal::builder("request-dns").build(), + Signal::builder("request-hostname-change") + .param_types([String::static_type()]) + .build(), + Signal::builder("request-port-change") + .param_types([u32::static_type()]) + .build(), + Signal::builder("request-position-change") + .param_types([u32::static_type()]) + .build(), ] }) } @@ -78,22 +94,40 @@ impl ObjectImpl for ClientRow { #[gtk::template_callbacks] impl ClientRow { #[template_callback] - fn handle_client_set_state(&self, state: bool, _switch: &Switch) -> bool { - log::debug!("state change -> requesting update"); - self.obj().emit_by_name::<()>("request-update", &[&state]); + fn handle_activate_switch(&self, state: bool, _switch: &Switch) -> bool { + self.obj().emit_by_name::<()>("request-activate", &[&state]); true // dont run default handler } #[template_callback] - fn handle_request_dns(&self, _: Button) { + fn handle_request_dns(&self, _: &Button) { self.obj().emit_by_name::<()>("request-dns", &[]); } #[template_callback] fn handle_client_delete(&self, _button: &Button) { - log::debug!("delete button pressed -> requesting delete"); self.obj().emit_by_name::<()>("request-delete", &[]); } + + #[template_callback] + fn handle_port_changed(&self) { + if let Ok(port) = self.port.text().parse::() { + self.obj() + .emit_by_name::<()>("request-port-change", &[&(port as u32)]); + } + } + + // #[template_callback] + fn handle_hostname_changed(&self, entry: &Entry) { + self.obj() + .emit_by_name::<()>("request-hostname-change", &[&entry.text()]); + } + + #[template_callback] + fn handle_position_changed(&self) { + self.obj() + .emit_by_name("request-position-change", &[&self.position.selected()]) + } } impl WidgetImpl for ClientRow {} diff --git a/lan-mouse-gtk/src/lib.rs b/lan-mouse-gtk/src/lib.rs index 2469c57..75199b5 100644 --- a/lan-mouse-gtk/src/lib.rs +++ b/lan-mouse-gtk/src/lib.rs @@ -9,7 +9,7 @@ use std::{env, process, str}; use window::Window; -use lan_mouse_ipc::{FrontendEvent, FrontendRequest}; +use lan_mouse_ipc::FrontendEvent; use adw::Application; use gtk::{ @@ -127,9 +127,6 @@ fn build_ui(app: &Application) { loop { let notify = receiver.recv().await.unwrap_or_else(|_| process::exit(1)); match notify { - FrontendEvent::Changed(handle) => { - window.request(FrontendRequest::GetState(handle)); - } FrontendEvent::Created(handle, client, state) => { window.new_client(handle, client, state); } diff --git a/lan-mouse-gtk/src/window.rs b/lan-mouse-gtk/src/window.rs index 8be703a..837947c 100644 --- a/lan-mouse-gtk/src/window.rs +++ b/lan-mouse-gtk/src/window.rs @@ -112,16 +112,54 @@ impl Window { .expect("Expected object of type `ClientObject`."); let row = window.create_client_row(client_object); row.connect_closure( - "request-update", + "request-hostname-change", + false, + closure_local!( + #[strong] + window, + move |row: ClientRow, hostname: String| { + if let Some(client) = window.client_by_idx(row.index() as u32) { + let hostname = Some(hostname).filter(|s| !s.is_empty()); + window.request(FrontendRequest::UpdateHostname( + client.handle(), + hostname, + )); + } + } + ), + ); + row.connect_closure( + "request-port-change", + false, + closure_local!( + #[strong] + window, + move |row: ClientRow, port: u32| { + if let Some(client) = window.client_by_idx(row.index() as u32) { + window.request(FrontendRequest::UpdatePort( + client.handle(), + port as u16, + )); + } + } + ), + ); + row.connect_closure( + "request-activate", false, closure_local!( #[strong] window, move |row: ClientRow, active: bool| { if let Some(client) = window.client_by_idx(row.index() as u32) { - window.request_client_activate(&client, active); - window.request_client_update(&client); - window.request_client_state(&client); + log::info!( + "request: {} client", + if active { "activating" } else { "deactivating" } + ); + window.request(FrontendRequest::Activate( + client.handle(), + active, + )); } } ), @@ -134,7 +172,7 @@ impl Window { window, move |row: ClientRow| { if let Some(client) = window.client_by_idx(row.index() as u32) { - window.request_client_delete(&client); + window.request(FrontendRequest::Delete(client.handle())); } } ), @@ -147,9 +185,31 @@ impl Window { window, move |row: ClientRow| { if let Some(client) = window.client_by_idx(row.index() as u32) { - window.request_client_update(&client); - window.request_dns(&client); - window.request_client_state(&client); + window.request(FrontendRequest::ResolveDns( + client.get_data().handle, + )); + } + } + ), + ); + row.connect_closure( + "request-position-change", + false, + closure_local!( + #[strong] + window, + move |row: ClientRow, pos_idx: u32| { + if let Some(client) = window.client_by_idx(row.index() as u32) { + let position = match pos_idx { + 0 => Position::Left, + 1 => Position::Right, + 2 => Position::Top, + _ => Position::Bottom, + }; + window.request(FrontendRequest::UpdatePosition( + client.handle(), + position, + )); } } ), @@ -257,15 +317,11 @@ impl Window { let client_object: &ClientObject = client_object.downcast_ref().unwrap(); let data = client_object.get_data(); - if state.active != data.active { - client_object.set_active(state.active); - log::debug!("set active to {}", state.active); - } + client_object.set_active(state.active); + log::info!("set active to {}", state.active); - if state.resolving != data.resolving { - client_object.set_resolving(state.resolving); - log::debug!("resolving {}: {}", data.handle, state.resolving); - } + client_object.set_resolving(state.resolving); + log::info!("resolving {}: {}", data.handle, state.resolving); self.update_dns_state(handle, !state.ips.is_empty()); let ips = state @@ -291,7 +347,7 @@ impl Window { } } - pub fn request_port_change(&self) { + fn request_port_change(&self) { let port = self .imp() .port_entry @@ -303,54 +359,18 @@ impl Window { self.request(FrontendRequest::ChangePort(port)); } - pub fn request_capture(&self) { + fn request_capture(&self) { self.request(FrontendRequest::EnableCapture); } - pub fn request_emulation(&self) { + fn request_emulation(&self) { self.request(FrontendRequest::EnableEmulation); } - pub fn request_client_state(&self, client: &ClientObject) { - self.request_client_state_for(client.handle()); - } - - pub fn request_client_state_for(&self, handle: ClientHandle) { - self.request(FrontendRequest::GetState(handle)); - } - - pub fn request_client_create(&self) { + fn request_client_create(&self) { self.request(FrontendRequest::Create); } - pub fn request_dns(&self, client: &ClientObject) { - self.request(FrontendRequest::ResolveDns(client.get_data().handle)); - } - - pub fn request_client_update(&self, client: &ClientObject) { - let handle = client.handle(); - let data = client.get_data(); - let position = Position::try_from(data.position.as_str()).expect("invalid position"); - let hostname = data.hostname; - let port = data.port as u16; - - for event in [ - FrontendRequest::UpdateHostname(handle, hostname), - FrontendRequest::UpdatePosition(handle, position), - FrontendRequest::UpdatePort(handle, port), - ] { - self.request(event); - } - } - - pub fn request_client_activate(&self, client: &ClientObject, active: bool) { - self.request(FrontendRequest::Activate(client.handle(), active)); - } - - pub fn request_client_delete(&self, client: &ClientObject) { - self.request(FrontendRequest::Delete(client.handle())); - } - pub fn open_fingerprint_dialog(&self) { let window = FingerprintWindow::new(); window.set_transient_for(Some(self)); diff --git a/lan-mouse-ipc/src/lib.rs b/lan-mouse-ipc/src/lib.rs index 7c2a51b..0d0b87c 100644 --- a/lan-mouse-ipc/src/lib.rs +++ b/lan-mouse-ipc/src/lib.rs @@ -177,8 +177,6 @@ pub struct ClientState { #[derive(Debug, Clone, Serialize, Deserialize)] pub enum FrontendEvent { - /// client state has changed, new state must be requested via [`FrontendRequest::GetState`] - Changed(ClientHandle), /// a client was created Created(ClientHandle, ClientConfig, ClientState), /// no such client @@ -229,8 +227,6 @@ pub enum FrontendRequest { UpdatePosition(ClientHandle, Position), /// update fix-ips UpdateFixIps(ClientHandle, Vec), - /// request the state of the given client - GetState(ClientHandle), /// request reenabling input capture EnableCapture, /// request reenabling input emulation diff --git a/src/service.rs b/src/service.rs index 2717649..ce08a0c 100644 --- a/src/service.rs +++ b/src/service.rs @@ -186,7 +186,6 @@ impl Service { FrontendRequest::EnableCapture => self.capture.reenable(), FrontendRequest::EnableEmulation => self.emulation.reenable(), FrontendRequest::Enumerate() => self.enumerate(), - FrontendRequest::GetState(handle) => self.broadcast_client(handle), FrontendRequest::UpdateFixIps(handle, fix_ips) => self.update_fix_ips(handle, fix_ips), FrontendRequest::UpdateHostname(handle, host) => self.update_hostname(handle, host), FrontendRequest::UpdatePort(handle, port) => self.update_port(handle, port), @@ -283,7 +282,7 @@ impl Service { handle } }; - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); } fn resolve(&self, handle: ClientHandle) { @@ -399,7 +398,7 @@ impl Service { log::debug!("deactivating client {handle}"); if self.client_manager.deactivate_client(handle) { self.capture.destroy(handle); - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); log::info!("deactivated client {handle}"); } } @@ -425,7 +424,7 @@ impl Service { if self.client_manager.activate_client(handle) { /* notify capture and frontends */ self.capture.create(handle, pos, CaptureType::Default); - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); log::info!("activated client {handle} ({pos})"); } } @@ -452,19 +451,19 @@ impl Service { fn update_fix_ips(&mut self, handle: ClientHandle, fix_ips: Vec) { self.client_manager.set_fix_ips(handle, fix_ips); - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); } fn update_hostname(&mut self, handle: ClientHandle, hostname: Option) { if self.client_manager.set_hostname(handle, hostname.clone()) { self.resolve(handle); } - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); } fn update_port(&mut self, handle: ClientHandle, port: u16) { self.client_manager.set_port(handle, port); - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); } fn update_pos(&mut self, handle: ClientHandle, pos: Position) { @@ -473,7 +472,7 @@ impl Service { self.deactivate_client(handle); self.activate_client(handle); } - self.notify_frontend(FrontendEvent::Changed(handle)); + self.broadcast_client(handle); } fn broadcast_client(&mut self, handle: ClientHandle) {