Add Phase 5 enhancements: security, i18n, analysis, backup, notifications

- Database v8 migration: tags, pinned, avg_startup_ms columns
- Security scanning with CVE matching and batch scan
- Bundled library extraction and vulnerability reports
- Desktop notification system for security alerts
- Backup/restore system for AppImage configurations
- i18n framework with gettext support
- Runtime analysis and Wayland compatibility detection
- AppStream metadata and Flatpak-style build support
- File watcher module for live directory monitoring
- Preferences panel with GSettings integration
- CLI interface for headless operation
- Detail view: tabbed layout with ViewSwitcher in title bar,
  health score, sandbox controls, changelog links
- Library view: sort dropdown, context menu enhancements
- Dashboard: system status, disk usage, launch history
- Security report page with scan and export
- Packaging: meson build, PKGBUILD, metainfo
This commit is contained in:
lashman
2026-02-27 17:16:41 +02:00
parent a7ed3742fb
commit 423323d5a9
51 changed files with 10583 additions and 481 deletions

View File

@@ -310,6 +310,103 @@ pub fn detect_desktop_environment() -> String {
}
}
/// Result of analyzing a running process for Wayland usage.
#[derive(Debug, Clone)]
pub struct RuntimeAnalysis {
pub pid: u32,
pub has_wayland_socket: bool,
pub has_x11_connection: bool,
pub env_vars: Vec<(String, String)>,
}
impl RuntimeAnalysis {
/// Human-readable status label.
pub fn status_label(&self) -> &'static str {
match (self.has_wayland_socket, self.has_x11_connection) {
(true, false) => "Native Wayland",
(true, true) => "Wayland + X11 fallback",
(false, true) => "X11 / XWayland",
(false, false) => "Unknown",
}
}
/// Machine-readable status string for database storage.
pub fn as_status_str(&self) -> &'static str {
match (self.has_wayland_socket, self.has_x11_connection) {
(true, false) => "native",
(true, true) => "native",
(false, true) => "xwayland",
(false, false) => "unknown",
}
}
}
/// Analyze a running process to determine its actual Wayland/X11 usage.
/// Inspects /proc/<pid>/fd for Wayland and X11 sockets, and reads
/// relevant environment variables from /proc/<pid>/environ.
pub fn analyze_running_process(pid: u32) -> Result<RuntimeAnalysis, String> {
let proc_path = format!("/proc/{}", pid);
if !std::path::Path::new(&proc_path).exists() {
return Err(format!("Process {} not found", pid));
}
// Check file descriptors for Wayland and X11 sockets
let fd_dir = format!("{}/fd", proc_path);
let mut has_wayland_socket = false;
let mut has_x11_connection = false;
if let Ok(entries) = std::fs::read_dir(&fd_dir) {
for entry in entries.flatten() {
if let Ok(target) = std::fs::read_link(entry.path()) {
let target_str = target.to_string_lossy();
if target_str.contains("wayland") {
has_wayland_socket = true;
}
if target_str.contains("/tmp/.X11-unix/") || target_str.contains("@/tmp/.X11") {
has_x11_connection = true;
}
}
}
}
// Read relevant environment variables
let environ_path = format!("{}/environ", proc_path);
let mut env_vars = Vec::new();
let relevant_vars = [
"WAYLAND_DISPLAY", "DISPLAY", "GDK_BACKEND", "QT_QPA_PLATFORM",
"XDG_SESSION_TYPE", "SDL_VIDEODRIVER", "CLUTTER_BACKEND",
];
if let Ok(data) = std::fs::read(&environ_path) {
for entry in data.split(|&b| b == 0) {
if let Ok(s) = std::str::from_utf8(entry) {
if let Some((key, value)) = s.split_once('=') {
if relevant_vars.contains(&key) {
env_vars.push((key.to_string(), value.to_string()));
}
}
}
}
}
// Also check env vars for hints if fd inspection was inconclusive
if !has_wayland_socket {
has_wayland_socket = env_vars.iter().any(|(k, v)| {
(k == "GDK_BACKEND" && v.contains("wayland"))
|| (k == "QT_QPA_PLATFORM" && v.contains("wayland"))
|| (k == "WAYLAND_DISPLAY" && !v.is_empty())
});
}
Ok(RuntimeAnalysis {
pid,
has_wayland_socket,
has_x11_connection,
env_vars,
})
}
/// Check if XWayland is available on the system.
pub fn has_xwayland() -> bool {
// Check if Xwayland process is running