refactor(config): replace launch_wrapper with use_uwsm boolean
- Replace complex auto-detection with explicit use_uwsm config option - Remove detect_launch_wrapper() function and hyprctl/uwsm auto-detection - Use gio launch as default (always available via GTK4's glib2 dependency) - When use_uwsm=true, launch via uwsm app -- for systemd session integration - Add error handling for when uwsm is enabled but not installed - Update documentation in README.md, CLAUDE.md, and config.example.toml
This commit is contained in:
@@ -208,8 +208,8 @@ cp /usr/share/doc/owlry/config.example.toml ~/.config/owlry/config.toml
|
||||
show_icons = true
|
||||
max_results = 10
|
||||
tabs = ["app", "cmd", "uuctl"]
|
||||
# terminal_command = "kitty" # Auto-detected
|
||||
# launch_wrapper = "uwsm app --" # Auto-detected
|
||||
# terminal_command = "kitty" # Auto-detected
|
||||
# use_uwsm = false # Enable for systemd session integration
|
||||
|
||||
[appearance]
|
||||
width = 850
|
||||
|
||||
@@ -27,11 +27,12 @@ pub struct GeneralConfig {
|
||||
/// Terminal command (auto-detected if not specified)
|
||||
#[serde(default)]
|
||||
pub terminal_command: Option<String>,
|
||||
/// Launch wrapper command for app execution.
|
||||
/// Examples: "uwsm app --", "hyprctl dispatch exec --", "systemd-run --user --"
|
||||
/// If None or empty, launches directly via sh -c
|
||||
/// Enable uwsm (Universal Wayland Session Manager) for launching apps.
|
||||
/// When enabled, desktop files are launched via `uwsm app -- <file>`
|
||||
/// which starts apps in a proper systemd user session.
|
||||
/// When disabled (default), apps are launched via `gio launch`.
|
||||
#[serde(default)]
|
||||
pub launch_wrapper: Option<String>,
|
||||
pub use_uwsm: bool,
|
||||
/// Provider tabs shown in the header bar.
|
||||
/// Valid values: app, cmd, uuctl, bookmark, calc, clip, dmenu, emoji, file, script, ssh, sys, web
|
||||
#[serde(default = "default_tabs")]
|
||||
@@ -44,7 +45,7 @@ impl Default for GeneralConfig {
|
||||
show_icons: true,
|
||||
max_results: 100,
|
||||
terminal_command: None,
|
||||
launch_wrapper: None,
|
||||
use_uwsm: false,
|
||||
tabs: default_tabs(),
|
||||
}
|
||||
}
|
||||
@@ -396,28 +397,6 @@ fn default_pomodoro_break() -> u32 {
|
||||
5
|
||||
}
|
||||
|
||||
/// Detect the best launch wrapper for the current session
|
||||
/// Checks for uwsm (Universal Wayland Session Manager) and hyprland
|
||||
fn detect_launch_wrapper() -> Option<String> {
|
||||
// Check if running under uwsm (has UWSM_FINALIZE_VARNAMES or similar uwsm env vars)
|
||||
if (std::env::var("UWSM_FINALIZE_VARNAMES").is_ok()
|
||||
|| std::env::var("__UWSM_SELECT_TAG").is_ok())
|
||||
&& command_exists("uwsm") {
|
||||
debug!("Detected uwsm session, using 'uwsm app --' wrapper");
|
||||
return Some("uwsm app --".to_string());
|
||||
}
|
||||
|
||||
// Check if running under Hyprland
|
||||
if std::env::var("HYPRLAND_INSTANCE_SIGNATURE").is_ok()
|
||||
&& command_exists("hyprctl") {
|
||||
debug!("Detected Hyprland session, using 'hyprctl dispatch exec --' wrapper");
|
||||
return Some("hyprctl dispatch exec --".to_string());
|
||||
}
|
||||
|
||||
// No wrapper needed for other environments
|
||||
debug!("No launch wrapper detected, using direct execution");
|
||||
None
|
||||
}
|
||||
|
||||
/// Detect the best available terminal emulator
|
||||
/// Fallback chain:
|
||||
@@ -578,11 +557,6 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-detect launch wrapper if not configured
|
||||
if config.general.launch_wrapper.is_none() {
|
||||
config.general.launch_wrapper = detect_launch_wrapper();
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
|
||||
@@ -1341,14 +1341,13 @@ impl MainWindow {
|
||||
}
|
||||
}
|
||||
|
||||
/// Launch a .desktop file using gio (GLib's desktop entry launcher).
|
||||
/// Launch a .desktop file.
|
||||
///
|
||||
/// gio is always available as it's part of glib2, which is a hard dependency
|
||||
/// of GTK4. It handles D-Bus activation, field codes, Terminal flag, etc.
|
||||
/// per the freedesktop Desktop Entry specification.
|
||||
/// When `use_uwsm` is enabled in config, launches via `uwsm app -- <file>`
|
||||
/// which starts the app in a proper systemd user session.
|
||||
///
|
||||
/// Optionally wraps with a session manager (uwsm, hyprctl) for proper
|
||||
/// process tracking in Wayland compositors.
|
||||
/// Otherwise, uses `gio launch` which is always available (part of glib2/GTK4)
|
||||
/// and handles D-Bus activation, field codes, Terminal flag, etc.
|
||||
fn launch_desktop_file(desktop_path: &str, config: &Config) -> std::io::Result<std::process::Child> {
|
||||
use std::path::Path;
|
||||
|
||||
@@ -1360,25 +1359,32 @@ impl MainWindow {
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::NotFound, msg));
|
||||
}
|
||||
|
||||
match &config.general.launch_wrapper {
|
||||
// With wrapper: wrapper manages the process, gio handles the .desktop file
|
||||
Some(wrapper) if !wrapper.is_empty() => {
|
||||
info!("Launching via {} + gio launch: {}", wrapper, desktop_path);
|
||||
let mut parts: Vec<&str> = wrapper.split_whitespace().collect();
|
||||
let cmd = parts.remove(0);
|
||||
Command::new(cmd)
|
||||
.args(&parts)
|
||||
.args(["gio", "launch"])
|
||||
.arg(desktop_path)
|
||||
.spawn()
|
||||
}
|
||||
// No wrapper: use gio directly
|
||||
_ => {
|
||||
info!("Launching via gio launch: {}", desktop_path);
|
||||
Command::new("gio")
|
||||
.args(["launch", desktop_path])
|
||||
.spawn()
|
||||
if config.general.use_uwsm {
|
||||
// Check if uwsm is available
|
||||
let uwsm_available = Command::new("which")
|
||||
.arg("uwsm")
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.status()
|
||||
.map(|s| s.success())
|
||||
.unwrap_or(false);
|
||||
|
||||
if !uwsm_available {
|
||||
let msg = "uwsm is enabled in config but not installed";
|
||||
log::error!("{}", msg);
|
||||
crate::notify::notify("Launch failed", msg);
|
||||
return Err(std::io::Error::new(std::io::ErrorKind::NotFound, msg));
|
||||
}
|
||||
|
||||
info!("Launching via uwsm: {}", desktop_path);
|
||||
Command::new("uwsm")
|
||||
.args(["app", "--", desktop_path])
|
||||
.spawn()
|
||||
} else {
|
||||
info!("Launching via gio: {}", desktop_path);
|
||||
Command::new("gio")
|
||||
.args(["launch", desktop_path])
|
||||
.spawn()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1391,8 +1397,9 @@ impl MainWindow {
|
||||
command.to_string()
|
||||
};
|
||||
|
||||
// Detect shell commands that shouldn't use a wrapper
|
||||
let is_shell_command = cmd.starts_with("playerctl ")
|
||||
// Shell/system commands run directly without uwsm wrapper
|
||||
// (they're typically short-lived or system utilities)
|
||||
let is_system_command = cmd.starts_with("playerctl ")
|
||||
|| cmd.starts_with("dbus-send ")
|
||||
|| cmd.starts_with("systemctl ")
|
||||
|| cmd.starts_with("journalctl ")
|
||||
@@ -1402,19 +1409,14 @@ impl MainWindow {
|
||||
|| cmd.contains(" > ")
|
||||
|| cmd.contains(" < ");
|
||||
|
||||
match &config.general.launch_wrapper {
|
||||
Some(wrapper) if !wrapper.is_empty() && !is_shell_command => {
|
||||
info!("Launching command via {}: {}", wrapper, cmd);
|
||||
let mut parts: Vec<&str> = wrapper.split_whitespace().collect();
|
||||
let wrapper_cmd = parts.remove(0);
|
||||
Command::new(wrapper_cmd)
|
||||
.args(&parts)
|
||||
.args(["sh", "-c", &cmd])
|
||||
.spawn()
|
||||
}
|
||||
_ => {
|
||||
Command::new("sh").arg("-c").arg(&cmd).spawn()
|
||||
}
|
||||
// Use uwsm for regular commands if enabled (and not a system command)
|
||||
if config.general.use_uwsm && !is_system_command {
|
||||
info!("Launching command via uwsm: {}", cmd);
|
||||
Command::new("uwsm")
|
||||
.args(["app", "--", "sh", "-c", &cmd])
|
||||
.spawn()
|
||||
} else {
|
||||
Command::new("sh").arg("-c").arg(&cmd).spawn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,11 @@ max_results = 10
|
||||
# Uncomment to override:
|
||||
# terminal_command = "kitty"
|
||||
|
||||
# Launch wrapper for app execution (auto-detected for uwsm/Hyprland)
|
||||
# Examples: "uwsm app --", "hyprctl dispatch exec --", ""
|
||||
# launch_wrapper = "uwsm app --"
|
||||
# Enable uwsm (Universal Wayland Session Manager) for launching apps.
|
||||
# When enabled, apps are launched via "uwsm app --" which starts them
|
||||
# in a proper systemd user session for better process management.
|
||||
# Requires: uwsm to be installed
|
||||
# use_uwsm = true
|
||||
|
||||
# Header tabs - providers shown as toggle buttons (Ctrl+1, Ctrl+2, etc.)
|
||||
# Values: app, cmd, uuctl, bookmark, calc, clip, dmenu, emoji, file, script, ssh, sys, web
|
||||
|
||||
Reference in New Issue
Block a user