mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-13 11:21:29 +03:00
port changing functionality (#34)
* port changing functionality * add portchange to cli frontend
This commit is contained in:
committed by
GitHub
parent
60a73b3cb0
commit
e88241e816
@@ -1,3 +1,11 @@
|
|||||||
#delete-button {
|
#delete-button {
|
||||||
color: @red_1;
|
color: @red_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#port-edit-cancel {
|
||||||
|
color: @red_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#port-edit-apply {
|
||||||
|
color: @green_1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
#delete-button {
|
#delete-button {
|
||||||
color: @red_3;
|
color: @red_3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#port-edit-cancel {
|
||||||
|
color: @red_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#port-edit-apply {
|
||||||
|
color: @green_3;
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,114 +8,143 @@
|
|||||||
<attribute name="action">window.close</attribute>
|
<attribute name="action">window.close</attribute>
|
||||||
</item>
|
</item>
|
||||||
</menu>
|
</menu>
|
||||||
<template class="LanMouseWindow" parent="GtkApplicationWindow">
|
<template class="LanMouseWindow" parent="AdwApplicationWindow">
|
||||||
<property name="width-request">600</property>
|
<property name="width-request">600</property>
|
||||||
<property name="title" translatable="yes">Lan Mouse</property>
|
<property name="title" translatable="yes">Lan Mouse</property>
|
||||||
<property name="show-menubar">True</property>
|
<property name="show-menubar">True</property>
|
||||||
<child type="titlebar">
|
<property name="content">
|
||||||
<object class="GtkHeaderBar">
|
<object class="AdwToolbarView">
|
||||||
<child type ="end">
|
<child type="top">
|
||||||
<object class="GtkMenuButton">
|
<object class="AdwHeaderBar">
|
||||||
<property name="icon-name">open-menu-symbolic</property>
|
<child type ="end">
|
||||||
<property name="menu-model">main-menu</property>
|
<object class="GtkMenuButton">
|
||||||
|
<property name="icon-name">open-menu-symbolic</property>
|
||||||
|
<property name="menu-model">main-menu</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="flat"/>
|
||||||
|
</style>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<style>
|
<property name="content">
|
||||||
<class name="flat"/>
|
<object class="AdwToastOverlay" id="toast_overlay">
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="AdwStatusPage">
|
|
||||||
<property name="title" translatable="yes">Lan Mouse</property>
|
|
||||||
<property name="description" translatable="yes">easily use your mouse and keyboard on multiple computers</property>
|
|
||||||
<property name="icon-name">mouse-icon</property>
|
|
||||||
<property name="child">
|
|
||||||
<object class="AdwClamp">
|
|
||||||
<property name="maximum-size">600</property>
|
|
||||||
<property name="tightening-threshold">0</property>
|
|
||||||
<property name="child">
|
|
||||||
<object class="GtkBox">
|
|
||||||
<property name="orientation">vertical</property>
|
|
||||||
<property name="spacing">12</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="AdwPreferencesGroup">
|
<object class="AdwStatusPage">
|
||||||
<property name="title" translatable="yes">General</property>
|
<property name="title" translatable="yes">Lan Mouse</property>
|
||||||
<child>
|
<property name="description" translatable="yes">easily use your mouse and keyboard on multiple computers</property>
|
||||||
<object class="AdwActionRow">
|
<property name="icon-name">mouse-icon</property>
|
||||||
<property name="title" translatable="yes">enable</property>
|
<property name="child">
|
||||||
<child type="suffix">
|
<object class="AdwClamp">
|
||||||
<object class="GtkSwitch">
|
<property name="maximum-size">600</property>
|
||||||
<property name="valign">center</property>
|
<property name="tightening-threshold">0</property>
|
||||||
<property name="tooltip-text" translatable="yes">enable</property>
|
<property name="child">
|
||||||
</object>
|
<object class="GtkBox">
|
||||||
</child>
|
<property name="orientation">vertical</property>
|
||||||
</object>
|
<property name="spacing">12</property>
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="AdwActionRow">
|
|
||||||
<property name="title">port</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkEntry">
|
<object class="AdwPreferencesGroup">
|
||||||
<!-- <property name="title" translatable="yes">port</property> -->
|
<property name="title" translatable="yes">General</property>
|
||||||
<property name="placeholder-text">4242</property>
|
<child>
|
||||||
<property name="width-chars">5</property>
|
<object class="AdwActionRow">
|
||||||
<property name="xalign">0.5</property>
|
<property name="title" translatable="yes">enable</property>
|
||||||
<property name="valign">center</property>
|
<child type="suffix">
|
||||||
<!-- <property name="show-apply-button">True</property> -->
|
<object class="GtkSwitch">
|
||||||
<property name="input-purpose">GTK_INPUT_PURPOSE_DIGITS</property>
|
<property name="valign">center</property>
|
||||||
|
<property name="tooltip-text" translatable="yes">enable</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title">port</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="port_entry">
|
||||||
|
<signal name="activate" handler="handle_port_edit_apply" swapped="true"/>
|
||||||
|
<signal name="changed" handler="handle_port_changed" swapped="true"/>
|
||||||
|
<!-- <signal name="delete-text" handler="handle_port_changed" swapped="true"/> -->
|
||||||
|
<!-- <property name="title" translatable="yes">port</property> -->
|
||||||
|
<property name="placeholder-text">4242</property>
|
||||||
|
<property name="width-chars">5</property>
|
||||||
|
<property name="xalign">0.5</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<!-- <property name="show-apply-button">True</property> -->
|
||||||
|
<property name="input-purpose">GTK_INPUT_PURPOSE_DIGITS</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="port_edit_apply">
|
||||||
|
<signal name="clicked" handler="handle_port_edit_apply" swapped="true"/>
|
||||||
|
<property name="icon-name">object-select-symbolic</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="name">port-edit-apply</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="port_edit_cancel">
|
||||||
|
<signal name="clicked" handler="handle_port_edit_cancel" swapped="true"/>
|
||||||
|
<property name="icon-name">process-stop-symbolic</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="visible">false</property>
|
||||||
|
<property name="name">port-edit-cancel</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
<child>
|
||||||
</child>
|
<object class="AdwPreferencesGroup">
|
||||||
</object>
|
<property name="title" translatable="yes">Connections</property>
|
||||||
</child>
|
<child>
|
||||||
<child>
|
<object class="GtkListBox" id="client_list">
|
||||||
<object class="AdwPreferencesGroup">
|
<property name="selection-mode">none</property>
|
||||||
<property name="title" translatable="yes">Connections</property>
|
<child type="placeholder">
|
||||||
<child>
|
<object class="AdwActionRow" id="client_placeholder">
|
||||||
<object class="GtkListBox" id="client_list">
|
<property name="title">No connections!</property>
|
||||||
<property name="selection-mode">none</property>
|
<property name="subtitle">add a new client via the button below</property>
|
||||||
<child type="placeholder">
|
</object>
|
||||||
<object class="AdwActionRow" id="client_placeholder">
|
</child>
|
||||||
<property name="title">No connections!</property>
|
<style>
|
||||||
<property name="subtitle">add a new client via the button below</property>
|
<class name="boxed-list" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<style>
|
<child>
|
||||||
<class name="boxed-list" />
|
<object class="AdwPreferencesGroup">
|
||||||
</style>
|
<child>
|
||||||
|
<object class="GtkButton" id="add_client_button">
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="tooltip-text">connect a new computer</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwButtonContent">
|
||||||
|
<property name="icon-name">list-add-symbolic</property>
|
||||||
|
<property name="label" translatable="yes">Add</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
<signal name="clicked" handler="handle_add_client_pressed" swapped="true"/>
|
||||||
|
<style>
|
||||||
|
<class name="pill"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
</object>
|
||||||
<object class="AdwPreferencesGroup">
|
</property>
|
||||||
<child>
|
|
||||||
<object class="GtkButton" id="add_client_button">
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<property name="tooltip-text">connect a new computer</property>
|
|
||||||
<property name="child">
|
|
||||||
<object class="AdwButtonContent">
|
|
||||||
<property name="icon-name">list-add-symbolic</property>
|
|
||||||
<property name="label" translatable="yes">Add</property>
|
|
||||||
<property name="use-underline">True</property>
|
|
||||||
</object>
|
|
||||||
</property>
|
|
||||||
<!-- <signal name="clicked" handler="handle_add_client" swapped="true"/> -->
|
|
||||||
<style>
|
|
||||||
<class name="pill"/>
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</property>
|
|
||||||
</object>
|
|
||||||
</property>
|
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</property>
|
||||||
</template>
|
</template>
|
||||||
</interface>
|
</interface>
|
||||||
|
|||||||
@@ -453,13 +453,38 @@ impl Server {
|
|||||||
match event {
|
match event {
|
||||||
FrontendEvent::AddClient(hostname, port, pos) => { self.add_client(hostname, HashSet::new(), port, pos).await; },
|
FrontendEvent::AddClient(hostname, port, pos) => { self.add_client(hostname, HashSet::new(), port, pos).await; },
|
||||||
FrontendEvent::ActivateClient(client, active) => self.activate_client(client, active).await,
|
FrontendEvent::ActivateClient(client, active) => self.activate_client(client, active).await,
|
||||||
|
FrontendEvent::ChangePort(port) => {
|
||||||
|
let current_port = self.socket.local_addr().unwrap().port();
|
||||||
|
if current_port == port {
|
||||||
|
if let Err(e) = self.frontend.notify_all(FrontendNotify::NotifyPortChange(port, None)).await {
|
||||||
|
log::warn!("error notifying frontend: {e}");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
|
||||||
|
match UdpSocket::bind(listen_addr).await {
|
||||||
|
Ok(socket) => {
|
||||||
|
self.socket = socket;
|
||||||
|
if let Err(e) = self.frontend.notify_all(FrontendNotify::NotifyPortChange(port, None)).await {
|
||||||
|
log::warn!("error notifying frontend: {e}");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("could not change port: {e}");
|
||||||
|
let port = self.socket.local_addr().unwrap().port();
|
||||||
|
if let Err(e) = self.frontend.notify_all(FrontendNotify::NotifyPortChange(port, Some(format!("could not change port: {e}")))).await {
|
||||||
|
log::error!("error notifying frontend: {e}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
FrontendEvent::DelClient(client) => { self.remove_client(client).await; },
|
FrontendEvent::DelClient(client) => { self.remove_client(client).await; },
|
||||||
FrontendEvent::UpdateClient(client, hostname, port, pos) => self.update_client(client, hostname, port, pos).await,
|
|
||||||
FrontendEvent::Enumerate() => self.enumerate().await,
|
FrontendEvent::Enumerate() => self.enumerate().await,
|
||||||
FrontendEvent::Shutdown() => {
|
FrontendEvent::Shutdown() => {
|
||||||
log::info!("terminating gracefully...");
|
log::info!("terminating gracefully...");
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
FrontendEvent::UpdateClient(client, hostname, port, pos) => self.update_client(client, hostname, port, pos).await,
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,14 +33,16 @@ pub enum FrontendEvent {
|
|||||||
AddClient(Option<String>, u16, Position),
|
AddClient(Option<String>, u16, Position),
|
||||||
/// activate/deactivate client
|
/// activate/deactivate client
|
||||||
ActivateClient(ClientHandle, bool),
|
ActivateClient(ClientHandle, bool),
|
||||||
/// update a client (hostname, port, position)
|
/// change the listen port (recreate udp listener)
|
||||||
UpdateClient(ClientHandle, Option<String>, u16, Position),
|
ChangePort(u16),
|
||||||
/// remove a client
|
/// remove a client
|
||||||
DelClient(ClientHandle),
|
DelClient(ClientHandle),
|
||||||
/// request an enumertaion of all clients
|
/// request an enumertaion of all clients
|
||||||
Enumerate(),
|
Enumerate(),
|
||||||
/// service shutdown
|
/// service shutdown
|
||||||
Shutdown(),
|
Shutdown(),
|
||||||
|
/// update a client (hostname, port, position)
|
||||||
|
UpdateClient(ClientHandle, Option<String>, u16, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -48,6 +50,8 @@ pub enum FrontendNotify {
|
|||||||
NotifyClientCreate(ClientHandle, Option<String>, u16, Position),
|
NotifyClientCreate(ClientHandle, Option<String>, u16, Position),
|
||||||
NotifyClientUpdate(ClientHandle, Option<String>, u16, Position),
|
NotifyClientUpdate(ClientHandle, Option<String>, u16, Position),
|
||||||
NotifyClientDelete(ClientHandle),
|
NotifyClientDelete(ClientHandle),
|
||||||
|
/// new port, reason of failure (if failed)
|
||||||
|
NotifyPortChange(u16, Option<String>),
|
||||||
Enumerate(Vec<(Client, bool)>),
|
Enumerate(Vec<(Client, bool)>),
|
||||||
NotifyError(String),
|
NotifyError(String),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ pub fn start() -> Result<(JoinHandle<()>, JoinHandle<()>)> {
|
|||||||
.join(", ")
|
.join(", ")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
FrontendNotify::NotifyPortChange(port, msg) => {
|
||||||
|
match msg {
|
||||||
|
Some(msg) => log::info!("could not change port: {msg}"),
|
||||||
|
None => log::info!("port changed: {port}"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
prompt();
|
prompt();
|
||||||
@@ -142,6 +148,7 @@ fn parse_cmd(s: String, len: usize) -> Option<Vec<FrontendEvent>> {
|
|||||||
log::info!("activate <client> activate a client");
|
log::info!("activate <client> activate a client");
|
||||||
log::info!("deactivate <client> deactivate a client");
|
log::info!("deactivate <client> deactivate a client");
|
||||||
log::info!("exit exit lan-mouse");
|
log::info!("exit exit lan-mouse");
|
||||||
|
log::info!("setport <port> change port");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
"exit" => return Some(vec![FrontendEvent::Shutdown()]),
|
"exit" => return Some(vec![FrontendEvent::Shutdown()]),
|
||||||
@@ -150,13 +157,14 @@ fn parse_cmd(s: String, len: usize) -> Option<Vec<FrontendEvent>> {
|
|||||||
"disconnect" => Some(parse_disconnect(l)),
|
"disconnect" => Some(parse_disconnect(l)),
|
||||||
"activate" => Some(parse_activate(l)),
|
"activate" => Some(parse_activate(l)),
|
||||||
"deactivate" => Some(parse_deactivate(l)),
|
"deactivate" => Some(parse_deactivate(l)),
|
||||||
|
"setport" => Some(parse_port(l)),
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("unknown command: {s}");
|
log::error!("unknown command: {s}");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match res {
|
match res {
|
||||||
Some(Ok(e)) => Some(vec![e, FrontendEvent::Enumerate()]),
|
Some(Ok(e)) => Some(e),
|
||||||
Some(Err(e)) => {
|
Some(Err(e)) => {
|
||||||
log::warn!("{e}");
|
log::warn!("{e}");
|
||||||
None
|
None
|
||||||
@@ -165,7 +173,7 @@ fn parse_cmd(s: String, len: usize) -> Option<Vec<FrontendEvent>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_connect(mut l: SplitWhitespace) -> Result<FrontendEvent> {
|
fn parse_connect(mut l: SplitWhitespace) -> Result<Vec<FrontendEvent>> {
|
||||||
let usage = "usage: connect <host> left|right|top|bottom [port]";
|
let usage = "usage: connect <host> left|right|top|bottom [port]";
|
||||||
let host = l.next().context(usage)?.to_owned();
|
let host = l.next().context(usage)?.to_owned();
|
||||||
let pos = match l.next().context(usage)? {
|
let pos = match l.next().context(usage)? {
|
||||||
@@ -179,19 +187,25 @@ fn parse_connect(mut l: SplitWhitespace) -> Result<FrontendEvent> {
|
|||||||
} else {
|
} else {
|
||||||
DEFAULT_PORT
|
DEFAULT_PORT
|
||||||
};
|
};
|
||||||
Ok(FrontendEvent::AddClient(Some(host), port, pos))
|
Ok(vec![FrontendEvent::AddClient(Some(host), port, pos), FrontendEvent::Enumerate()])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_disconnect(mut l: SplitWhitespace) -> Result<FrontendEvent> {
|
fn parse_disconnect(mut l: SplitWhitespace) -> Result<Vec<FrontendEvent>> {
|
||||||
let client = l.next().context("usage: disconnect <client_id>")?.parse()?;
|
let client = l.next().context("usage: disconnect <client_id>")?.parse()?;
|
||||||
Ok(FrontendEvent::DelClient(client))
|
Ok(vec![FrontendEvent::DelClient(client), FrontendEvent::Enumerate()])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_activate(mut l: SplitWhitespace) -> Result<FrontendEvent> {
|
fn parse_activate(mut l: SplitWhitespace) -> Result<Vec<FrontendEvent>> {
|
||||||
let client = l.next().context("usage: activate <client_id>")?.parse()?;
|
let client = l.next().context("usage: activate <client_id>")?.parse()?;
|
||||||
Ok(FrontendEvent::ActivateClient(client, true))
|
Ok(vec![FrontendEvent::ActivateClient(client, true), FrontendEvent::Enumerate()])
|
||||||
}
|
}
|
||||||
fn parse_deactivate(mut l: SplitWhitespace) -> Result<FrontendEvent> {
|
|
||||||
|
fn parse_deactivate(mut l: SplitWhitespace) -> Result<Vec<FrontendEvent>> {
|
||||||
let client = l.next().context("usage: deactivate <client_id>")?.parse()?;
|
let client = l.next().context("usage: deactivate <client_id>")?.parse()?;
|
||||||
Ok(FrontendEvent::ActivateClient(client, false))
|
Ok(vec![FrontendEvent::ActivateClient(client, false), FrontendEvent::Enumerate()])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_port(mut l: SplitWhitespace) -> Result<Vec<FrontendEvent>> {
|
||||||
|
let port = l.next().context("usage: setport <port>")?.parse()?;
|
||||||
|
Ok(vec![FrontendEvent::ChangePort(port)])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,13 @@ fn build_ui(app: &Application) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
FrontendNotify::NotifyPortChange(port, msg) => {
|
||||||
|
match msg {
|
||||||
|
None => window.show_toast(format!("port changed: {port}").as_str()),
|
||||||
|
Some(msg) => window.show_toast(msg.as_str()),
|
||||||
|
}
|
||||||
|
window.imp().set_port(port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
glib::ControlFlow::Continue
|
glib::ControlFlow::Continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,9 +100,19 @@ impl Window {
|
|||||||
|
|
||||||
pub fn request_client_create(&self) {
|
pub fn request_client_create(&self) {
|
||||||
let event = FrontendEvent::AddClient(None, DEFAULT_PORT, Position::default());
|
let event = FrontendEvent::AddClient(None, DEFAULT_PORT, Position::default());
|
||||||
|
self.imp().set_port(DEFAULT_PORT);
|
||||||
self.request(event);
|
self.request(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request_port_change(&self) {
|
||||||
|
let port = self.imp().port_entry.get().text().to_string();
|
||||||
|
if let Ok(port) = u16::from_str_radix(port.as_str(), 10) {
|
||||||
|
self.request(FrontendEvent::ChangePort(port));
|
||||||
|
} else {
|
||||||
|
self.request(FrontendEvent::ChangePort(DEFAULT_PORT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn request_client_update(&self, client: &ClientObject) {
|
pub fn request_client_update(&self, client: &ClientObject) {
|
||||||
let data = client.get_data();
|
let data = client.get_data();
|
||||||
let position = match data.position.as_str() {
|
let position = match data.position.as_str() {
|
||||||
@@ -150,11 +160,9 @@ impl Window {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_callbacks(&self) {
|
pub fn show_toast(&self, msg: &str) {
|
||||||
self.imp()
|
let toast = adw::Toast::new(msg);
|
||||||
.add_client_button
|
let toast_overlay = &self.imp().toast_overlay;
|
||||||
.connect_clicked(clone!(@weak self as window => move |_| {
|
toast_overlay.add_toast(toast);
|
||||||
window.request_client_create();
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
use std::{cell::{Cell, RefCell}, os::unix::net::UnixStream};
|
use std::{cell::{Cell, RefCell}, os::unix::net::UnixStream};
|
||||||
|
|
||||||
use glib::subclass::InitializingObject;
|
use glib::subclass::InitializingObject;
|
||||||
use adw::{prelude::*, ActionRow};
|
use adw::{ActionRow, ToastOverlay, prelude::{WidgetExt, EditableExt}};
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use gtk::{glib, Button, CompositeTemplate, ListBox, gio};
|
use gtk::{glib, Button, CompositeTemplate, ListBox, gio, Entry};
|
||||||
|
|
||||||
|
use crate::config::DEFAULT_PORT;
|
||||||
|
|
||||||
#[derive(CompositeTemplate, Default)]
|
#[derive(CompositeTemplate, Default)]
|
||||||
#[template(resource = "/de/feschber/LanMouse/window.ui")]
|
#[template(resource = "/de/feschber/LanMouse/window.ui")]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub number: Cell<i32>,
|
#[template_child]
|
||||||
|
pub port_edit_apply: TemplateChild<Button>,
|
||||||
|
#[template_child]
|
||||||
|
pub port_edit_cancel: TemplateChild<Button>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub add_client_button: TemplateChild<Button>,
|
pub add_client_button: TemplateChild<Button>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub client_list: TemplateChild<ListBox>,
|
pub client_list: TemplateChild<ListBox>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub client_placeholder: TemplateChild<ActionRow>,
|
pub client_placeholder: TemplateChild<ActionRow>,
|
||||||
|
#[template_child]
|
||||||
|
pub port_entry: TemplateChild<Entry>,
|
||||||
|
#[template_child]
|
||||||
|
pub toast_overlay: TemplateChild<ToastOverlay>,
|
||||||
pub clients: RefCell<Option<gio::ListStore>>,
|
pub clients: RefCell<Option<gio::ListStore>>,
|
||||||
pub stream: RefCell<Option<UnixStream>>,
|
pub stream: RefCell<Option<UnixStream>>,
|
||||||
|
pub port: Cell<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
@@ -24,7 +34,7 @@ impl ObjectSubclass for Window {
|
|||||||
// `NAME` needs to match `class` attribute of template
|
// `NAME` needs to match `class` attribute of template
|
||||||
const NAME: &'static str = "LanMouseWindow";
|
const NAME: &'static str = "LanMouseWindow";
|
||||||
type Type = super::Window;
|
type Type = super::Window;
|
||||||
type ParentType = gtk::ApplicationWindow;
|
type ParentType = adw::ApplicationWindow;
|
||||||
|
|
||||||
fn class_init(klass: &mut Self::Class) {
|
fn class_init(klass: &mut Self::Class) {
|
||||||
klass.bind_template();
|
klass.bind_template();
|
||||||
@@ -39,10 +49,38 @@ impl ObjectSubclass for Window {
|
|||||||
#[gtk::template_callbacks]
|
#[gtk::template_callbacks]
|
||||||
impl Window {
|
impl Window {
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn handle_button_clicked(&self, button: &Button) {
|
fn handle_add_client_pressed(&self, _button: &Button) {
|
||||||
let number_increased = self.number.get() + 1;
|
self.obj().request_client_create();
|
||||||
self.number.set(number_increased);
|
}
|
||||||
button.set_label(&number_increased.to_string())
|
|
||||||
|
#[template_callback]
|
||||||
|
fn handle_port_changed(&self, _entry: &Entry) {
|
||||||
|
self.port_edit_apply.set_visible(true);
|
||||||
|
self.port_edit_cancel.set_visible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn handle_port_edit_apply(&self) {
|
||||||
|
self.obj().request_port_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn handle_port_edit_cancel(&self) {
|
||||||
|
log::debug!("cancel port edit");
|
||||||
|
self.port_entry.set_text(self.port.get().to_string().as_str());
|
||||||
|
self.port_edit_apply.set_visible(false);
|
||||||
|
self.port_edit_cancel.set_visible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_port(&self, port: u16) {
|
||||||
|
self.port.set(port);
|
||||||
|
if port == DEFAULT_PORT {
|
||||||
|
self.port_entry.set_text("");
|
||||||
|
} else {
|
||||||
|
self.port_entry.set_text(format!("{port}").as_str());
|
||||||
|
}
|
||||||
|
self.port_edit_apply.set_visible(false);
|
||||||
|
self.port_edit_cancel.set_visible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,13 +88,14 @@ impl Window {
|
|||||||
impl ObjectImpl for Window {
|
impl ObjectImpl for Window {
|
||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
|
self.set_port(DEFAULT_PORT);
|
||||||
let obj = self.obj();
|
let obj = self.obj();
|
||||||
obj.setup_icon();
|
obj.setup_icon();
|
||||||
obj.setup_clients();
|
obj.setup_clients();
|
||||||
obj.setup_callbacks();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetImpl for Window {}
|
impl WidgetImpl for Window {}
|
||||||
impl WindowImpl for Window {}
|
impl WindowImpl for Window {}
|
||||||
impl ApplicationWindowImpl for Window {}
|
impl ApplicationWindowImpl for Window {}
|
||||||
|
impl AdwApplicationWindowImpl for Window {}
|
||||||
|
|||||||
Reference in New Issue
Block a user