mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-07 09:21:28 +03:00
properly synchronize frontend
This commit is contained in:
@@ -5,7 +5,6 @@
|
|||||||
<!-- enabled -->
|
<!-- enabled -->
|
||||||
<child type="prefix">
|
<child type="prefix">
|
||||||
<object class="GtkSwitch" id="enable_switch">
|
<object class="GtkSwitch" id="enable_switch">
|
||||||
<signal name="state_set" handler="handle_activate_switch" swapped="true"/>
|
|
||||||
<property name="valign">center</property>
|
<property name="valign">center</property>
|
||||||
<property name="halign">end</property>
|
<property name="halign">end</property>
|
||||||
<property name="tooltip-text" translatable="yes">enable</property>
|
<property name="tooltip-text" translatable="yes">enable</property>
|
||||||
@@ -68,7 +67,6 @@
|
|||||||
</items>
|
</items>
|
||||||
</object>
|
</object>
|
||||||
</property>
|
</property>
|
||||||
<signal name="notify::selected" handler="handle_position_changed" swapped="true"/>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<!-- delete button -->
|
<!-- delete button -->
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use std::cell::Cell;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use glib::Properties;
|
use glib::Properties;
|
||||||
@@ -21,7 +20,6 @@ pub struct ClientObject {
|
|||||||
#[property(name = "resolving", get, set, type = bool, member = resolving)]
|
#[property(name = "resolving", get, set, type = bool, member = resolving)]
|
||||||
#[property(name = "ips", get, set, type = Vec<String>, member = ips)]
|
#[property(name = "ips", get, set, type = Vec<String>, member = ips)]
|
||||||
pub data: RefCell<ClientData>,
|
pub data: RefCell<ClientData>,
|
||||||
pub ignore_next_update: Cell<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use std::cell::RefCell;
|
|||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use adw::{prelude::*, ActionRow, ComboRow};
|
use adw::{prelude::*, ActionRow, ComboRow};
|
||||||
use glib::{subclass::InitializingObject, Binding};
|
use glib::{subclass::InitializingObject, Binding};
|
||||||
use gtk::glib::clone;
|
|
||||||
use gtk::glib::subclass::Signal;
|
use gtk::glib::subclass::Signal;
|
||||||
|
use gtk::glib::{clone, SignalHandlerId};
|
||||||
use gtk::{glib, Button, CompositeTemplate, Entry, Switch};
|
use gtk::{glib, Button, CompositeTemplate, Entry, Switch};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
@@ -28,6 +28,10 @@ pub struct ClientRow {
|
|||||||
#[template_child]
|
#[template_child]
|
||||||
pub dns_loading_indicator: TemplateChild<gtk::Spinner>,
|
pub dns_loading_indicator: TemplateChild<gtk::Spinner>,
|
||||||
pub bindings: RefCell<Vec<Binding>>,
|
pub bindings: RefCell<Vec<Binding>>,
|
||||||
|
pub hostname_change_handler: RefCell<Option<SignalHandlerId>>,
|
||||||
|
pub port_change_handler: RefCell<Option<SignalHandlerId>>,
|
||||||
|
pub position_change_handler: RefCell<Option<SignalHandlerId>>,
|
||||||
|
pub set_state_handler: RefCell<Option<SignalHandlerId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
@@ -59,13 +63,42 @@ impl ObjectImpl for ClientRow {
|
|||||||
row.handle_client_delete(button);
|
row.handle_client_delete(button);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
self.hostname.connect_changed(clone!(
|
let handler = self.hostname.connect_changed(clone!(
|
||||||
#[weak(rename_to = row)]
|
#[weak(rename_to = row)]
|
||||||
self,
|
self,
|
||||||
move |entry| {
|
move |entry| {
|
||||||
row.handle_hostname_changed(entry);
|
row.handle_hostname_changed(entry);
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
self.hostname_change_handler.replace(Some(handler));
|
||||||
|
let handler = self.port.connect_changed(clone!(
|
||||||
|
#[weak(rename_to = row)]
|
||||||
|
self,
|
||||||
|
move |entry| {
|
||||||
|
row.handle_port_changed(entry);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
self.port_change_handler.replace(Some(handler));
|
||||||
|
let handler = self.position.connect_selected_notify(clone!(
|
||||||
|
#[weak(rename_to = row)]
|
||||||
|
self,
|
||||||
|
move |position| {
|
||||||
|
row.handle_position_changed(position);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
self.position_change_handler.replace(Some(handler));
|
||||||
|
// <signal name="state_set" handler="handle_activate_switch" swapped="true"/>
|
||||||
|
let handler = self.enable_switch.connect_state_set(clone!(
|
||||||
|
#[weak(rename_to = row)]
|
||||||
|
self,
|
||||||
|
#[upgrade_or]
|
||||||
|
glib::Propagation::Proceed,
|
||||||
|
move |switch, state| {
|
||||||
|
row.handle_activate_switch(state, switch);
|
||||||
|
glib::Propagation::Proceed
|
||||||
|
}
|
||||||
|
));
|
||||||
|
self.set_state_handler.replace(Some(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signals() -> &'static [glib::subclass::Signal] {
|
fn signals() -> &'static [glib::subclass::Signal] {
|
||||||
@@ -109,24 +142,70 @@ impl ClientRow {
|
|||||||
self.obj().emit_by_name::<()>("request-delete", &[]);
|
self.obj().emit_by_name::<()>("request-delete", &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
fn handle_port_changed(&self, port_entry: &Entry) {
|
||||||
fn handle_port_changed(&self) {
|
if let Ok(port) = port_entry.text().parse::<u16>() {
|
||||||
if let Ok(port) = self.port.text().parse::<u16>() {
|
|
||||||
self.obj()
|
self.obj()
|
||||||
.emit_by_name::<()>("request-port-change", &[&(port as u32)]);
|
.emit_by_name::<()>("request-port-change", &[&(port as u32)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[template_callback]
|
fn handle_hostname_changed(&self, hostname_entry: &Entry) {
|
||||||
fn handle_hostname_changed(&self, entry: &Entry) {
|
log::error!("hostname changed: {}", hostname_entry.text());
|
||||||
self.obj()
|
self.obj()
|
||||||
.emit_by_name::<()>("request-hostname-change", &[&entry.text()]);
|
.emit_by_name::<()>("request-hostname-change", &[&hostname_entry.text()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
fn handle_position_changed(&self, position: &ComboRow) {
|
||||||
fn handle_position_changed(&self) {
|
|
||||||
self.obj()
|
self.obj()
|
||||||
.emit_by_name("request-position-change", &[&self.position.selected()])
|
.emit_by_name("request-position-change", &[&position.selected()])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_hostname_change(&self) {
|
||||||
|
let handler = self.hostname_change_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.hostname.block_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock_hostname_change(&self) {
|
||||||
|
let handler = self.hostname_change_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.hostname.unblock_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_port_change(&self) {
|
||||||
|
let handler = self.port_change_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.port.block_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock_port_change(&self) {
|
||||||
|
let handler = self.port_change_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.port.unblock_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_position_change(&self) {
|
||||||
|
let handler = self.position_change_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.position.block_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock_position_change(&self) {
|
||||||
|
let handler = self.position_change_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.position.unblock_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn block_active_switch(&self) {
|
||||||
|
let handler = self.set_state_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.enable_switch.block_signal(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unblock_active_switch(&self) {
|
||||||
|
let handler = self.set_state_handler.borrow();
|
||||||
|
let handler = handler.as_ref().expect("signal handler");
|
||||||
|
self.enable_switch.unblock_signal(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use glib::{clone, Object};
|
|||||||
use gtk::{
|
use gtk::{
|
||||||
gio,
|
gio,
|
||||||
glib::{self, closure_local},
|
glib::{self, closure_local},
|
||||||
ListBox, NoSelection,
|
NoSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
use lan_mouse_ipc::{
|
use lan_mouse_ipc::{
|
||||||
@@ -58,6 +58,14 @@ impl Window {
|
|||||||
self.clients().item(idx).map(|o| o.downcast().unwrap())
|
self.clients().item(idx).map(|o| o.downcast().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn row_by_idx(&self, idx: i32) -> Option<ClientRow> {
|
||||||
|
self.imp()
|
||||||
|
.client_list
|
||||||
|
.get()
|
||||||
|
.row_at_index(idx)
|
||||||
|
.map(|o| o.downcast().expect("expected ClientRow"))
|
||||||
|
}
|
||||||
|
|
||||||
fn authorized_by_idx(&self, idx: u32) -> Option<KeyObject> {
|
fn authorized_by_idx(&self, idx: u32) -> Option<KeyObject> {
|
||||||
self.authorized().item(idx).map(|o| o.downcast().unwrap())
|
self.authorized().item(idx).map(|o| o.downcast().unwrap())
|
||||||
}
|
}
|
||||||
@@ -118,8 +126,11 @@ impl Window {
|
|||||||
#[strong]
|
#[strong]
|
||||||
window,
|
window,
|
||||||
move |row: ClientRow, hostname: String| {
|
move |row: ClientRow, hostname: String| {
|
||||||
|
log::info!("request-hostname-change");
|
||||||
if let Some(client) = window.client_by_idx(row.index() as u32) {
|
if let Some(client) = window.client_by_idx(row.index() as u32) {
|
||||||
let hostname = Some(hostname).filter(|s| !s.is_empty());
|
let hostname = Some(hostname).filter(|s| !s.is_empty());
|
||||||
|
/* changed in response to FrontendEvent
|
||||||
|
* -> do not request additional update */
|
||||||
window.request(FrontendRequest::UpdateHostname(
|
window.request(FrontendRequest::UpdateHostname(
|
||||||
client.handle(),
|
client.handle(),
|
||||||
hostname,
|
hostname,
|
||||||
@@ -264,14 +275,10 @@ impl Window {
|
|||||||
self.update_dns_state(handle, !state.ips.is_empty());
|
self.update_dns_state(handle, !state.ips.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn client_idx(&self, handle: ClientHandle) -> Option<usize> {
|
pub(super) fn client_idx(&self, handle: ClientHandle) -> Option<usize> {
|
||||||
self.clients().iter::<ClientObject>().position(|c| {
|
self.clients()
|
||||||
if let Ok(c) = c {
|
.iter::<ClientObject>()
|
||||||
c.handle() == handle
|
.position(|c| c.ok().map(|c| c.handle() == handle).unwrap_or_default())
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_client(&self, handle: ClientHandle) {
|
pub fn delete_client(&self, handle: ClientHandle) {
|
||||||
@@ -287,41 +294,51 @@ impl Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_client_config(&self, handle: ClientHandle, client: ClientConfig) {
|
pub fn update_client_config(&self, handle: ClientHandle, client: ClientConfig) {
|
||||||
let Some(idx) = self.client_idx(handle) else {
|
let Some(row) = self.row_for_handle(handle) else {
|
||||||
log::warn!("could not find client with handle {}", handle);
|
log::warn!("could not find row for handle {}", handle);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(client_object) = self.client_object_for_handle(handle) else {
|
||||||
|
log::warn!("could not find row for handle {}", handle);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let client_object = self.clients().item(idx as u32).unwrap();
|
|
||||||
let client_object: &ClientObject = client_object.downcast_ref().unwrap();
|
|
||||||
let data = client_object.get_data();
|
|
||||||
|
|
||||||
/* only change if it actually has changed, otherwise
|
row.imp().block_hostname_change();
|
||||||
* the update signal is triggered */
|
client_object.set_hostname(client.hostname.unwrap_or("".into()));
|
||||||
if data.hostname != client.hostname {
|
row.imp().unblock_hostname_change();
|
||||||
client_object.set_hostname(client.hostname.unwrap_or("".into()));
|
|
||||||
}
|
row.imp().block_port_change();
|
||||||
if data.port != client.port as u32 {
|
client_object.set_port(client.port as u32);
|
||||||
client_object.set_port(client.port as u32);
|
row.imp().unblock_port_change();
|
||||||
}
|
|
||||||
if data.position != client.pos.to_string() {
|
row.imp().block_position_change();
|
||||||
client_object.set_position(client.pos.to_string());
|
client_object.set_position(client.pos.to_string());
|
||||||
}
|
row.imp().unblock_position_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_client_state(&self, handle: ClientHandle, state: ClientState) {
|
pub fn update_client_state(&self, handle: ClientHandle, state: ClientState) {
|
||||||
let Some(idx) = self.client_idx(handle) else {
|
let Some(row) = self.row_for_handle(handle) else {
|
||||||
log::warn!("could not find client with handle {}", handle);
|
log::warn!("could not find row for handle {}", handle);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(client_object) = self.client_object_for_handle(handle) else {
|
||||||
|
log::warn!("could not find row for handle {}", handle);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let client_object = self.clients().item(idx as u32).unwrap();
|
|
||||||
let client_object: &ClientObject = client_object.downcast_ref().unwrap();
|
|
||||||
let data = client_object.get_data();
|
|
||||||
|
|
||||||
|
/* activation state */
|
||||||
|
row.imp().block_active_switch();
|
||||||
client_object.set_active(state.active);
|
client_object.set_active(state.active);
|
||||||
|
row.imp().unblock_active_switch();
|
||||||
log::info!("set active to {}", state.active);
|
log::info!("set active to {}", state.active);
|
||||||
|
|
||||||
|
/* dns state */
|
||||||
client_object.set_resolving(state.resolving);
|
client_object.set_resolving(state.resolving);
|
||||||
log::info!("resolving {}: {}", data.handle, state.resolving);
|
log::info!(
|
||||||
|
"resolving {}: {}",
|
||||||
|
client_object.get_data().handle,
|
||||||
|
state.resolving
|
||||||
|
);
|
||||||
|
|
||||||
self.update_dns_state(handle, !state.ips.is_empty());
|
self.update_dns_state(handle, !state.ips.is_empty());
|
||||||
let ips = state
|
let ips = state
|
||||||
@@ -332,18 +349,25 @@ impl Window {
|
|||||||
client_object.set_ips(ips);
|
client_object.set_ips(ips);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_dns_state(&self, handle: ClientHandle, resolved: bool) {
|
fn client_object_for_handle(&self, handle: ClientHandle) -> Option<ClientObject> {
|
||||||
let Some(idx) = self.client_idx(handle) else {
|
self.client_idx(handle)
|
||||||
log::warn!("could not find client with handle {}", handle);
|
.map(|i| self.client_by_idx(i as u32))
|
||||||
return;
|
.flatten()
|
||||||
};
|
}
|
||||||
let list_box: ListBox = self.imp().client_list.get();
|
|
||||||
let row = list_box.row_at_index(idx as i32).unwrap();
|
fn row_for_handle(&self, handle: ClientHandle) -> Option<ClientRow> {
|
||||||
let client_row: ClientRow = row.downcast().expect("expected ClientRow Object");
|
self.client_idx(handle)
|
||||||
if resolved {
|
.map(|i| self.row_by_idx(i as i32))
|
||||||
client_row.imp().dns_button.set_css_classes(&["success"])
|
.flatten()
|
||||||
} else {
|
}
|
||||||
client_row.imp().dns_button.set_css_classes(&["warning"])
|
|
||||||
|
fn update_dns_state(&self, handle: ClientHandle, resolved: bool) {
|
||||||
|
if let Some(client_row) = self.row_for_handle(handle) {
|
||||||
|
if resolved {
|
||||||
|
client_row.imp().dns_button.set_css_classes(&["success"])
|
||||||
|
} else {
|
||||||
|
client_row.imp().dns_button.set_css_classes(&["warning"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -455,6 +455,7 @@ impl Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_hostname(&mut self, handle: ClientHandle, hostname: Option<String>) {
|
fn update_hostname(&mut self, handle: ClientHandle, hostname: Option<String>) {
|
||||||
|
log::info!("hostname changed: {hostname:?}");
|
||||||
if self.client_manager.set_hostname(handle, hostname.clone()) {
|
if self.client_manager.set_hostname(handle, hostname.clone()) {
|
||||||
self.resolve(handle);
|
self.resolve(handle);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user