Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,29 @@ sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libssl-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```

**Linux** (Fedora/RPM):
```bash
sudo dnf install -y \
webkit2gtk4.1-devel \
openssl-devel \
gtk3-devel \
libayatana-appindicator-gtk3-devel \
librsvg2-devel \
curl wget file gcc make

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env

# Enable cron scheduling support
sudo dnf install -y cronie
sudo systemctl enable --now crond
```

> **Fedora note:** If `libayatana-appindicator-gtk3-devel` is not found, try `libappindicator-gtk3-devel`. If `webkit2gtk4.1-devel` is missing, also install `libsoup3-devel`.

> **Wayland:** ATM supports Wayland natively via gnome-terminal or konsole. If you are running a pure Wayland session (no XWayland), ensure one of these is installed.

</details>

**Build for production**:
Expand Down Expand Up @@ -221,7 +244,8 @@ pnpm tauri build
|----------|--------|---------|
| Windows | Full support | PowerShell |
| macOS | Full support | bash (Terminal.app) |
| Linux | Supported | bash |
| Linux (Debian/Ubuntu) | Supported | gnome-terminal, xterm, or any installed emulator |
| Linux (Fedora/RPM) | Supported | konsole, gnome-terminal, alacritty, kitty, xterm |

---

Expand Down
67 changes: 52 additions & 15 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,42 @@ fn delete_scheduled_task(task_name: String) -> Result<String, String> {
}
}

/// Finds an available terminal emulator, preferring Wayland-native ones when running
/// under a pure Wayland session (WAYLAND_DISPLAY set, DISPLAY unset).
#[cfg(target_os = "linux")]
fn find_terminal_emulator() -> Option<&'static str> {
let wayland = std::env::var("WAYLAND_DISPLAY").is_ok();
let x11 = std::env::var("DISPLAY").is_ok();
let pure_wayland = wayland && !x11;

// X11-only terminals that won't work without XWayland
const X11_ONLY: &[&str] = &["xterm", "urxvt"];

// Ordered by preference: Debian compat first, then common DEs, then fallbacks
const CANDIDATES: &[&str] = &[
"x-terminal-emulator", // Debian/Ubuntu alternatives system
"gnome-terminal", // GNOME (native Wayland)
"konsole", // KDE (native Wayland, default on Fedora KDE)
"xfce4-terminal", // XFCE
"alacritty", // Modern, widespread
"kitty", // Modern, widespread
"tilix", // GNOME alternative
"xterm", // X11 fallback
"urxvt", // X11 fallback
];

CANDIDATES.iter().find(|&&term| {
if pure_wayland && X11_ONLY.contains(&term) {
return false;
}
StdCommand::new("which")
.arg(term)
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}).copied()
}

/// Opens a visible terminal window running the given script.
#[tauri::command]
fn open_terminal(script_path: String) -> Result<(), String> {
Expand Down Expand Up @@ -287,21 +323,22 @@ fn open_terminal(script_path: String) -> Result<(), String> {

#[cfg(target_os = "linux")]
{
let terminals = [
("x-terminal-emulator", vec!["-e", &script_path]),
("gnome-terminal", vec!["--", &script_path]),
("xterm", vec!["-e", &script_path]),
];
let mut launched = false;
for (term, args) in &terminals {
if StdCommand::new(term).args(args).spawn().is_ok() {
launched = true;
break;
}
}
if !launched {
return Err("No terminal emulator found".into());
}
let term = find_terminal_emulator().ok_or_else(|| {
"No terminal emulator found. Install gnome-terminal, konsole, xterm, or another terminal emulator.".to_string()
})?;

// Terminals that use "--" as argument separator instead of "-e"
const DASH_DASH_TERMS: &[&str] = &["gnome-terminal", "konsole", "kitty"];
let args: Vec<&str> = if DASH_DASH_TERMS.contains(&term) {
vec!["--", &script_path]
} else {
vec!["-e", &script_path]
};

StdCommand::new(term)
.args(&args)
.spawn()
.map_err(|e| format!("Failed to open terminal '{}': {}", term, e))?;
}

Ok(())
Expand Down