Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rig-hub"
version = "0.1.0-alpha.1"
version = "0.1.0-alpha.2"
edition = "2024"
license = "GPL-3.0-or-later"
description = "One app for your mouse, cooler LCD, headset and mic on Linux"
Expand Down
2 changes: 1 addition & 1 deletion plasmoid/contents/ui/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PlasmoidItem {
// { panel: "85%", rows: [[label, value], …] } written by Rig Hub; null while it isn't running
property var status: null
// pgrep first: the file outlives Rig Hub, and stale numbers would look live
readonly property string poll: `pgrep -x rig-hub >/dev/null && cat "\${XDG_RUNTIME_DIR:-\${XDG_CACHE_HOME:-$HOME/.cache}}/rig-hub-status.json"`
readonly property string poll: `pgrep -x rig-hub >/dev/null && cat "\${XDG_RUNTIME_DIR:-\${XDG_CACHE_HOME:-$HOME/.cache}/rig-hub}/rig-hub-status.json"`
// a second launch just brings the running one to the front
readonly property string open: `PATH="$HOME/.local/bin:$HOME/.cargo/bin:$PATH" setsid -f rig-hub`

Expand Down
34 changes: 24 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,23 +232,37 @@ fn status_rows(st: &State) -> Vec<(String, String)> {
rows
}

/// Somewhere only this user can write: never a shared /tmp, where another user could plant files.
fn private_dir() -> PathBuf {
dirs::runtime_dir().or_else(dirs::cache_dir).unwrap_or_else(std::env::temp_dir)
/// Somewhere only this user can write, never a shared /tmp where another user could plant files
/// or symlinks. None if there's no such place: the status file and window raising are skipped.
fn private_dir() -> Option<PathBuf> {
if let Some(dir) = dirs::runtime_dir() {
return Some(dir); // the system makes it owner-only
}
// ~/.cache can be group-writable under a loose umask, so use our own owner-only folder in it
let dir = dirs::cache_dir()?.join("rig-hub");
std::fs::create_dir_all(&dir).ok()?;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o700)).ok()?;
}
Some(dir)
}

/// For the KDE widget (`plasmoid/`), which polls this file while Rig Hub runs. The widget looks in
/// the same place: `${XDG_RUNTIME_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}}`.
fn status_path() -> PathBuf {
private_dir().join("rig-hub-status.json")
/// the same place: `${XDG_RUNTIME_DIR:-${XDG_CACHE_HOME:-$HOME/.cache}/rig-hub}`.
fn status_path() -> Option<PathBuf> {
Some(private_dir()?.join("rig-hub-status.json"))
}

fn write_status(st: &State, rows: &[(String, String)]) -> bool {
let panel = match st.headset.ok().map(|h| &h.battery) {
Some(audio::Battery::Level(p) | audio::Battery::Charging(Some(p))) => format!("{p}%"),
_ => String::new(),
};
write_atomic(&status_path(), &serde_json::json!({ "panel": panel, "rows": rows }).to_string())
// nowhere to write yet: false, so the next refresh tries again
let Some(path) = status_path() else { return false };
write_atomic(&path, &serde_json::json!({ "panel": panel, "rows": rows }).to_string())
}

/// Write then rename, so readers (the widget, Plasma) never see half a file.
Expand Down Expand Up @@ -518,7 +532,7 @@ fn kwin_raise() {
fn raise() {
use std::io::Write;
use std::os::unix::fs::OpenOptionsExt;
let script = private_dir().join("rig-hub-raise.js");
let Some(script) = private_dir().map(|d| d.join("rig-hub-raise.js")) else { return };
let js = r#"for (const w of workspace.windowList()) if (w.resourceClass === "rig-hub") { w.minimized = false; workspace.activeWindow = w; }"#;
// KWin runs whatever is in this file, so nobody else may be able to write it
let _ = std::fs::remove_file(&script);
Expand Down Expand Up @@ -1353,8 +1367,8 @@ fn main() -> eframe::Result {
},
};
// numbers from a previous run would look live until our first refresh
if screenshot.is_none() {
let _ = std::fs::remove_file(status_path());
if let (None, Some(path)) = (&screenshot, status_path()) {
let _ = std::fs::remove_file(path);
}
#[cfg(target_os = "linux")]
install_widget();
Expand Down
Loading