198 lines
9.2 KiB
Rust
198 lines
9.2 KiB
Rust
|
|
{
|
||
|
|
{
|
||
|
|
let child_proc = Rc::clone(&child_proc);
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
let server_entry = server_entry.clone();
|
||
|
|
let server_addr_fallback = Rc::clone(&server_addr);
|
||
|
|
let clipboard_tx = clipboard_tx.clone();
|
||
|
|
widgets.clipboard_button.connect_clicked(move |_| {
|
||
|
|
if child_proc.borrow().is_none() {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Start the relay before sending clipboard text.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let server_addr =
|
||
|
|
selected_server_addr(&server_entry, server_addr_fallback.as_ref());
|
||
|
|
let Some(display) = gtk::gdk::Display::default() else {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("No desktop clipboard is available in this session.");
|
||
|
|
return;
|
||
|
|
};
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Reading the local clipboard and preparing remote paste...");
|
||
|
|
let clipboard = display.clipboard();
|
||
|
|
let clipboard_tx = clipboard_tx.clone();
|
||
|
|
clipboard.read_text_async(None::<>k::gio::Cancellable>, move |result| {
|
||
|
|
match result {
|
||
|
|
Ok(Some(text)) => {
|
||
|
|
let text = text.trim_end_matches(['\r', '\n']).to_string();
|
||
|
|
if text.is_empty() {
|
||
|
|
let _ = clipboard_tx.send(ClipboardMessage::Finished(Err(
|
||
|
|
"clipboard is empty".to_string(),
|
||
|
|
)));
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let clipboard_tx = clipboard_tx.clone();
|
||
|
|
std::thread::spawn(move || {
|
||
|
|
let result = send_clipboard_text_to_remote(&server_addr, &text)
|
||
|
|
.map_err(|err| err.to_string());
|
||
|
|
let _ = clipboard_tx
|
||
|
|
.send(ClipboardMessage::Finished(result));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
Ok(None) => {
|
||
|
|
let _ = clipboard_tx.send(ClipboardMessage::Finished(Err(
|
||
|
|
"clipboard is empty".to_string(),
|
||
|
|
)));
|
||
|
|
}
|
||
|
|
Err(err) => {
|
||
|
|
let _ = clipboard_tx.send(ClipboardMessage::Finished(Err(
|
||
|
|
format!("clipboard read failed: {err}"),
|
||
|
|
)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
widgets.probe_button.connect_clicked(move |_| {
|
||
|
|
if let Some(display) = gtk::gdk::Display::default() {
|
||
|
|
let clipboard = display.clipboard();
|
||
|
|
clipboard.set_text(quality_probe_command());
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Quality probe command copied to the local clipboard.");
|
||
|
|
} else {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("No desktop clipboard is available in this session.");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
let server_entry = server_entry.clone();
|
||
|
|
let server_addr_fallback = Rc::clone(&server_addr);
|
||
|
|
let widgets_for_click = widgets.clone();
|
||
|
|
widgets.usb_recover_button.connect_clicked(move |_| {
|
||
|
|
let server_addr =
|
||
|
|
selected_server_addr(&server_entry, server_addr_fallback.as_ref());
|
||
|
|
widgets_for_click.status_label.set_text(
|
||
|
|
"Requesting a forced USB gadget re-enumeration on the relay host...",
|
||
|
|
);
|
||
|
|
let (tx, rx) = std::sync::mpsc::channel();
|
||
|
|
std::thread::spawn(move || {
|
||
|
|
let result =
|
||
|
|
reset_usb_gadget(&server_addr).map_err(|err| format!("{err:#}"));
|
||
|
|
let _ = tx.send(result);
|
||
|
|
});
|
||
|
|
let widgets = widgets_for_click.clone();
|
||
|
|
glib::timeout_add_local(Duration::from_millis(100), move || {
|
||
|
|
match rx.try_recv() {
|
||
|
|
Ok(Ok(())) => {
|
||
|
|
widgets.status_label.set_text(
|
||
|
|
"USB gadget recovery requested. Give the host a few seconds to re-enumerate keyboard, mouse, webcam, and audio.",
|
||
|
|
);
|
||
|
|
glib::ControlFlow::Break
|
||
|
|
}
|
||
|
|
Ok(Err(err)) => {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text(&format!("USB gadget recovery failed: {err}"));
|
||
|
|
glib::ControlFlow::Break
|
||
|
|
}
|
||
|
|
Err(std::sync::mpsc::TryRecvError::Empty) => glib::ControlFlow::Continue,
|
||
|
|
Err(std::sync::mpsc::TryRecvError::Disconnected) => {
|
||
|
|
widgets.status_label.set_text(
|
||
|
|
"USB gadget recovery ended unexpectedly before the relay answered.",
|
||
|
|
);
|
||
|
|
glib::ControlFlow::Break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
widgets.diagnostics_copy_button.connect_clicked(move |_| {
|
||
|
|
if let Err(err) = copy_plain_text(&widgets.diagnostics_rendered_text.borrow()) {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text(&format!("Could not copy the diagnostics report: {err}"));
|
||
|
|
} else {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Diagnostics report copied to the local clipboard.");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let app = app.clone();
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
let diagnostics_popout = Rc::clone(&diagnostics_popout);
|
||
|
|
widgets.diagnostics_popout_button.connect_clicked(move |_| {
|
||
|
|
open_diagnostics_popout(
|
||
|
|
&app,
|
||
|
|
&diagnostics_popout,
|
||
|
|
&widgets.diagnostics_popout_label,
|
||
|
|
&widgets.diagnostics_popout_scroll,
|
||
|
|
&widgets.diagnostics_rendered_text,
|
||
|
|
);
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Diagnostics report moved into its own window.");
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
widgets.console_level_combo.connect_changed(move |combo| {
|
||
|
|
let level = combo
|
||
|
|
.active_id()
|
||
|
|
.as_deref()
|
||
|
|
.and_then(ConsoleLogLevel::from_id)
|
||
|
|
.unwrap_or_default();
|
||
|
|
*widgets.session_log_level.borrow_mut() = level;
|
||
|
|
widgets.status_label.set_text(&format!(
|
||
|
|
"Console now shows {} relay logs and higher.",
|
||
|
|
level.label()
|
||
|
|
));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
widgets.console_copy_button.connect_clicked(move |_| {
|
||
|
|
if let Err(err) = copy_session_log(&widgets.session_log_buffer) {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text(&format!("Could not copy the session log: {err}"));
|
||
|
|
} else {
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Session log copied to the local clipboard.");
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
let app = app.clone();
|
||
|
|
let widgets = widgets.clone();
|
||
|
|
let log_popout = Rc::clone(&log_popout);
|
||
|
|
widgets.console_popout_button.connect_clicked(move |_| {
|
||
|
|
open_session_log_popout(&app, &log_popout, &widgets.session_log_buffer);
|
||
|
|
widgets
|
||
|
|
.status_label
|
||
|
|
.set_text("Session log moved into its own window.");
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|