mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-16 17:50:54 +03:00
159 lines
4.7 KiB
Rust
159 lines
4.7 KiB
Rust
use std::cell::{Cell, RefCell};
|
|
|
|
#[cfg(windows)]
|
|
use std::net::TcpStream;
|
|
#[cfg(unix)]
|
|
use std::os::unix::net::UnixStream;
|
|
|
|
use adw::subclass::prelude::*;
|
|
use adw::{prelude::*, ActionRow, PreferencesGroup, ToastOverlay};
|
|
use glib::subclass::InitializingObject;
|
|
use gtk::glib::clone;
|
|
use gtk::{gdk, gio, glib, Button, CompositeTemplate, Entry, Label, ListBox};
|
|
|
|
use crate::config::DEFAULT_PORT;
|
|
|
|
#[derive(CompositeTemplate, Default)]
|
|
#[template(resource = "/de/feschber/LanMouse/window.ui")]
|
|
pub struct Window {
|
|
#[template_child]
|
|
pub port_edit_apply: TemplateChild<Button>,
|
|
#[template_child]
|
|
pub port_edit_cancel: TemplateChild<Button>,
|
|
#[template_child]
|
|
pub client_list: TemplateChild<ListBox>,
|
|
#[template_child]
|
|
pub client_placeholder: TemplateChild<ActionRow>,
|
|
#[template_child]
|
|
pub port_entry: TemplateChild<Entry>,
|
|
#[template_child]
|
|
pub hostname_label: TemplateChild<Label>,
|
|
#[template_child]
|
|
pub toast_overlay: TemplateChild<ToastOverlay>,
|
|
#[template_child]
|
|
pub capture_emulation_group: TemplateChild<PreferencesGroup>,
|
|
#[template_child]
|
|
pub capture_status_row: TemplateChild<ActionRow>,
|
|
#[template_child]
|
|
pub emulation_status_row: TemplateChild<ActionRow>,
|
|
#[template_child]
|
|
pub input_emulation_button: TemplateChild<Button>,
|
|
#[template_child]
|
|
pub input_capture_button: TemplateChild<Button>,
|
|
pub clients: RefCell<Option<gio::ListStore>>,
|
|
#[cfg(unix)]
|
|
pub stream: RefCell<Option<UnixStream>>,
|
|
#[cfg(windows)]
|
|
pub stream: RefCell<Option<TcpStream>>,
|
|
pub port: Cell<u16>,
|
|
pub capture_active: Cell<bool>,
|
|
pub emulation_active: Cell<bool>,
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
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;
|
|
|
|
fn class_init(klass: &mut Self::Class) {
|
|
klass.bind_template();
|
|
klass.bind_template_callbacks();
|
|
}
|
|
|
|
fn instance_init(obj: &InitializingObject<Self>) {
|
|
obj.init_template();
|
|
}
|
|
}
|
|
|
|
#[gtk::template_callbacks]
|
|
impl Window {
|
|
#[template_callback]
|
|
fn handle_add_client_pressed(&self, _button: &Button) {
|
|
self.obj().request_client_create();
|
|
}
|
|
|
|
#[template_callback]
|
|
fn handle_copy_hostname(&self, button: &Button) {
|
|
if let Ok(hostname) = hostname::get() {
|
|
let display = gdk::Display::default().unwrap();
|
|
let clipboard = display.clipboard();
|
|
clipboard.set_text(hostname.to_str().expect("hostname: invalid utf8"));
|
|
button.set_icon_name("emblem-ok-symbolic");
|
|
button.set_css_classes(&["success"]);
|
|
glib::spawn_future_local(clone!(
|
|
#[weak]
|
|
button,
|
|
async move {
|
|
glib::timeout_future_seconds(1).await;
|
|
button.set_icon_name("edit-copy-symbolic");
|
|
button.set_css_classes(&[]);
|
|
}
|
|
));
|
|
}
|
|
}
|
|
|
|
#[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);
|
|
}
|
|
|
|
#[template_callback]
|
|
fn handle_emulation(&self) {
|
|
self.obj().request_emulation();
|
|
}
|
|
|
|
#[template_callback]
|
|
fn handle_capture(&self) {
|
|
self.obj().request_capture();
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
impl ObjectImpl for Window {
|
|
fn constructed(&self) {
|
|
if let Ok(hostname) = hostname::get() {
|
|
self.hostname_label
|
|
.set_text(hostname.to_str().expect("hostname: invalid utf8"));
|
|
}
|
|
self.parent_constructed();
|
|
self.set_port(DEFAULT_PORT);
|
|
let obj = self.obj();
|
|
obj.setup_icon();
|
|
obj.setup_clients();
|
|
}
|
|
}
|
|
|
|
impl WidgetImpl for Window {}
|
|
impl WindowImpl for Window {}
|
|
impl ApplicationWindowImpl for Window {}
|
|
impl AdwApplicationWindowImpl for Window {}
|