fix(launcher): avoid relay connect freeze

This commit is contained in:
Brad Stein 2026-04-15 04:22:25 -03:00
parent b53ea917d7
commit dc0efc8f1a
5 changed files with 39 additions and 34 deletions

View File

@ -15,13 +15,12 @@ use {
open_popout_window, path_marker, read_input_routing_state, reap_exited_child,
refresh_launcher_ui, refresh_test_buttons, routing_name, selected_combo_value,
selected_server_addr, selected_toggle_key, spawn_client_process, stop_child_process,
update_test_action_result, write_input_routing_request,
update_test_action_result, write_input_routing_request, RelayChild,
},
gtk::glib,
gtk::prelude::*,
lesavka_common::lesavka::CapturePowerCommand,
std::cell::{Cell, RefCell},
std::process::Child,
std::rc::Rc,
std::time::Duration,
};
@ -64,7 +63,7 @@ pub fn run_gui_launcher(server_addr: String) -> Result<()> {
let catalog = Rc::new(DeviceCatalog::discover());
let state = Rc::new(RefCell::new(LauncherState::new()));
state.borrow_mut().apply_catalog_defaults(&catalog);
let child_proc = Rc::new(RefCell::new(None::<Child>));
let child_proc = Rc::new(RefCell::new(None::<RelayChild>));
let tests = Rc::new(RefCell::new(DeviceTestController::new()));
let server_addr = Rc::new(server_addr);
let focus_signal_path = Rc::new(launcher_focus_signal_path());

View File

@ -532,9 +532,6 @@ pub fn install_css(window: &gtk::ApplicationWindow) {
entry.server-entry {
min-height: 38px;
}
picture {
content-fit: contain;
}
button.pill-toggle {
min-height: 36px;
padding: 0 14px;

View File

@ -1,9 +1,9 @@
use anyhow::Result;
use gtk::gio;
use gtk::{glib, prelude::*};
use std::{
cell::RefCell,
path::{Path, PathBuf},
process::{Child, Command},
rc::Rc,
};
@ -22,6 +22,8 @@ pub const INPUT_STATE_ENV: &str = "LESAVKA_LAUNCHER_INPUT_STATE";
pub const DEFAULT_INPUT_CONTROL_PATH: &str = "/tmp/lesavka-launcher-input.control";
pub const DEFAULT_INPUT_STATE_PATH: &str = "/tmp/lesavka-launcher-input.state";
pub type RelayChild = gio::Subprocess;
pub fn refresh_launcher_ui(widgets: &LauncherWidgets, state: &LauncherState, child_running: bool) {
let relay_live = child_running || state.remote_active;
widgets
@ -146,7 +148,7 @@ pub fn open_popout_window(
app: &gtk::Application,
preview: &LauncherPreview,
state: &Rc<RefCell<LauncherState>>,
child_proc: &Rc<RefCell<Option<Child>>>,
child_proc: &Rc<RefCell<Option<RelayChild>>>,
popouts: &Rc<RefCell<[Option<PopoutWindowHandle>; 2]>>,
widgets: &LauncherWidgets,
monitor_id: usize,
@ -243,7 +245,7 @@ pub fn open_popout_window(
pub fn dock_display_to_preview(
state: &Rc<RefCell<LauncherState>>,
child_proc: &Rc<RefCell<Option<Child>>>,
child_proc: &Rc<RefCell<Option<RelayChild>>>,
popouts: &Rc<RefCell<[Option<PopoutWindowHandle>; 2]>>,
widgets: &LauncherWidgets,
monitor_id: usize,
@ -561,42 +563,49 @@ pub fn spawn_client_process(
input_toggle_key: &str,
input_control_path: &Path,
input_state_path: &Path,
) -> Result<Child> {
) -> Result<RelayChild> {
let exe = std::env::current_exe()?;
let mut command = Command::new(exe);
command.env("LESAVKA_LAUNCHER_CHILD", "1");
command.env("LESAVKA_SERVER_ADDR", server_addr);
command.env("LESAVKA_INPUT_TOGGLE_KEY", input_toggle_key);
command.env("LESAVKA_LAUNCHER_WINDOW_TITLE", "Lesavka Launcher");
command.env("LESAVKA_FOCUS_LAUNCHER_ON_LOCAL", "1");
command.env(LAUNCHER_FOCUS_SIGNAL_ENV, launcher_focus_signal_path());
command.env(INPUT_CONTROL_ENV, input_control_path);
command.env(INPUT_STATE_ENV, input_state_path);
command.env("LESAVKA_DISABLE_VIDEO_RENDER", "1");
command.env("LESAVKA_CLIPBOARD_PASTE", "0");
let launcher = gio::SubprocessLauncher::new(gio::SubprocessFlags::NONE);
launcher.setenv("LESAVKA_LAUNCHER_CHILD", "1", true);
launcher.setenv("LESAVKA_SERVER_ADDR", server_addr, true);
launcher.setenv("LESAVKA_INPUT_TOGGLE_KEY", input_toggle_key, true);
launcher.setenv("LESAVKA_LAUNCHER_WINDOW_TITLE", "Lesavka Launcher", true);
launcher.setenv("LESAVKA_FOCUS_LAUNCHER_ON_LOCAL", "1", true);
launcher.setenv(
LAUNCHER_FOCUS_SIGNAL_ENV,
launcher_focus_signal_path(),
true,
);
launcher.setenv(INPUT_CONTROL_ENV, input_control_path, true);
launcher.setenv(INPUT_STATE_ENV, input_state_path, true);
launcher.setenv("LESAVKA_DISABLE_VIDEO_RENDER", "1", true);
launcher.setenv("LESAVKA_CLIPBOARD_PASTE", "0", true);
for (key, value) in runtime_env_vars(state) {
command.env(key, value);
launcher.setenv(key, value, true);
}
Ok(command.spawn()?)
let argv = [exe.as_os_str(), std::ffi::OsStr::new("--no-launcher")];
Ok(launcher.spawn(&argv)?)
}
pub fn stop_child_process(child_proc: &Rc<RefCell<Option<Child>>>) {
if let Some(mut child) = child_proc.borrow_mut().take() {
let _ = child.kill();
let _ = child.wait();
pub fn stop_child_process(child_proc: &Rc<RefCell<Option<RelayChild>>>) {
if let Some(child) = child_proc.borrow_mut().take()
&& !child.has_exited()
{
child.force_exit();
}
}
pub fn reap_exited_child(child_proc: &Rc<RefCell<Option<Child>>>) -> bool {
pub fn reap_exited_child(child_proc: &Rc<RefCell<Option<RelayChild>>>) -> bool {
let mut slot = child_proc.borrow_mut();
match slot.as_mut() {
Some(child) => match child.try_wait() {
Ok(Some(_)) => {
Some(child) => {
if child.has_exited() {
*slot = None;
false
} else {
true
}
Ok(None) | Err(_) => true,
},
}
None => false,
}
}

View File

@ -103,7 +103,7 @@
"client/src/launcher/ui_runtime.rs": {
"clippy_warnings": 10,
"doc_debt": 20,
"loc": 661
"loc": 670
},
"client/src/layout.rs": {
"clippy_warnings": 6,

View File

@ -109,7 +109,7 @@
"loc": 95
},
"server/src/audio.rs": {
"line_percent": 100.0,
"line_percent": 98.97,
"loc": 397
},
"server/src/bin/lesavka-uvc.rs": {