Compare commits

...

5 Commits

6 changed files with 134 additions and 12 deletions

89
Cargo.lock generated
View File

@ -328,6 +328,12 @@ dependencies = [
"subtle",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.12"
@ -400,6 +406,12 @@ dependencies = [
"version_check",
]
[[package]]
name = "hashbrown"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
[[package]]
name = "heck"
version = "0.5.0"
@ -421,6 +433,16 @@ dependencies = [
"digest",
]
[[package]]
name = "indexmap"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
@ -500,6 +522,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "microxdg"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0ba94daabea2c803df477d4dc1d37a6f15726e4bed53be7067022ddb89328e"
[[package]]
name = "niri-ipc"
version = "25.5.1"
@ -515,11 +543,13 @@ dependencies = [
"anyhow",
"clap",
"libsystemd",
"microxdg",
"niri-ipc",
"nix 0.30.1",
"serde",
"serde_json",
"smol",
"toml",
"tracing",
"tracing-subscriber",
]
@ -699,6 +729,15 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_spanned"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.10.9"
@ -809,6 +848,47 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "toml"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_write",
"winnow",
]
[[package]]
name = "toml_write"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
[[package]]
name = "tracing"
version = "0.1.41"
@ -1059,3 +1139,12 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
dependencies = [
"memchr",
]

View File

@ -26,4 +26,6 @@ serde_json = "1.0"
smol = "2.0"
serde = { version = "1.0", features = ["derive"] }
clap = { version = "4.5", features = ["derive"] }
microxdg = "0.2.0"
toml = "0.8.23"

View File

@ -29,7 +29,7 @@ pub async fn event_consumer(tx: channel::Sender<Event>) -> Result<()> {
loop {
let _ = socket.read_line(&mut buf).await?;
let event: Event = serde_json::from_str(&buf)?;
tracing::debug!("event: {:?}", event);
tracing::trace!("event: {:?}", event);
tx.send(event).await?;
}
unreachable!("Listener loop ended");

View File

@ -2,9 +2,29 @@ mod ipc;
mod manager;
mod socket;
use anyhow::{Context, Result};
use std::io::Read;
use anyhow::{Context, Result, anyhow};
use microxdg::Xdg;
use niri_tag::Config;
fn main() -> Result<()> {
// try to read a config
let xdg = Xdg::new()?;
let mut config_dir = xdg.config()?;
config_dir.push("niri-tag");
config_dir.push("config.toml");
let config = std::fs::File::open(config_dir)
.map_err(|e| anyhow!(e))
.and_then(|mut f| {
let mut buf = String::new();
f.read_to_string(&mut buf).map_err(|e| anyhow!(e))?;
Ok(buf)
})
.and_then(|buf| toml::from_str::<Config>(&buf).map_err(|e| anyhow!(e)))
.inspect_err(|e| tracing::error!("Using default config due to: {}", e))
.unwrap_or_default();
// let systemd know we're ready
let _ = libsystemd::daemon::notify(false, &[libsystemd::daemon::NotifyState::Ready])?;
// debug stuff
@ -25,7 +45,7 @@ fn main() -> Result<()> {
smol::spawn(ipc::event_provider(event_rx, fullstate_tx)).detach();
// begin managing niri tags
smol::block_on(async {
let niri_tag = manager::NiriTag::new(event_tx)
let niri_tag = manager::NiriTag::new(config, event_tx)
.await
.context("Initialising niri tag manager")
.unwrap();

View File

@ -4,7 +4,7 @@ use niri_ipc::{
Action, Event, Reply, Request, Response, Window, Workspace, WorkspaceReferenceArg,
state::{EventStreamState, EventStreamStatePart},
};
use niri_tag::{TagCmd, TagEvent, TagState};
use niri_tag::{Config, TagCmd, TagEvent, TagState};
use smol::{
channel::{self, Sender},
future,
@ -14,6 +14,7 @@ use smol::{
use std::collections::HashMap;
pub struct NiriTag {
config: Config,
tags: HashMap<u8, bool>,
windows: HashMap<u64, u8>,
active_ws: Vec<u64>,
@ -28,13 +29,14 @@ enum TagAction {
}
impl NiriTag {
pub async fn new(ev_tx: channel::Sender<TagEvent>) -> Result<Self> {
pub async fn new(config: Config, ev_tx: channel::Sender<TagEvent>) -> Result<Self> {
Ok(Self {
config,
tags: HashMap::new(),
windows: HashMap::new(),
active_ws: Vec::new(),
state: EventStreamState::default(),
socket: create_niri_socket().await?,
active_ws: Vec::new(),
ev_tx,
})
}
@ -241,6 +243,7 @@ impl NiriTag {
let fullstate: HashMap<u8, TagState> = self
.tags
.iter()
.filter(|(t, _)| **t != 0)
.map(|(&t, &enabled)| {
(
t,
@ -302,14 +305,14 @@ impl NiriTag {
ChangeTag(t)
}
TagCmd::ToggleTag(t) => {
let visible = *self.tags.entry(t).or_insert(false);
if visible {
let new_state = !*self.tags.entry(t).or_insert(false);
if new_state {
send_event(self.ev_tx.clone(), TagEvent::TagEnabled(t)).await;
} else {
send_event(self.ev_tx.clone(), TagEvent::TagDisabled(t)).await;
}
tracing::debug!("toggling tag {} to {}", t, !visible);
self.tags.insert(t, !visible);
tracing::debug!("toggling tag {} to {}", t, new_state);
self.tags.insert(t, new_state);
ChangeTag(t)
}
},
@ -391,8 +394,11 @@ impl NiriTag {
tag_rx: channel::Receiver<TagCmd>,
fullstate_rx: channel::Receiver<channel::Sender<HashMap<u8, TagState>>>,
) -> Result<()> {
// base tag is always visible
// prepopulate tags
self.tags.insert(0, true);
(1..=self.config.prepopulate).for_each(|i| {
self.tags.insert(i, true);
});
loop {
let recvd: Receivable = future::or(
@ -403,7 +409,7 @@ impl NiriTag {
),
)
.await?;
tracing::debug!("manager received {:?}", recvd);
tracing::trace!("manager received {:?}", recvd);
let res = self.handle_recvd(recvd).await;
match res {

View File

@ -30,3 +30,8 @@ pub struct TagState {
pub occupied: bool,
pub urgent: bool,
}
#[derive(Default, Deserialize)]
pub struct Config {
pub prepopulate: u8,
}