mirror of
https://github.com/devmobasa/wayscriber.git
synced 2026-11-01 07:36:42 +01:00
`--language CODE` sets the interface language for one run of --active, --freeze, --daemon or --about without changing config.toml. It accepts the spellings `[ui] language` does and takes precedence over both WAYSCRIBER_LANGUAGE and the config. A daemon started with it gives it to the About windows it opens, and to its overlays as an optional environment input that an older overlay ignores. The process broker strips that input from every other helper, so a configurator opened from an overlay keeps previewing its own Language row. With --daemon-toggle or an overlay action the flag is an error, since a running daemon's overlays cannot be changed from outside. `--list-languages` prints each language's code and name, the configured language, and the language in effect with the setting that decided it. Languages now carry their native and English names, and the configurator's Language row takes its labels from them. The help text, README, CONFIG.md, I18N.md and config.example.toml describe both options.
149 lines
5.1 KiB
Rust
149 lines
5.1 KiB
Rust
//! Backend-owned launch of the About window and configurator.
|
|
//!
|
|
//! Input records semantic intent only. The backend resolves executables and
|
|
//! talks to the process broker because both are runtime side effects.
|
|
|
|
use std::ffi::{OsStr, OsString};
|
|
|
|
use super::WaylandState;
|
|
use crate::configurator_destination::{ConfiguratorDestination, configurator_launch_arguments};
|
|
use crate::env_vars::CONFIGURATOR_ENV;
|
|
use crate::i18n::tr;
|
|
use crate::input::state::{HelperLaunchRequest, Toast, ToastPriority};
|
|
|
|
fn spawn_detached(
|
|
kind: crate::process_broker::HelperKind,
|
|
program: &OsStr,
|
|
arguments: &[OsString],
|
|
) -> anyhow::Result<crate::process_broker::BrokerChild> {
|
|
crate::process_broker::current()?.try_spawn(
|
|
kind,
|
|
crate::process_broker::HelperLifetime::DetachedAfterExec,
|
|
program,
|
|
arguments,
|
|
Vec::new(),
|
|
)
|
|
}
|
|
|
|
fn launch_deferred_by_busy_broker(error: &anyhow::Error) -> bool {
|
|
crate::process_broker::error_kind(error) == Some(crate::process_broker::BrokerErrorKind::Busy)
|
|
}
|
|
|
|
fn launch_failure_message(error: &anyhow::Error, failed: &'static str) -> &'static str {
|
|
if launch_deferred_by_busy_broker(error) {
|
|
tr("Busy with another task. Try again in a moment.")
|
|
} else {
|
|
failed
|
|
}
|
|
}
|
|
|
|
impl WaylandState {
|
|
pub(in crate::backend::wayland) fn handle_helper_launch(
|
|
&mut self,
|
|
request: HelperLaunchRequest,
|
|
) {
|
|
match request {
|
|
HelperLaunchRequest::About => self.launch_about_helper(),
|
|
HelperLaunchRequest::Configurator(destination) => {
|
|
self.launch_configurator_helper(destination);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn launch_about_helper(&mut self) {
|
|
let executable = match std::env::current_exe() {
|
|
Ok(path) => path,
|
|
Err(error) => {
|
|
log::error!("Failed to resolve the Wayscriber executable for About: {error}");
|
|
self.input_state.push_toast(
|
|
ToastPriority::Critical,
|
|
"launcher",
|
|
Toast::error(tr("Could not locate Wayscriber to open About.")),
|
|
);
|
|
return;
|
|
}
|
|
};
|
|
|
|
match spawn_detached(
|
|
crate::process_broker::HelperKind::About,
|
|
executable.as_os_str(),
|
|
&crate::about_window::launch_arguments(),
|
|
) {
|
|
Ok(child) => {
|
|
log::info!("Launched About window (pid {})", child.id());
|
|
self.input_state.should_exit = true;
|
|
}
|
|
Err(error) => {
|
|
log::error!("Failed to launch the About window: {error:#}");
|
|
self.input_state.push_toast(
|
|
ToastPriority::Critical,
|
|
"launcher",
|
|
Toast::error(launch_failure_message(
|
|
&error,
|
|
tr("Failed to open About (see logs)."),
|
|
)),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn launch_configurator_helper(&mut self, destination: Option<ConfiguratorDestination>) {
|
|
let binary = std::env::var(CONFIGURATOR_ENV)
|
|
.unwrap_or_else(|_| "wayscriber-configurator".to_string());
|
|
let arguments = configurator_launch_arguments(destination.as_ref());
|
|
|
|
match spawn_detached(
|
|
crate::process_broker::HelperKind::Configurator,
|
|
OsStr::new(&binary),
|
|
&arguments,
|
|
) {
|
|
Ok(child) => {
|
|
log::info!(
|
|
"Launched wayscriber-configurator (binary: {binary}, pid: {})",
|
|
child.id()
|
|
);
|
|
self.input_state.should_exit = true;
|
|
}
|
|
Err(error) => {
|
|
log::error!("Failed to launch wayscriber-configurator using '{binary}': {error:#}");
|
|
log::error!("Set {CONFIGURATOR_ENV} to override the executable path if needed.");
|
|
if !launch_deferred_by_busy_broker(&error)
|
|
&& self.input_state.open_config_file_default()
|
|
{
|
|
log::info!(
|
|
"Queued config file for the default application because wayscriber-configurator was unavailable"
|
|
);
|
|
} else {
|
|
self.input_state.push_toast(
|
|
ToastPriority::Critical,
|
|
"launcher",
|
|
Toast::error(launch_failure_message(
|
|
&error,
|
|
tr("Failed to launch configurator (see logs)."),
|
|
)),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn ordinary_launch_failure_keeps_specific_notice() {
|
|
let error = anyhow::anyhow!(
|
|
"unrelated diagnostic: process broker is busy running another helper; No such file"
|
|
)
|
|
.context("launch context");
|
|
|
|
assert!(!launch_deferred_by_busy_broker(&error));
|
|
assert_eq!(
|
|
launch_failure_message(&error, "Failed to open About (see logs)."),
|
|
"Failed to open About (see logs)."
|
|
);
|
|
}
|
|
}
|