|
| 1 | +use std::{path::Path, process::Command}; |
| 2 | +use tauri::{AppHandle, Runtime}; |
| 3 | +use tauri_plugin_shell::ShellExt; |
| 4 | + |
| 5 | +enum LinuxDesktopEnvironment { |
| 6 | + Gnome, |
| 7 | + Kde, |
| 8 | +} |
| 9 | + |
| 10 | +impl LinuxDesktopEnvironment { |
| 11 | + // This impl is based on: https://wiki.archlinux.org/title/Desktop_entries#Usage |
| 12 | + fn launch_app_via_desktop_file<P: AsRef<Path>>(&self, file: P) -> Result<(), String> { |
| 13 | + let path = file.as_ref(); |
| 14 | + if !path.try_exists().map_err(|e| e.to_string())? { |
| 15 | + return Err(format!("desktop file [{}] does not exist", path.display())); |
| 16 | + } |
| 17 | + |
| 18 | + let cmd_output = match self { |
| 19 | + Self::Gnome => { |
| 20 | + let uri = path |
| 21 | + .file_stem() |
| 22 | + .expect("the desktop file should contain a file stem part"); |
| 23 | + |
| 24 | + Command::new("gtk-launch") |
| 25 | + .arg(uri) |
| 26 | + .output() |
| 27 | + .map_err(|e| e.to_string())? |
| 28 | + } |
| 29 | + Self::Kde => Command::new("kde-open") |
| 30 | + .arg(path) |
| 31 | + .output() |
| 32 | + .map_err(|e| e.to_string())?, |
| 33 | + }; |
| 34 | + |
| 35 | + if !cmd_output.status.success() { |
| 36 | + return Err(format!( |
| 37 | + "failed to launch app via desktop file [{}], underlying command stderr [{}]", |
| 38 | + path.display(), |
| 39 | + String::from_utf8_lossy(&cmd_output.stderr) |
| 40 | + )); |
| 41 | + } |
| 42 | + |
| 43 | + Ok(()) |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +fn get_linux_desktop_environment() -> Option<LinuxDesktopEnvironment> { |
| 48 | + let de_os_str = std::env::var_os("XDG_CURRENT_DESKTOP")?; |
| 49 | + let de_str = de_os_str |
| 50 | + .into_string() |
| 51 | + .expect("$XDG_CURRENT_DESKTOP should be UTF-8 encoded"); |
| 52 | + |
| 53 | + let de = match de_str.as_str() { |
| 54 | + "GNOME" => LinuxDesktopEnvironment::Gnome, |
| 55 | + "KDE" => LinuxDesktopEnvironment::Kde, |
| 56 | + |
| 57 | + unsupported_de => unimplemented!( |
| 58 | + "This desktop environment [{}] has not been supported yet", |
| 59 | + unsupported_de |
| 60 | + ), |
| 61 | + }; |
| 62 | + |
| 63 | + Some(de) |
| 64 | +} |
| 65 | + |
| 66 | +/// Homemade open() function to support open Linux applications via the `.desktop` file. |
| 67 | +// |
| 68 | +// tauri_plugin_shell::open() is deprecated, but we still use it. |
| 69 | +#[allow(deprecated)] |
| 70 | +#[tauri::command] |
| 71 | +pub async fn open<R: Runtime>(app_handle: AppHandle<R>, path: String) -> Result<(), String> { |
| 72 | + if cfg!(target_os = "linux") { |
| 73 | + let borrowed_path = Path::new(&path); |
| 74 | + if let Some(file_extension) = borrowed_path.extension() { |
| 75 | + if file_extension == "desktop" { |
| 76 | + let desktop_environment = get_linux_desktop_environment().expect("The Linux OS is running without a desktop, Coco could never run in such a environment"); |
| 77 | + return desktop_environment.launch_app_via_desktop_file(path); |
| 78 | + } |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + app_handle |
| 83 | + .shell() |
| 84 | + .open(path, None) |
| 85 | + .map_err(|e| e.to_string()) |
| 86 | +} |
0 commit comments