~tsdh/public-inbox

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH swayrbar] Add pipewire (wpctl) module

Details
Message ID
<20241001095000.856501-1-bitraid@protonmail.ch>
DKIM signature
pass
Download raw message
Patch: +205 -0
---
 swayrbar/src/bar.rs          |   1 +
 swayrbar/src/module.rs       |   1 +
 swayrbar/src/module/wpctl.rs | 203 +++++++++++++++++++++++++++++++++++
 3 files changed, 205 insertions(+)
 create mode 100644 swayrbar/src/module/wpctl.rs

diff --git a/swayrbar/src/bar.rs b/swayrbar/src/bar.rs
index 8321c3b..b62053b 100644
--- a/swayrbar/src/bar.rs
+++ b/swayrbar/src/bar.rs
@@ -97,6 +97,7 @@ fn create_modules(config: config::Config) -> Vec<Box<dyn BarModuleFn>> {
            "battery" => module::battery::create(mc),
            "date" => module::date::create(mc),
            "pactl" => module::pactl::create(mc),
            "wpctl" => module::wpctl::create(mc),
            "nmcli" => module::wifi::create(module::wifi::WifiTool::Nmcli, mc),
            "iwctl" => module::wifi::create(module::wifi::WifiTool::Iwctl, mc),
            "cmd" => module::cmd::create(mc),
diff --git a/swayrbar/src/module.rs b/swayrbar/src/module.rs
index fe2d39f..c3e3ba4 100644
--- a/swayrbar/src/module.rs
+++ b/swayrbar/src/module.rs
@@ -23,6 +23,7 @@ pub mod battery;
pub mod cmd;
pub mod date;
pub mod pactl;
pub mod wpctl;
pub mod sysinfo;
pub mod wifi;
pub mod window;
diff --git a/swayrbar/src/module/wpctl.rs b/swayrbar/src/module/wpctl.rs
new file mode 100644
index 0000000..f3c7241
--- /dev/null
+++ b/swayrbar/src/module/wpctl.rs
@@ -0,0 +1,203 @@
// Copyright (C) 2022-2023  Tassilo Horn <tsdh@gnu.org>
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program.  If not, see <https://www.gnu.org/licenses/>.

//! The wpctl `swayrbar` module.

use crate::config;
use crate::module::{BarModuleFn, RefreshReason};
use crate::shared::fmt::subst_placeholders;
use once_cell::sync::Lazy;
use regex::Regex;
use std::collections::HashMap;
use std::process::Command;
use std::sync::Mutex;
use swaybar_types as s;

const NAME: &str = "wpctl";

struct State {
    volume: u8,
    muted: bool,
    volume_source: u8,
    muted_source: bool,
    cached_text: String,
}

pub static VOLUME_RX: Lazy<Regex> =
    Lazy::new(|| Regex::new(r".* (?<num>\d+)\.(?<frac>\d{2}).*").unwrap());

fn run_wpctl(args: &[&str]) -> String {
    match Command::new("wpctl").args(args).output() {
        Ok(output) => String::from_utf8_lossy(&output.stdout).to_string(),
        Err(err) => {
            log::error!("Could not run wpctl: {err}");
            String::new()
        }
    }
}

fn get_volume(device: &str) -> (u8, bool) {
    let output = run_wpctl(&["get-volume", device]);
    let mut volume = String::new();
    VOLUME_RX
        .captures(&output)
        .unwrap()
        .expand("$num$frac", &mut volume);
    (volume.parse::<u8>().unwrap_or(255_u8), output.contains("[MUTED]"))
}

pub struct BarModuleWpctl {
    config: config::ModuleConfig,
    state: Mutex<State>,
}

fn refresh_state(state: &mut State, fmt_str: &str, html_escape: bool) {
    (state.volume, state.muted) = get_volume("@DEFAULT_AUDIO_SINK@");
    (state.volume_source, state.muted_source) = get_volume("@DEFAULT_AUDIO_SOURCE@");
    state.cached_text = subst_placeholders(fmt_str, html_escape, state);
}

fn subst_placeholders(fmt: &str, html_escape: bool, state: &State) -> String {
    subst_placeholders!(fmt, html_escape, {
        "volume" => {
            state.volume
        },
        "muted" =>{
            if state.muted {
                " muted"
            } else {
                ""
            }
        },
        "volume_source" => {
            state.volume_source
        },
        "muted_source" =>{
            if state.muted_source {
                " muted"
            } else {
                ""
            }
        },
    })
}

pub fn create(config: config::ModuleConfig) -> Box<dyn BarModuleFn> {
    Box::new(BarModuleWpctl {
        config,
        state: Mutex::new(State {
            volume: 255_u8,
            muted: false,
            volume_source: 255_u8,
            muted_source: false,
            cached_text: String::new(),
        }),
    })
}

impl BarModuleFn for BarModuleWpctl {
    fn default_config(instance: String) -> config::ModuleConfig
    where
        Self: Sized,
    {
        config::ModuleConfig {
            name: NAME.to_owned(),
            instance,
            format: "🔈 Vol: {volume:{:3}}%{muted}".to_owned(),
            html_escape: Some(true),
            on_click: Some(HashMap::from([
                ("Left".to_owned(),
                 vec!["foot".to_owned(), "watch".to_owned(),
                 "wpctl".to_owned(), "status".to_owned()]),
                (
                    "Right".to_owned(),
                    vec![
                        "wpctl".to_owned(),
                        "set-mute".to_owned(),
                        "@DEFAULT_AUDIO_SINK@".to_owned(),
                        "toggle".to_owned(),
                    ],
                ),
                (
                    "WheelUp".to_owned(),
                    vec![
                        "wpctl".to_owned(),
                        "set-volume".to_owned(),
                        "@DEFAULT_AUDIO_SINK@".to_owned(),
                        "1%+".to_owned(),
                    ],
                ),
                (
                    "WheelDown".to_owned(),
                    vec![
                        "wpctl".to_owned(),
                        "set-volume".to_owned(),
                        "@DEFAULT_AUDIO_SINK@".to_owned(),
                        "1%-".to_owned(),
                    ],
                ),
            ])),
        }
    }

    fn get_config(&self) -> &config::ModuleConfig {
        &self.config
    }

    fn build(&self, reason: &RefreshReason) -> s::Block {
        let mut state = self.state.lock().expect("Could not lock state.");

        if match reason {
            RefreshReason::TimerEvent => true,
            RefreshReason::ClickEvent { name, instance } => {
                name == &self.config.name && instance == &self.config.instance
            }
            _ => false,
        } {
            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_cmd_args<'a>(&'a self, cmd: &'a [String]) -> Vec<String> {
        let state = self.state.lock().expect("Could not lock state.");
        cmd.iter()
            .map(|arg| subst_placeholders(arg, false, &state))
            .collect()
    }
}
-- 
2.46.1
Details
Message ID
<87zfnm29uz.fsf@gnu.org>
In-Reply-To
<20241001095000.856501-1-bitraid@protonmail.ch> (view parent)
DKIM signature
pass
Download raw message
bitraid <bitraid@protonmail.ch> writes:

Hi, thanks a lot!

the code looks fine and I'm happy to accept your contribution.  Some
minor nitpicks below.

> --- /dev/null
> +++ b/swayrbar/src/module/wpctl.rs
> @@ -0,0 +1,203 @@
> +// Copyright (C) 2022-2023  Tassilo Horn <tsdh@gnu.org>

This should be just 2024.  The module didn't exist before.  And feel
free to mention you as author, too.

And would you mind writing a short README.md section about the new
module in the configuration section and mention it in the swayrbar
summary?  Basically look for pactl and write something similar about
wpctl directly below.

Thanks again,
  Tassilo
Reply to thread Export thread (mbox)