{ { 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."); }); } }