mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-04 07:51:27 +03:00
Activate on startup (#70)
Frontends are now properly synced among each other and on startup the correct state is reflected. Closes #75 Closes #68
This commit is contained in:
committed by
GitHub
parent
2e52660714
commit
d90eb0cd0f
@@ -3,26 +3,20 @@ mod imp;
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::glib::{self, Object};
|
||||
|
||||
use crate::client::ClientHandle;
|
||||
use crate::client::{Client, ClientHandle};
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct ClientObject(ObjectSubclass<imp::ClientObject>);
|
||||
}
|
||||
|
||||
impl ClientObject {
|
||||
pub fn new(
|
||||
handle: ClientHandle,
|
||||
hostname: Option<String>,
|
||||
port: u32,
|
||||
position: String,
|
||||
active: bool,
|
||||
) -> Self {
|
||||
pub fn new(client: Client, active: bool) -> Self {
|
||||
Object::builder()
|
||||
.property("handle", handle)
|
||||
.property("hostname", hostname)
|
||||
.property("port", port)
|
||||
.property("handle", client.handle)
|
||||
.property("hostname", client.hostname)
|
||||
.property("port", client.port as u32)
|
||||
.property("position", client.pos.to_string())
|
||||
.property("active", active)
|
||||
.property("position", position)
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ impl ClientRow {
|
||||
.sync_create()
|
||||
.build();
|
||||
|
||||
let switch_position_binding = client_object
|
||||
.bind_property("active", &self.imp().enable_switch.get(), "active")
|
||||
.bidirectional()
|
||||
.sync_create()
|
||||
.build();
|
||||
|
||||
let hostname_binding = client_object
|
||||
.bind_property("hostname", &self.imp().hostname.get(), "text")
|
||||
.transform_to(|_, v: Option<String>| {
|
||||
@@ -104,6 +110,7 @@ impl ClientRow {
|
||||
.build();
|
||||
|
||||
bindings.push(active_binding);
|
||||
bindings.push(switch_position_binding);
|
||||
bindings.push(hostname_binding);
|
||||
bindings.push(title_binding);
|
||||
bindings.push(port_binding);
|
||||
|
||||
@@ -4,6 +4,8 @@ use adw::subclass::prelude::*;
|
||||
use adw::{prelude::*, ActionRow, ComboRow};
|
||||
use glib::{subclass::InitializingObject, Binding};
|
||||
use gtk::glib::clone;
|
||||
use gtk::glib::once_cell::sync::Lazy;
|
||||
use gtk::glib::subclass::Signal;
|
||||
use gtk::{glib, Button, CompositeTemplate, Switch};
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
@@ -28,6 +30,8 @@ pub struct ClientRow {
|
||||
impl ObjectSubclass for ClientRow {
|
||||
// `NAME` needs to match `class` attribute of template
|
||||
const NAME: &'static str = "ClientRow";
|
||||
const ABSTRACT: bool = false;
|
||||
|
||||
type Type = super::ClientRow;
|
||||
type ParentType = adw::ExpanderRow;
|
||||
|
||||
@@ -49,28 +53,33 @@ impl ObjectImpl for ClientRow {
|
||||
row.handle_client_delete(button);
|
||||
}));
|
||||
}
|
||||
|
||||
fn signals() -> &'static [glib::subclass::Signal] {
|
||||
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||
vec![
|
||||
Signal::builder("request-update")
|
||||
.param_types([bool::static_type()])
|
||||
.build(),
|
||||
Signal::builder("request-delete").build(),
|
||||
]
|
||||
});
|
||||
SIGNALS.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[gtk::template_callbacks]
|
||||
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.set_state(state);
|
||||
|
||||
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]);
|
||||
true // dont run default handler
|
||||
}
|
||||
|
||||
#[template_callback]
|
||||
fn handle_client_delete(&self, button: &Button) {
|
||||
log::debug!("delete button pressed");
|
||||
let idx = self.obj().index() as u32;
|
||||
button
|
||||
.activate_action("win.request-client-delete", Some(&idx.to_variant()))
|
||||
.unwrap();
|
||||
fn handle_client_delete(&self, _button: &Button) {
|
||||
log::debug!("delete button pressed -> requesting delete");
|
||||
self.obj().emit_by_name::<()>("request-delete", &[]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,14 @@ use std::io::Write;
|
||||
use adw::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use glib::{clone, Object};
|
||||
use gtk::{gio, glib, NoSelection};
|
||||
use gtk::{
|
||||
gio,
|
||||
glib::{self, closure_local},
|
||||
NoSelection,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
client::{ClientHandle, Position},
|
||||
client::{Client, ClientHandle, Position},
|
||||
config::DEFAULT_PORT,
|
||||
frontend::{gtk::client_object::ClientObject, FrontendEvent},
|
||||
};
|
||||
@@ -45,6 +49,18 @@ impl Window {
|
||||
clone!(@weak self as window => @default-panic, move |obj| {
|
||||
let client_object = obj.downcast_ref().expect("Expected object of type `ClientObject`.");
|
||||
let row = window.create_client_row(client_object);
|
||||
row.connect_closure("request-update", false, closure_local!(@strong window => move |row: ClientRow, active: bool| {
|
||||
let index = row.index() as u32;
|
||||
let Some(client) = window.clients().item(index) else {
|
||||
return;
|
||||
};
|
||||
let client = client.downcast_ref::<ClientObject>().unwrap();
|
||||
window.request_client_update(client, active);
|
||||
}));
|
||||
row.connect_closure("request-delete", false, closure_local!(@strong window => move |row: ClientRow| {
|
||||
let index = row.index() as u32;
|
||||
window.request_client_delete(index);
|
||||
}));
|
||||
row.upcast()
|
||||
})
|
||||
);
|
||||
@@ -71,15 +87,8 @@ impl Window {
|
||||
row
|
||||
}
|
||||
|
||||
pub fn new_client(
|
||||
&self,
|
||||
handle: ClientHandle,
|
||||
hostname: Option<String>,
|
||||
port: u16,
|
||||
position: Position,
|
||||
active: bool,
|
||||
) {
|
||||
let client = ClientObject::new(handle, hostname, port as u32, position.to_string(), active);
|
||||
pub fn new_client(&self, client: Client, active: bool) {
|
||||
let client = ClientObject::new(client, active);
|
||||
self.clients().append(&client);
|
||||
self.set_placeholder_visible(false);
|
||||
}
|
||||
@@ -106,6 +115,42 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_client(&self, client: Client) {
|
||||
let Some(idx) = self.client_idx(client.handle) else {
|
||||
log::warn!("could not find client with handle {}", client.handle);
|
||||
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
|
||||
* the update signal is triggered */
|
||||
if data.hostname != client.hostname {
|
||||
client_object.set_hostname(client.hostname.unwrap_or("".into()));
|
||||
}
|
||||
if data.port != client.port as u32 {
|
||||
client_object.set_port(client.port as u32);
|
||||
}
|
||||
if data.position != client.pos.to_string() {
|
||||
client_object.set_position(client.pos.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn activate_client(&self, handle: ClientHandle, active: bool) {
|
||||
let Some(idx) = self.client_idx(handle) else {
|
||||
log::warn!("could not find client with handle {handle}");
|
||||
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();
|
||||
if data.active != active {
|
||||
client_object.set_active(active);
|
||||
log::debug!("set active to {active}");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_client_create(&self) {
|
||||
let event = FrontendEvent::AddClient(None, DEFAULT_PORT, Position::default());
|
||||
self.imp().set_port(DEFAULT_PORT);
|
||||
@@ -121,13 +166,10 @@ impl Window {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_client_update(&self, client: &ClientObject) {
|
||||
pub fn request_client_update(&self, client: &ClientObject, active: bool) {
|
||||
let data = client.get_data();
|
||||
let position = match data.position.as_str() {
|
||||
"left" => Position::Left,
|
||||
"right" => Position::Right,
|
||||
"top" => Position::Top,
|
||||
"bottom" => Position::Bottom,
|
||||
let position = match Position::try_from(data.position.as_str()) {
|
||||
Ok(pos) => pos,
|
||||
_ => {
|
||||
log::error!("invalid position: {}", data.position);
|
||||
return;
|
||||
@@ -135,10 +177,13 @@ impl Window {
|
||||
};
|
||||
let hostname = data.hostname;
|
||||
let port = data.port as u16;
|
||||
|
||||
let event = FrontendEvent::UpdateClient(client.handle(), hostname, port, position);
|
||||
log::debug!("requesting update: {event:?}");
|
||||
self.request(event);
|
||||
|
||||
let event = FrontendEvent::ActivateClient(client.handle(), !client.active());
|
||||
let event = FrontendEvent::ActivateClient(client.handle(), active);
|
||||
log::debug!("requesting activate: {event:?}");
|
||||
self.request(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,7 @@ use std::net::TcpStream;
|
||||
use std::os::unix::net::UnixStream;
|
||||
|
||||
use adw::subclass::prelude::*;
|
||||
use adw::{
|
||||
prelude::{EditableExt, WidgetExt},
|
||||
ActionRow, ToastOverlay,
|
||||
};
|
||||
use adw::{prelude::*, ActionRow, ToastOverlay};
|
||||
use glib::subclass::InitializingObject;
|
||||
use gtk::{gio, glib, Button, CompositeTemplate, Entry, ListBox};
|
||||
|
||||
@@ -42,6 +39,8 @@ pub struct Window {
|
||||
impl ObjectSubclass for Window {
|
||||
// `NAME` needs to match `class` attribute of template
|
||||
const NAME: &'static str = "LanMouseWindow";
|
||||
const ABSTRACT: bool = false;
|
||||
|
||||
type Type = super::Window;
|
||||
type ParentType = adw::ApplicationWindow;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user