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, open_popout_window, path_marker, read_input_routing_state, reap_exited_child,
refresh_launcher_ui, refresh_test_buttons, routing_name, selected_combo_value, refresh_launcher_ui, refresh_test_buttons, routing_name, selected_combo_value,
selected_server_addr, selected_toggle_key, spawn_client_process, stop_child_process, 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::glib,
gtk::prelude::*, gtk::prelude::*,
lesavka_common::lesavka::CapturePowerCommand, lesavka_common::lesavka::CapturePowerCommand,
std::cell::{Cell, RefCell}, std::cell::{Cell, RefCell},
std::process::Child,
std::rc::Rc, std::rc::Rc,
std::time::Duration, std::time::Duration,
}; };
@ -64,7 +63,7 @@ pub fn run_gui_launcher(server_addr: String) -> Result<()> {
let catalog = Rc::new(DeviceCatalog::discover()); let catalog = Rc::new(DeviceCatalog::discover());
let state = Rc::new(RefCell::new(LauncherState::new())); let state = Rc::new(RefCell::new(LauncherState::new()));
state.borrow_mut().apply_catalog_defaults(&catalog); 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 tests = Rc::new(RefCell::new(DeviceTestController::new()));
let server_addr = Rc::new(server_addr); let server_addr = Rc::new(server_addr);
let focus_signal_path = Rc::new(launcher_focus_signal_path()); 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 { entry.server-entry {
min-height: 38px; min-height: 38px;
} }
picture {
content-fit: contain;
}
button.pill-toggle { button.pill-toggle {
min-height: 36px; min-height: 36px;
padding: 0 14px; padding: 0 14px;

View File

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

View File

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

View File

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