feat(linux): native build path + Linux-specific launcher optimizations
- X-Plane auto-detection now finds Steam (native + Flatpak), /opt and external-drive SteamLibrary installs, not just ~/ and macOS/Windows paths. - Close-to-background minimizes on Linux instead of hiding to tray, so the app is never stranded on desktops without a tray (e.g. vanilla GNOME). - Disable WebKitGTK's DMABUF renderer on Linux to avoid black/blank windows on some GPU/driver combos (overridable via the env var). - Launcher font stack gains Linux UI/mono fallbacks (Cantarell/Ubuntu/Noto). - scripts/build.sh: Docker-free Linux AppImage build — repack the cockpit into the prebuilt bundle for web-only changes; recompile natively for code changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -66,30 +66,71 @@ fn suggest_port(start: u16) -> u16 {
|
||||
start
|
||||
}
|
||||
|
||||
// A directory is an X-Plane 12 root iff it holds Resources/default data.
|
||||
fn is_xplane_root(p: &std::path::Path) -> bool {
|
||||
p.join("Resources").join("default data").is_dir()
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn default_xplane_path() -> Option<String> {
|
||||
let home = std::env::var("HOME")
|
||||
.or_else(|_| std::env::var("USERPROFILE"))
|
||||
.unwrap_or_default();
|
||||
let candidates = [
|
||||
let user = std::env::var("USER")
|
||||
.or_else(|_| std::env::var("USERNAME"))
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut candidates = vec![
|
||||
// Generic / cross-platform
|
||||
format!("{home}/X-Plane 12"),
|
||||
format!("{home}/Desktop/X-Plane 12"),
|
||||
format!("{home}/Games/X-Plane 12"),
|
||||
// Steam on Linux — native, plus the Flatpak Steam sandbox path
|
||||
format!("{home}/.steam/steam/steamapps/common/X-Plane 12"),
|
||||
format!("{home}/.local/share/Steam/steamapps/common/X-Plane 12"),
|
||||
format!("{home}/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/common/X-Plane 12"),
|
||||
// System-wide (Linux)
|
||||
"/opt/X-Plane 12".to_string(),
|
||||
// macOS
|
||||
"/Applications/X-Plane 12".to_string(),
|
||||
// Windows
|
||||
"C:/X-Plane 12".to_string(),
|
||||
"D:/X-Plane 12".to_string(),
|
||||
];
|
||||
|
||||
// Secondary/external drives: Steam libraries on extra disks usually mount
|
||||
// under /media/$USER, /run/media/$USER or /mnt. Probe each mounted volume
|
||||
// for the standard SteamLibrary layout (and a bare "X-Plane 12" folder).
|
||||
for base in [
|
||||
format!("/media/{user}"),
|
||||
format!("/run/media/{user}"),
|
||||
"/mnt".to_string(),
|
||||
] {
|
||||
if let Ok(entries) = std::fs::read_dir(&base) {
|
||||
for vol in entries.flatten().map(|e| e.path()) {
|
||||
candidates.push(
|
||||
vol.join("SteamLibrary/steamapps/common/X-Plane 12")
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
);
|
||||
candidates.push(
|
||||
vol.join("steamapps/common/X-Plane 12")
|
||||
.to_string_lossy()
|
||||
.into_owned(),
|
||||
);
|
||||
candidates.push(vol.join("X-Plane 12").to_string_lossy().into_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
candidates
|
||||
.into_iter()
|
||||
.find(|c| PathBuf::from(c).join("Resources").join("default data").is_dir())
|
||||
.find(|c| is_xplane_root(&PathBuf::from(c)))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn valid_xplane_path(path: String) -> bool {
|
||||
!path.is_empty()
|
||||
&& PathBuf::from(&path)
|
||||
.join("Resources")
|
||||
.join("default data")
|
||||
.is_dir()
|
||||
!path.is_empty() && is_xplane_root(&PathBuf::from(&path))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -225,11 +266,17 @@ pub fn run() {
|
||||
build_tray(app.handle())?;
|
||||
Ok(())
|
||||
})
|
||||
// Closing the window hides it instead of quitting, so the server keeps
|
||||
// serving tablets in the background. Quit from the tray.
|
||||
// Closing the window keeps the app alive so the server keeps serving
|
||||
// tablets in the background. On macOS/Windows the tray icon is always
|
||||
// reachable, so fully hide. On Linux many desktops (notably vanilla
|
||||
// GNOME) show no tray at all, so hiding would strand the app with no way
|
||||
// back — minimize instead, keeping it in the taskbar while it runs.
|
||||
.on_window_event(|window, event| {
|
||||
if let tauri::WindowEvent::CloseRequested { api, .. } = event {
|
||||
api.prevent_close();
|
||||
#[cfg(target_os = "linux")]
|
||||
let _ = window.minimize();
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let _ = window.hide();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,5 +2,14 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
fn main() {
|
||||
// WebKitGTK's DMABUF renderer shows a black/blank window on a number of Linux
|
||||
// GPU/driver combinations (notably Nvidia and older Mesa). This launcher is a
|
||||
// simple control panel, so favour reliability over GPU compositing: disable
|
||||
// the DMABUF renderer unless the user has already set the variable themselves.
|
||||
#[cfg(target_os = "linux")]
|
||||
if std::env::var_os("WEBKIT_DISABLE_DMABUF_RENDERER").is_none() {
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
}
|
||||
|
||||
xplane_cockpit_lib::run()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user