Add a wifi module which can display wifi network name and signal strength. It gathers this information by running nmcli. Karl Eklund (1): Add wifi module Cargo.lock | 2 +- README.md | 7 ++ swayrbar/Cargo.toml | 2 +- swayrbar/src/bar.rs | 1 + swayrbar/src/module.rs | 1 + swayrbar/src/module/wifi.rs | 141 ++++++++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 swayrbar/src/module/wifi.rs -- 2.34.5
swayr/patches/arch.yml: SUCCESS in 4m5s [Add wifi module][0] from [~ke][1] [0]: https://lists.sr.ht/~tsdh/public-inbox/patches/36332 [1]: mailto:localpart@gmail.com ✓ #867892 SUCCESS swayr/patches/arch.yml https://builds.sr.ht/~tsdh/job/867892
Tassilo Horn <tsdh@gnu.org> writes:
Karl Eklund <localpart@gmail.com> writes: Hi Karl,
Karl Eklund <localpart@gmail.com> writes: Hi Karl,
Tassilo Horn <tsdh@gnu.org> writes: Hey Karl,
I've asked on #srht on libera.chat. There is or was some issue where cloning a repo using the "Clone repo to your account" button resulted in a broken repo with exactly the above problem. When did you clone the repo to your account? Anyway, I suggest you simply rebase your commits on the wifi branch and squash them into a single commit and then send that as a new patch to this list again. Bye, Tassilo
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~tsdh/public-inbox/patches/36332/mbox | git am -3Learn more about email & git
Tassilo Horn <tsdh@gnu.org> writes: > > Whatever you prefer. When I should merge from you, it's best you send > the output of > > $ git request-pull -p \ > origin/master \ > https://my.repo.com/my-fork \ > wifi > > where origin is the name of the swayr upstream remote and the URL is the > one of your fork. OK, here goes... The following changes since commit 1a0eec73e339ba166d17effab0551b61c3ca0595: Release swayrbar-0.2.4 (2022-09-27 16:56:18 +0200) are available in the Git repository at: https://git.sr.ht/~ke/swayr wifi for you to fetch changes up to f5a81f25c3646e704794bf3e6c132c2c3c692ca2: Make nmcli module prettier when there is no wifi (2022-10-24 15:49:12 +0200)
Thank you, that's what I need. Unfortunately, I get an error with "git fetch" when trying to fetch from your remote... --8<---------------cut here---------------start------------->8--- ❯ git fetch --all --verbose Fetching origin From git.sr.ht:~tsdh/swayr = [up to date] main -> origin/main Fetching jirutka POST git-upload-pack (155 bytes) From https://git.sr.ht/~jirutka/swayr = [up to date] main -> jirutka/main = [up to date] optimize-size -> jirutka/optimize-size = [up to date] sys-config -> jirutka/sys-config = [up to date] truncation -> jirutka/truncation Fetching ke POST git-upload-pack (155 bytes) POST git-upload-pack (958 bytes) POST git-upload-pack (gzip 1758 to 929 bytes) POST git-upload-pack (gzip 1858 to 984 bytes) POST git-upload-pack (167 bytes) remote: fatal: failed to read object 1a0eec73e339ba166d17effab0551b61c3ca0595: Permission denied remote: aborting due to possible repository corruption on the remote side. fatal: protocol error: bad pack header error: could not fetch ke --8<---------------cut here---------------end--------------->8--- I have no clue why that is. The named commit is the last one I have, too. Do you know what might cause that? Otherwise, I'd ask on the ~sircmpwn/sr.ht-discuss@lists.sr.ht list as it might very well be a bug and add you to the Cc in case you're not subscribed to that list. Bye, Tassilo
---------------------------------------------------------------- Karl Eklund (5): Add wifi module Add "bars" placeholder to wifi module If there is no connection, clear the state Rename wifi module to nmcli Make nmcli module prettier when there is no wifi Cargo.lock | 2 +- README.md | 10 +++ swayrbar/Cargo.toml | 2 +- swayrbar/src/bar.rs | 1 + swayrbar/src/module.rs | 1 + swayrbar/src/module/nmcli.rs | 153 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 swayrbar/src/module/nmcli.rs diff --git a/Cargo.lock b/Cargo.lock index 4e2c013..d4ba99d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,7 +704,7 @@ dependencies = [ [[package]] name = "swayrbar" -version = "0.2.4" +version = "0.2.4-nmcli" dependencies = [ "battery", "chrono", diff --git a/README.md b/README.md index a21fe09..e626ecd 100644 --- a/README.md +++ b/README.md @@ -800,6 +800,16 @@ By default, it has the following click bindings: * `WheelUp` and `WheelDown` increase/decrease the volume of the default sink. +#### The `nmcli` module + +The `nmcli` module requires NetworkManager and the `nmcli` command line tool. +It can display information about the wi-fi connection. It supports the +following placeholders: +* `{name}` wi-fi network name. +* `{signal}` wireless signal strength. +* `{bars}` a visualization of connection strength, like "▂▄▆_". + + #### The `date` module The `date` module shows the date and time by defining the `format` using diff --git a/swayrbar/Cargo.toml b/swayrbar/Cargo.toml index 942f2da..798e028 100644 --- a/swayrbar/Cargo.toml +++ b/swayrbar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swayrbar" -version = "0.2.4" +version = "0.2.4-nmcli" edition = "2021" homepage = "https://sr.ht/~tsdh/swayr/#swayrbar" repository = "https://git.sr.ht/~tsdh/swayr" diff --git a/swayrbar/src/bar.rs b/swayrbar/src/bar.rs index ea51ce4..e68c6d0 100644 --- a/swayrbar/src/bar.rs +++ b/swayrbar/src/bar.rs @@ -101,6 +101,7 @@ fn create_modules(config: config::Config) -> Vec<Box<dyn BarModuleFn>> { "battery" => module::battery::BarModuleBattery::create(mc), "date" => module::date::BarModuleDate::create(mc), "pactl" => module::pactl::BarModulePactl::create(mc), + "nmcli" => module::nmcli::BarModuleNmcli::create(mc), unknown => { log::warn!("Unknown module name '{}'. Ignoring...", unknown); continue; diff --git a/swayrbar/src/module.rs b/swayrbar/src/module.rs index 152cc45..74427cb 100644 --- a/swayrbar/src/module.rs +++ b/swayrbar/src/module.rs @@ -22,6 +22,7 @@ pub mod battery; pub mod date; pub mod pactl; pub mod sysinfo; +pub mod nmcli; pub mod window; #[derive(Debug, PartialEq, Eq)] diff --git a/swayrbar/src/module/nmcli.rs b/swayrbar/src/module/nmcli.rs new file mode 100644 index 0000000..7bf2f1f --- /dev/null +++ b/swayrbar/src/module/nmcli.rs @@ -0,0 +1,153 @@ +use crate::config; +use crate::module::BarModuleFn; +use crate::shared::fmt::subst_placeholders; +use std::sync::Mutex; +use swaybar_types as s; + +use super::RefreshReason; + +const NAME: &str = "nmcli"; + +struct State { + cached_text: String, + signal: Option<String>, + name: Option<String>, + bars: Option<String>, +} + +pub struct BarModuleNmcli { + config: config::ModuleConfig, + state: Mutex<State>, +} + +fn run_nmcli() -> Result<String, String> { + let cmd = "nmcli"; + let args = "-c no -g IN-USE,SSID,SIGNAL,BARS dev wifi".split(" "); + let output = std::process::Command::new(cmd) + .args(args) + .output() + .map_err(|e| format!("Failed to run nmcli: {}", e))?; + + if !output.status.success() { + return Err(format!( + "nmcli failed with status code {}", + output.status.code().unwrap_or(-1) + )); + } + + Ok(String::from_utf8(output.stdout).unwrap()) +} + +fn subst_placeholders(fmt: &str, html_escape: bool, state: &State) -> String { + subst_placeholders!(fmt, html_escape, { + "name" => { + match &state.name { + None => "No wi-fi", + Some(name) => name, + } + }, + "signal" => { + match &state.signal { + None => "".to_owned(), + Some(signal) => " ".to_owned() + signal + "%", + } + }, + "bars" => { + match &state.bars { + None => "".to_owned(), + Some(bars) => " ".to_owned() + bars, + } + }, + }) +} + +fn refresh_state(state: &mut State, fmt_str: &str, html_escape: bool) { + if let Ok(output) = run_nmcli() { + state.name = None; + state.signal = None; + state.bars = None; + if let Some(line) = output.lines().find(|line| line.starts_with("*")) { + let mut parts = line.split(":"); + parts.next(); + state.name = Some(parts.next().unwrap().to_string()); + state.signal = Some(parts.next().unwrap().to_string()); + state.bars = Some(parts.next().unwrap().to_string()); + } + } + state.cached_text = subst_placeholders(fmt_str, html_escape, state); +} + +impl BarModuleFn for BarModuleNmcli { + fn create(config: config::ModuleConfig) -> Box<dyn BarModuleFn> + where + Self: Sized, + { + Box::new(BarModuleNmcli { + config, + state: Mutex::new(State { + cached_text: String::new(), + signal: None, + name: None, + bars: None, + }), + }) + } + + fn default_config(instance: String) -> config::ModuleConfig + where + Self: Sized, + { + config::ModuleConfig { + name: NAME.to_owned(), + instance, + format: "📡 Wi-fi: {name}{bars}{signal}".to_owned(), + html_escape: Some(false), + on_click: None, + } + } + + fn get_config(&self) -> &config::ModuleConfig { + &self.config + } + + fn build(&self, nai: &Option<super::NameInstanceAndReason>) -> s::Block { + let mut state = self.state.lock().expect("Could not lock state."); + + if self.should_refresh(nai, true, &[RefreshReason::ClickEvent]) { + refresh_state( + &mut state, + &self.config.format, + self.config.is_html_escape(), + ); + } + + s::Block { + name: Some(NAME.to_owned()), + instance: Some(self.config.instance.clone()), + full_text: state.cached_text.to_owned(), + align: Some(s::Align::Left), + markup: Some(s::Markup::Pango), + short_text: None, + color: None, + background: None, + border: None, + border_top: None, + border_bottom: None, + border_left: None, + border_right: None, + min_width: None, + urgent: None, + separator: Some(true), + separator_block_width: None, + } + } + + fn subst_args<'a>(&'a self, cmd: &'a [String]) -> Option<Vec<String>> { + let state = self.state.lock().expect("Could not lock state."); + Some( + cmd.iter() + .map(|arg| subst_placeholders(arg, false, &state)) + .collect(), + ) + } +}
Karl Eklund <localpart@gmail.com> writes: Hi Karl,
From: Karl Eklund <localpart@gmail.com> --- Cargo.lock | 2 +- README.md | 7 ++ swayrbar/Cargo.toml | 2 +- swayrbar/src/bar.rs | 1 + swayrbar/src/module.rs | 1 + swayrbar/src/module/wifi.rs | 141 ++++++++++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 swayrbar/src/module/wifi.rs diff --git a/Cargo.lock b/Cargo.lock index 4e2c013..bd61f2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -704,7 +704,7 @@ dependencies = [ [[package]] name = "swayrbar" -version = "0.2.4" +version = "0.2.4-wifi" dependencies = [ "battery", "chrono", diff --git a/README.md b/README.md index a21fe09..e33e84e 100644 --- a/README.md +++ b/README.md @@ -800,6 +800,13 @@ By default, it has the following click bindings: * `WheelUp` and `WheelDown` increase/decrease the volume of the default sink. +#### The `wifi` module + +The `wifi` module displays information about the wi-fi connection. It supports the following placeholders: +* `{name}` Wi-fi network name. +* `{signal}` wireless signal strength. + + #### The `date` module The `date` module shows the date and time by defining the `format` using diff --git a/swayrbar/Cargo.toml b/swayrbar/Cargo.toml index 942f2da..da2febd 100644 --- a/swayrbar/Cargo.toml +++ b/swayrbar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "swayrbar" -version = "0.2.4" +version = "0.2.4-wifi" edition = "2021" homepage = "https://sr.ht/~tsdh/swayr/#swayrbar" repository = "https://git.sr.ht/~tsdh/swayr" diff --git a/swayrbar/src/bar.rs b/swayrbar/src/bar.rs index ea51ce4..2fa78a5 100644 --- a/swayrbar/src/bar.rs +++ b/swayrbar/src/bar.rs @@ -101,6 +101,7 @@ fn create_modules(config: config::Config) -> Vec<Box<dyn BarModuleFn>> { "battery" => module::battery::BarModuleBattery::create(mc), "date" => module::date::BarModuleDate::create(mc), "pactl" => module::pactl::BarModulePactl::create(mc), + "wifi" => module::wifi::BarModuleWifi::create(mc), unknown => { log::warn!("Unknown module name '{}'. Ignoring...", unknown); continue; diff --git a/swayrbar/src/module.rs b/swayrbar/src/module.rs index 152cc45..268cbc0 100644 --- a/swayrbar/src/module.rs +++ b/swayrbar/src/module.rs @@ -22,6 +22,7 @@ pub mod battery; pub mod date; pub mod pactl; pub mod sysinfo; +pub mod wifi; pub mod window; #[derive(Debug, PartialEq, Eq)] diff --git a/swayrbar/src/module/wifi.rs b/swayrbar/src/module/wifi.rs new file mode 100644 index 0000000..d77be88 --- /dev/null +++ b/swayrbar/src/module/wifi.rs @@ -0,0 +1,141 @@ +use crate::config; +use crate::module::BarModuleFn; +use crate::shared::fmt::subst_placeholders; +use std::sync::Mutex; +use swaybar_types as s; + +use super::RefreshReason; + +const NAME: &str = "wifi"; + +struct State { + cached_text: String, + signal: Option<String>, + name: Option<String>, +} + +pub struct BarModuleWifi { + config: config::ModuleConfig, + state: Mutex<State>, +} + +fn run_nmcli() -> Result<String, String> { + let cmd = "nmcli"; + let args = "-c no -g IN-USE,SSID,SIGNAL,BARS dev wifi".split(" "); + let output = std::process::Command::new(cmd) + .args(args) + .output() + .map_err(|e| format!("Failed to run nmcli: {}", e))?; + + if !output.status.success() { + return Err(format!( + "nmcli failed with status code {}", + output.status.code().unwrap_or(-1) + )); + } + + Ok(String::from_utf8(output.stdout).unwrap()) +} + +fn subst_placeholders(fmt: &str, html_escape: bool, state: &State) -> String { + subst_placeholders!(fmt, html_escape, { + "name" => { + match &state.name { + None => "No wi-fi", + Some(name) => name, + } + }, + "signal" => { + match &state.signal { + None => "None", + Some(signal) => signal, + } + }, + }) +} + +fn refresh_state(state: &mut State, fmt_str: &str, html_escape: bool) { + if let Ok(output) = run_nmcli() { + if let Some(line) = output.lines().find(|line| line.starts_with("*")) { + let mut parts = line.split(":"); + parts.next(); + state.name = Some(parts.next().unwrap().to_string()); + state.signal = Some(parts.next().unwrap().to_string()); + } + } + state.cached_text = subst_placeholders(fmt_str, html_escape, state); +} + +impl BarModuleFn for BarModuleWifi { + fn create(config: config::ModuleConfig) -> Box<dyn BarModuleFn> + where + Self: Sized, + { + Box::new(BarModuleWifi { + config, + state: Mutex::new(State { + cached_text: String::new(), + signal: None, + name: None, + }), + }) + } + + fn default_config(instance: String) -> config::ModuleConfig + where + Self: Sized, + { + config::ModuleConfig { + name: NAME.to_owned(), + instance, + format: "📡 Wi-fi {name} {signal}%".to_owned(), + html_escape: Some(false), + on_click: None, + } + } + + fn get_config(&self) -> &config::ModuleConfig { + &self.config + } + + fn build(&self, nai: &Option<super::NameInstanceAndReason>) -> s::Block { + let mut state = self.state.lock().expect("Could not lock state."); + + if self.should_refresh(nai, true, &[RefreshReason::ClickEvent]) { + refresh_state( + &mut state, + &self.config.format, + self.config.is_html_escape(), + ); + } + + s::Block { + name: Some(NAME.to_owned()), + instance: Some(self.config.instance.clone()), + full_text: state.cached_text.to_owned(), + align: Some(s::Align::Left), + markup: Some(s::Markup::Pango), + short_text: None, + color: None, + background: None, + border: None, + border_top: None, + border_bottom: None, + border_left: None, + border_right: None, + min_width: None, + urgent: None, + separator: Some(true), + separator_block_width: None, + } + } + + fn subst_args<'a>(&'a self, cmd: &'a [String]) -> Option<Vec<String>> { + let state = self.state.lock().expect("Could not lock state."); + Some( + cmd.iter() + .map(|arg| subst_placeholders(arg, false, &state)) + .collect(), + ) + } +} -- 2.34.5
builds.sr.ht <builds@sr.ht>swayr/patches/arch.yml: SUCCESS in 4m5s [Add wifi module][0] from [~ke][1] [0]: https://lists.sr.ht/~tsdh/public-inbox/patches/36332 [1]: mailto:localpart@gmail.com ✓ #867892 SUCCESS swayr/patches/arch.yml https://builds.sr.ht/~tsdh/job/867892