Files
bar/src/widgets/volumeWidget.cpp
2026-01-31 11:46:12 +01:00

91 lines
2.6 KiB
C++

#include "widgets/volumeWidget.hpp"
#include <cmath>
#include <iostream>
#include <regex>
#include <sigc++/functors/mem_fun.h>
#include "helpers/command.hpp"
#include "giomm/applicationcommandline.h"
VolumeWidget::VolumeWidget() : Gtk::Box(Gtk::Orientation::HORIZONTAL) {
set_valign(Gtk::Align::CENTER);
set_halign(Gtk::Align::CENTER);
label.set_halign(Gtk::Align::CENTER);
label.set_valign(Gtk::Align::CENTER);
label.set_text("Vol");
append(label);
click = Gtk::GestureClick::create();
click->set_button(GDK_BUTTON_PRIMARY);
click->signal_released().connect([this](int, double, double) {
try {
(void)CommandHelper::exec(
"wpctl set-mute @DEFAULT_SINK@ toggle");
} catch (const std::exception &ex) {
std::cerr << "[VolumeWidget] failed to toggle mute: " << ex.what()
<< std::endl;
}
this->update();
});
add_controller(click);
update();
this->timeoutConn = Glib::signal_timeout().connect(
sigc::mem_fun(*this, &VolumeWidget::on_timeout), 100);
}
VolumeWidget::~VolumeWidget() {
if (this->timeoutConn.connected())
this->timeoutConn.disconnect();
}
void VolumeWidget::update() {
try {
const std::string out = CommandHelper::exec("wpctl get-volume @DEFAULT_SINK@");
std::smatch m;
std::regex r_percent(R"((\d+(?:\.\d+)?)%)");
std::regex r_number(R"((\d+(?:\.\d+)?))");
std::string text = out;
int percent = -1;
if (std::regex_search(text, m, r_percent)) {
percent = static_cast<int>(std::round(std::stod(m[1].str())));
} else if (std::regex_search(text, m, r_number)) {
const double v = std::stod(m[1].str());
if (v <= 1.0)
percent = static_cast<int>(std::round(v * 100.0));
else
percent = static_cast<int>(std::round(v));
}
if (percent >= 0) {
label.set_text(std::to_string(percent) + "%");
} else {
auto pos = text.find_first_not_of(" \t\n\r");
if (pos != std::string::npos) {
auto end = text.find_last_not_of(" \t\n\r");
label.set_text(text.substr(pos, end - pos + 1));
} else {
label.set_text("?");
}
}
} catch (const std::exception &ex) {
std::cerr << "[VolumeWidget] failed to read volume: " << ex.what()
<< std::endl;
label.set_text("N/A");
}
}
bool VolumeWidget::on_timeout() {
update();
return true; // keep timeout active
}