feat: pulseaudio slider module

This commit is contained in:
Brenno Lemos 2023-10-15 11:32:05 -03:00
parent c9e129cda2
commit 442a4b0da0
9 changed files with 221 additions and 2 deletions

19
include/ASlider.hpp Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "AModule.hpp"
#include "gtkmm/scale.h"
namespace waybar {
class ASlider : public AModule {
public:
ASlider(const Json::Value& config, const std::string& name, const std::string& id);
virtual void onValueChanged();
protected:
bool vertical_ = false;
int min_ = 0, max_ = 100, curr_ = 50;
Gtk::Scale scale_;
};
} // namespace waybar

View File

@ -0,0 +1,27 @@
#pragma once
#include <memory>
#include "ASlider.hpp"
#include "util/audio_backend.hpp"
namespace waybar::modules {
enum class PulseaudioSliderTarget {
Sink,
Source,
};
class PulseaudioSlider : public ASlider {
public:
PulseaudioSlider(const std::string&, const Json::Value&);
virtual ~PulseaudioSlider() = default;
void update() override;
void onValueChanged() override;
private:
std::shared_ptr<util::AudioBackend> backend = nullptr;
PulseaudioSliderTarget target = PulseaudioSliderTarget::Sink;
};
} // namespace waybar::modules

View File

@ -66,7 +66,7 @@ class AudioBackend {
AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag); AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag);
~AudioBackend(); ~AudioBackend();
void changeVolume(uint16_t volume, uint16_t max_volume = 100); void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100);
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100); void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100);
void setIgnoredSinks(const Json::Value& config); void setIgnoredSinks(const Json::Value& config);

View File

@ -0,0 +1,83 @@
waybar-pulseaudio-slider(5)
# NAME
waybar - pulseaudio slider module
# DESCRIPTION
The *pulseaudio slider* module displays and controls the current volume of the default sink or source as a bar.
The volume can be controlled by dragging the slider accross the bar, or clicking on a specific position.
# CONFIGURATION
*min*: ++
typeof: int ++
default: 0 ++
The minimum volume value the slider should display and set.
*max*: ++
typeof: int ++
default: 100 ++
The maximum volume value the slider should display and set.
*orientation*: ++
typeof: string ++
default: horizontal ++
The orientation of the slider. Can be either `horizontal` or `vertical`.
# EXAMPLES
```
"modules-right": [
"pulseaudio-slider",
],
"pulseaudio/slider": {
"min": 0,
"max": 100,
"orientation": "horizontal"
}
```
# STYLE
The slider is a component with multiple CSS Nodes, of which the following are exposed:
*#pulseaudio-slider*: ++
Controls the style of the box *around* the slider and bar.
*#pulseaudio-slider slider*: ++
Controls the style of the slider handle.
*#pulseaudio-slider trough*: ++
Controls the style of the part of the bar that has not been filled.
*#pulseaudio-slider highlight*: ++
Controls the style of the part of the bar that has been filled.
## STYLE EXAMPLE
```
#pulseaudio-slider slider {
min-height: 0px;
min-width: 0px;
opacity: 0;
background-image: none;
border: none;
box-shadow: none;
}
#pulseaudio-slider trough {
min-height: 80px;
min-width: 10px;
border-radius: 5px;
background-color: black;
}
#pulseaudio-slider highlight {
min-width: 10px;
border-radius: 5px;
background-color: green;
}
```

View File

@ -166,6 +166,7 @@ src_files = files(
'src/modules/image.cpp', 'src/modules/image.cpp',
'src/modules/temperature.cpp', 'src/modules/temperature.cpp',
'src/modules/user.cpp', 'src/modules/user.cpp',
'src/ASlider.cpp',
'src/main.cpp', 'src/main.cpp',
'src/bar.cpp', 'src/bar.cpp',
'src/client.cpp', 'src/client.cpp',
@ -274,6 +275,7 @@ endif
if libpulse.found() if libpulse.found()
add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp') add_project_arguments('-DHAVE_LIBPULSE', language: 'cpp')
src_files += 'src/modules/pulseaudio.cpp' src_files += 'src/modules/pulseaudio.cpp'
src_files += 'src/modules/pulseaudio_slider.cpp'
endif endif
if libjack.found() if libjack.found()
@ -441,6 +443,7 @@ if scdoc.found()
'waybar-mpris.5.scd', 'waybar-mpris.5.scd',
'waybar-network.5.scd', 'waybar-network.5.scd',
'waybar-pulseaudio.5.scd', 'waybar-pulseaudio.5.scd',
'waybar-pulseaudio-slider.5.scd',
'waybar-river-mode.5.scd', 'waybar-river-mode.5.scd',
'waybar-river-tags.5.scd', 'waybar-river-tags.5.scd',
'waybar-river-window.5.scd', 'waybar-river-window.5.scd',

34
src/ASlider.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "ASlider.hpp"
#include "gtkmm/adjustment.h"
#include "gtkmm/enums.h"
namespace waybar {
ASlider::ASlider(const Json::Value& config, const std::string& name, const std::string& id)
: AModule(config, name, id, false, false),
vertical_(config_["orientation"].asString() == "vertical"),
scale_(vertical_ ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL) {
scale_.set_name(name);
if (!id.empty()) {
scale_.get_style_context()->add_class(id);
}
event_box_.add(scale_);
scale_.signal_value_changed().connect(sigc::mem_fun(*this, &ASlider::onValueChanged));
if (config_["min"].isUInt()) {
min_ = config_["min"].asUInt();
}
if (config_["max"].isUInt()) {
max_ = config_["max"].asUInt();
}
scale_.set_inverted(vertical_);
scale_.set_draw_value(false);
scale_.set_adjustment(Gtk::Adjustment::create(curr_, min_, max_ + 1, 1, 1, 1));
}
void ASlider::onValueChanged() {}
} // namespace waybar

View File

@ -1,5 +1,9 @@
#include "factory.hpp" #include "factory.hpp"
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio_slider.hpp"
#endif
waybar::Factory::Factory(const Bar& bar, const Json::Value& config) : bar_(bar), config_(config) {} waybar::Factory::Factory(const Bar& bar, const Json::Value& config) : bar_(bar), config_(config) {}
waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
@ -136,6 +140,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "pulseaudio") { if (ref == "pulseaudio") {
return new waybar::modules::Pulseaudio(id, config_[name]); return new waybar::modules::Pulseaudio(id, config_[name]);
} }
if (ref == "pulseaudio/slider") {
return new waybar::modules::PulseaudioSlider(id, config_[name]);
}
#endif #endif
#ifdef HAVE_LIBMPDCLIENT #ifdef HAVE_LIBMPDCLIENT
if (ref == "mpd") { if (ref == "mpd") {

View File

@ -0,0 +1,45 @@
#include "modules/pulseaudio_slider.hpp"
namespace waybar::modules {
PulseaudioSlider::PulseaudioSlider(const std::string& id, const Json::Value& config)
: ASlider(config, "pulseaudio-slider", id) {
backend = util::AudioBackend::getInstance([this] { this->dp.emit(); });
backend->setIgnoredSinks(config_["ignored-sinks"]);
if (config_["target"].isString()) {
std::string target = config_["target"].asString();
if (target == "sink") {
this->target = PulseaudioSliderTarget::Sink;
} else if (target == "source") {
this->target = PulseaudioSliderTarget::Source;
}
}
}
void PulseaudioSlider::update() {
switch (target) {
case PulseaudioSliderTarget::Sink:
if (backend->getSinkMuted()) {
scale_.set_value(min_);
} else {
scale_.set_value(backend->getSinkVolume());
}
break;
case PulseaudioSliderTarget::Source:
if (backend->getSourceMuted()) {
scale_.set_value(min_);
} else {
scale_.set_value(backend->getSourceVolume());
}
break;
}
}
void PulseaudioSlider::onValueChanged() {
uint16_t volume = scale_.get_value();
backend->changeVolume(volume, min_, max_);
}
} // namespace waybar::modules

View File

@ -204,11 +204,12 @@ void AudioBackend::serverInfoCb(pa_context *context, const pa_server_info *i, vo
pa_context_get_source_info_list(context, sourceInfoCb, data); pa_context_get_source_info_list(context, sourceInfoCb, data);
} }
void AudioBackend::changeVolume(uint16_t volume, uint16_t max_volume) { void AudioBackend::changeVolume(uint16_t volume, uint16_t min_volume, uint16_t max_volume) {
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100; double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
pa_cvolume pa_volume = pa_volume_; pa_cvolume pa_volume = pa_volume_;
volume = std::min(volume, max_volume); volume = std::min(volume, max_volume);
volume = std::max(volume, min_volume);
pa_cvolume_set(&pa_volume, pa_volume_.channels, volume * volume_tick); pa_cvolume_set(&pa_volume, pa_volume_.channels, volume * volume_tick);
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this); pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);