Skip to content

Commit

Permalink
Activate on startup (#70)
Browse files Browse the repository at this point in the history
Frontends are now properly synced among each other and on startup the correct state is reflected.

Closes #75 
Closes #68
  • Loading branch information
feschber authored Jan 16, 2024
1 parent 2e52660 commit d90eb0c
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 224 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,15 +204,15 @@ port = 4242
# define a client on the right side with host name "iridium"
[right]
# hostname
host_name = "iridium"
hostname = "iridium"
# optional list of (known) ip addresses
ips = ["192.168.178.156"]

# define a client on the left side with IP address 192.168.178.189
[left]
# The hostname is optional: When no hostname is specified,
# at least one ip address needs to be specified.
host_name = "thorium"
hostname = "thorium"
# ips for ethernet and wifi
ips = ["192.168.178.189", "192.168.178.172"]
# optional port
Expand Down
4 changes: 2 additions & 2 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ port = 4242
# define a client on the right side with host name "iridium"
[right]
# hostname
host_name = "iridium"
hostname = "iridium"
# optional list of (known) ip addresses
ips = ["192.168.178.156"]

# define a client on the left side with IP address 192.168.178.189
[left]
# The hostname is optional: When no hostname is specified,
# at least one ip address needs to be specified.
host_name = "thorium"
hostname = "thorium"
# ips for ethernet and wifi
ips = ["192.168.178.189", "192.168.178.172"]
# optional port
Expand Down
17 changes: 16 additions & 1 deletion src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ impl Display for Position {
}
}

impl TryFrom<&str> for Position {
type Error = ();

fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
"left" => Ok(Position::Left),
"right" => Ok(Position::Right),
"top" => Ok(Position::Top),
"bottom" => Ok(Position::Bottom),
_ => Err(()),
}
}
}

#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
pub struct Client {
/// hostname of this client
Expand Down Expand Up @@ -112,6 +126,7 @@ impl ClientManager {
ips: HashSet<IpAddr>,
port: u16,
pos: Position,
active: bool,
) -> ClientHandle {
// get a new client_handle
let handle = self.free_id();
Expand All @@ -135,7 +150,7 @@ impl ClientManager {
// client was never seen, nor pinged
let client_state = ClientState {
client,
active: false,
active,
active_addr: None,
alive: false,
pressed_keys: HashSet::new(),
Expand Down
42 changes: 31 additions & 11 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ pub const DEFAULT_PORT: u16 = 4242;
pub struct ConfigToml {
pub port: Option<u16>,
pub frontend: Option<String>,
pub left: Option<Client>,
pub right: Option<Client>,
pub top: Option<Client>,
pub bottom: Option<Client>,
pub left: Option<TomlClient>,
pub right: Option<TomlClient>,
pub top: Option<TomlClient>,
pub bottom: Option<TomlClient>,
}

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Client {
pub struct TomlClient {
pub hostname: Option<String>,
pub host_name: Option<String>,
pub ips: Option<Vec<IpAddr>>,
pub port: Option<u16>,
pub activate_on_startup: Option<bool>,
}

impl ConfigToml {
Expand Down Expand Up @@ -66,10 +68,18 @@ pub enum Frontend {
pub struct Config {
pub frontend: Frontend,
pub port: u16,
pub clients: Vec<(Client, Position)>,
pub clients: Vec<(TomlClient, Position)>,
pub daemon: bool,
}

pub struct ConfigClient {
pub ips: HashSet<IpAddr>,
pub hostname: Option<String>,
pub port: u16,
pub pos: Position,
pub active: bool,
}

impl Config {
pub fn new() -> Result<Self> {
let args = CliArgs::parse();
Expand Down Expand Up @@ -128,7 +138,7 @@ impl Config {
},
};

let mut clients: Vec<(Client, Position)> = vec![];
let mut clients: Vec<(TomlClient, Position)> = vec![];

if let Some(config_toml) = config_toml {
if let Some(c) = config_toml.right {
Expand All @@ -155,18 +165,28 @@ impl Config {
})
}

pub fn get_clients(&self) -> Vec<(HashSet<IpAddr>, Option<String>, u16, Position)> {
pub fn get_clients(&self) -> Vec<ConfigClient> {
self.clients
.iter()
.map(|(c, p)| {
.map(|(c, pos)| {
let port = c.port.unwrap_or(DEFAULT_PORT);
let ips: HashSet<IpAddr> = 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)
let hostname = match &c.hostname {
Some(h) => Some(h.clone()),
None => c.host_name.clone(),
};
let active = c.activate_on_startup.unwrap_or(false);
ConfigClient {
ips,
hostname,
port,
pos: *pos,
active,
}
})
.collect()
}
Expand Down
6 changes: 3 additions & 3 deletions src/frontend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ pub enum FrontendEvent {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum FrontendNotify {
NotifyClientCreate(ClientHandle, Option<String>, u16, Position),
NotifyClientUpdate(ClientHandle, Option<String>, u16, Position),
NotifyClientActivate(ClientHandle, bool),
NotifyClientCreate(Client),
NotifyClientUpdate(Client),
NotifyClientDelete(ClientHandle),
/// new port, reason of failure (if failed)
NotifyPortChange(u16, Option<String>),
Expand Down Expand Up @@ -224,7 +225,6 @@ impl FrontendListener {
log::debug!("json: {json}, len: {}", payload.len());

let mut keep = vec![];

// TODO do simultaneously
for tx in self.tx_streams.iter_mut() {
// write len + payload
Expand Down
29 changes: 19 additions & 10 deletions src/frontend/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,17 +83,26 @@ pub fn run() -> Result<()> {
Err(e) => break log::error!("{e}"),
};
match notify {
FrontendNotify::NotifyClientCreate(client, host, port, pos) => {
log::info!(
"new client ({client}): {}:{port} - {pos}",
host.as_deref().unwrap_or("")
);
FrontendNotify::NotifyClientActivate(handle, active) => {
if active {
log::info!("client {handle} activated");
} else {
log::info!("client {handle} deactivated");
}
}
FrontendNotify::NotifyClientCreate(client) => {
let handle = client.handle;
let port = client.port;
let pos = client.pos;
let hostname = client.hostname.as_deref().unwrap_or("");
log::info!("new client ({handle}): {hostname}:{port} - {pos}");
}
FrontendNotify::NotifyClientUpdate(client, host, port, pos) => {
log::info!(
"client ({client}) updated: {}:{port} - {pos}",
host.as_deref().unwrap_or("")
);
FrontendNotify::NotifyClientUpdate(client) => {
let handle = client.handle;
let port = client.port;
let pos = client.pos;
let hostname = client.hostname.as_deref().unwrap_or("");
log::info!("client ({handle}) updated: {hostname}:{port} - {pos}");
}
FrontendNotify::NotifyClientDelete(client) => {
log::info!("client ({client}) deleted.");
Expand Down
76 changes: 17 additions & 59 deletions src/frontend/gtk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ use std::{
process, str,
};

use crate::{config::DEFAULT_PORT, frontend::gtk::window::Window};
use crate::frontend::gtk::window::Window;

use adw::Application;
use gtk::{
gdk::Display,
gio::{SimpleAction, SimpleActionGroup},
glib::clone,
prelude::*,
subclass::prelude::ObjectSubclassIsExt,
CssProvider, IconTheme,
gdk::Display, glib::clone, prelude::*, subclass::prelude::ObjectSubclassIsExt, CssProvider,
IconTheme,
};
use gtk::{gio, glib, prelude::ApplicationExt};

Expand Down Expand Up @@ -68,8 +64,8 @@ fn load_css() {
}

fn load_icons() {
let icon_theme =
IconTheme::for_display(&Display::default().expect("Could not connect to a display."));
let display = &Display::default().expect("Could not connect to a display.");
let icon_theme = IconTheme::for_display(display);
icon_theme.add_resource_path("/de/feschber/LanMouse/icons");
}

Expand Down Expand Up @@ -130,35 +126,29 @@ fn build_ui(app: &Application) {
loop {
let notify = receiver.recv().await.unwrap();
match notify {
FrontendNotify::NotifyClientCreate(client, hostname, port, position) => {
window.new_client(client, hostname, port, position, false);
FrontendNotify::NotifyClientActivate(handle, active) => {
window.activate_client(handle, active);
}
FrontendNotify::NotifyClientCreate(client) => {
window.new_client(client, false);
},
FrontendNotify::NotifyClientUpdate(client, hostname, port, position) => {
log::info!("client updated: {client}, {}:{port}, {position}", hostname.unwrap_or("".to_string()));
FrontendNotify::NotifyClientUpdate(client) => {
window.update_client(client);
}
FrontendNotify::NotifyError(e) => {
// TODO
log::error!("{e}");
window.show_toast(e.as_str());
},
FrontendNotify::NotifyClientDelete(client) => {
window.delete_client(client);
}
FrontendNotify::Enumerate(clients) => {
for (client, active) in clients {
if window.client_idx(client.handle).is_some() {
continue
window.activate_client(client.handle, active);
window.update_client(client);
} else {
window.new_client(client, active);
}
window.new_client(
client.handle,
client.hostname,
client.addrs
.iter()
.next()
.map(|s| s.port())
.unwrap_or(DEFAULT_PORT),
client.pos,
active,
);
}
},
FrontendNotify::NotifyPortChange(port, msg) => {
Expand All @@ -172,37 +162,5 @@ fn build_ui(app: &Application) {
}
}));

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()));

// update client state
action_request_client_update.connect_activate(clone!(@weak window => move |_action, param| {
log::debug!("request-client-update");
let index = param.unwrap()
.get::<u32>()
.unwrap();
let Some(client) = window.clients().item(index) else {
return;
};
let client = client.downcast_ref::<ClientObject>().unwrap();
window.request_client_update(client);
}));

action_client_delete.connect_activate(clone!(@weak window => move |_action, param| {
log::debug!("delete-client");
let idx = param.unwrap()
.get::<u32>()
.unwrap();
window.request_client_delete(idx);
}));

let actions = SimpleActionGroup::new();
window.insert_action_group("win", Some(&actions));
actions.add_action(&action_request_client_update);
actions.add_action(&action_client_delete);
window.present();
}
18 changes: 6 additions & 12 deletions src/frontend/gtk/client_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down
7 changes: 7 additions & 0 deletions src/frontend/gtk/client_row.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>| {
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit d90eb0c

Please sign in to comment.