Merge pull request #5045 from finitemonkey/master
Additional options when muted for the PulseAudio-Slider module
This commit is contained in:
@@ -6,11 +6,6 @@
|
|||||||
#include "util/audio_backend.hpp"
|
#include "util/audio_backend.hpp"
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
|
|
||||||
enum class PulseaudioSliderTarget {
|
|
||||||
Sink,
|
|
||||||
Source,
|
|
||||||
};
|
|
||||||
|
|
||||||
class PulseaudioSlider : public ASlider {
|
class PulseaudioSlider : public ASlider {
|
||||||
public:
|
public:
|
||||||
PulseaudioSlider(const std::string&, const Json::Value&);
|
PulseaudioSlider(const std::string&, const Json::Value&);
|
||||||
@@ -21,7 +16,15 @@ class PulseaudioSlider : public ASlider {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<util::AudioBackend> backend = nullptr;
|
std::shared_ptr<util::AudioBackend> backend = nullptr;
|
||||||
PulseaudioSliderTarget target = PulseaudioSliderTarget::Sink;
|
util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
|
||||||
|
|
||||||
|
bool zero_on_mute = true;
|
||||||
|
bool unmute_on_volume_change = true;
|
||||||
|
// zero_on_mute and unmute_on_volume_change default to true
|
||||||
|
// in order to maintain previous behaviour when using a
|
||||||
|
// config in which these values are undefined
|
||||||
|
|
||||||
|
bool previously_muted = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
@@ -14,6 +14,11 @@
|
|||||||
|
|
||||||
namespace waybar::util {
|
namespace waybar::util {
|
||||||
|
|
||||||
|
enum class PulseaudioTarget {
|
||||||
|
Sink,
|
||||||
|
Source,
|
||||||
|
};
|
||||||
|
|
||||||
class AudioBackend {
|
class AudioBackend {
|
||||||
private:
|
private:
|
||||||
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
|
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
|
||||||
@@ -92,6 +97,10 @@ class AudioBackend {
|
|||||||
void toggleSourceMute();
|
void toggleSourceMute();
|
||||||
void toggleSourceMute(bool);
|
void toggleSourceMute(bool);
|
||||||
|
|
||||||
|
uint16_t getVolume(PulseaudioTarget) const;
|
||||||
|
bool getMuted(PulseaudioTarget) const;
|
||||||
|
void unmute(PulseaudioTarget);
|
||||||
|
|
||||||
bool isBluetooth();
|
bool isBluetooth();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,20 @@ The volume can be controlled by dragging the slider across the bar or clicking o
|
|||||||
The orientation of the slider. Can be either `horizontal` or `vertical`.
|
The orientation of the slider. Can be either `horizontal` or `vertical`.
|
||||||
|
|
||||||
*expand*: ++
|
*expand*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: false ++
|
default: false ++
|
||||||
Enables this module to consume all left over space dynamically.
|
Enables this module to consume all left over space dynamically.
|
||||||
|
|
||||||
|
*zero-on-mute*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
`true` = The slider will be set to `min` when the source/sink is muted. ++
|
||||||
|
`false` = The slider will continue to show the unmuted volume level when the source/sink is muted.
|
||||||
|
|
||||||
|
*unmute-on-volume-change*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Specifies whether to unmute a muted souce/sink when its volume is changed by the user moving the slider.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
@@ -41,7 +52,9 @@ The volume can be controlled by dragging the slider across the bar or clicking o
|
|||||||
"pulseaudio/slider": {
|
"pulseaudio/slider": {
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 100,
|
"max": 100,
|
||||||
"orientation": "horizontal"
|
"orientation": "horizontal",
|
||||||
|
"zero-on-mute": false,
|
||||||
|
"unmute-on-volume-change": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -52,6 +65,9 @@ The slider is a component with multiple CSS Nodes, of which the following are ex
|
|||||||
*#pulseaudio-slider*: ++
|
*#pulseaudio-slider*: ++
|
||||||
Controls the style of the box *around* the slider and bar.
|
Controls the style of the box *around* the slider and bar.
|
||||||
|
|
||||||
|
*#pulseaudio-slider.muted*: ++
|
||||||
|
Controls the style when the audio source/sink is muted.
|
||||||
|
|
||||||
*#pulseaudio-slider slider*: ++
|
*#pulseaudio-slider slider*: ++
|
||||||
Controls the style of the slider handle.
|
Controls the style of the slider handle.
|
||||||
|
|
||||||
@@ -85,4 +101,8 @@ The slider is a component with multiple CSS Nodes, of which the following are ex
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
background: green;
|
background: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pulseaudio-slider.muted highlight {
|
||||||
|
background-color: orange;
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,73 +10,51 @@ PulseaudioSlider::PulseaudioSlider(const std::string& id, const Json::Value& con
|
|||||||
if (config_["target"].isString()) {
|
if (config_["target"].isString()) {
|
||||||
std::string target = config_["target"].asString();
|
std::string target = config_["target"].asString();
|
||||||
if (target == "sink") {
|
if (target == "sink") {
|
||||||
this->target = PulseaudioSliderTarget::Sink;
|
this->target = util::PulseaudioTarget::Sink;
|
||||||
} else if (target == "source") {
|
} else if (target == "source") {
|
||||||
this->target = PulseaudioSliderTarget::Source;
|
this->target = util::PulseaudioTarget::Source;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config_["zero-on-mute"].isBool()) {
|
||||||
|
zero_on_mute = config_["zero-on-mute"].asBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_["unmute-on-volume-change"].isBool()) {
|
||||||
|
unmute_on_volume_change = config_["unmute-on-volume-change"].asBool();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseaudioSlider::update() {
|
void PulseaudioSlider::update() {
|
||||||
switch (target) {
|
uint16_t display_value = backend->getVolume(target);
|
||||||
case PulseaudioSliderTarget::Sink:
|
bool is_muted = backend->getMuted(target);
|
||||||
if (backend->getSinkMuted()) {
|
|
||||||
scale_.set_value(min_);
|
|
||||||
} else {
|
|
||||||
scale_.set_value(backend->getSinkVolume());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PulseaudioSliderTarget::Source:
|
if (is_muted) {
|
||||||
if (backend->getSourceMuted()) {
|
if (zero_on_mute) {
|
||||||
scale_.set_value(min_);
|
display_value = min_;
|
||||||
} else {
|
}
|
||||||
scale_.set_value(backend->getSourceVolume());
|
if (!previously_muted) {
|
||||||
}
|
scale_.get_style_context()->add_class("muted");
|
||||||
break;
|
}
|
||||||
|
} else if (previously_muted) {
|
||||||
|
scale_.get_style_context()->remove_class("muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scale_.set_value(display_value);
|
||||||
|
|
||||||
|
previously_muted = is_muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PulseaudioSlider::onValueChanged() {
|
void PulseaudioSlider::onValueChanged() {
|
||||||
bool is_mute = false;
|
uint16_t slider_value = scale_.get_value();
|
||||||
|
|
||||||
switch (target) {
|
// Avoid setting sink/source to volume 0 if the user muted it via other means.
|
||||||
case PulseaudioSliderTarget::Sink:
|
if (!backend->getMuted(target) || slider_value != 0) {
|
||||||
if (backend->getSinkMuted()) {
|
if (unmute_on_volume_change) {
|
||||||
is_mute = true;
|
backend->unmute(target);
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PulseaudioSliderTarget::Source:
|
|
||||||
if (backend->getSourceMuted()) {
|
|
||||||
is_mute = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t volume = scale_.get_value();
|
|
||||||
|
|
||||||
if (is_mute) {
|
|
||||||
// Avoid setting sink/source to volume 0 if the user muted if via another mean.
|
|
||||||
if (volume == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the sink/source is mute, but the user clicked the slider, unmute it!
|
|
||||||
else {
|
|
||||||
switch (target) {
|
|
||||||
case PulseaudioSliderTarget::Sink:
|
|
||||||
backend->toggleSinkMute(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PulseaudioSliderTarget::Source:
|
|
||||||
backend->toggleSourceMute(false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
backend->changeVolume(slider_value, min_, max_);
|
||||||
}
|
}
|
||||||
|
|
||||||
backend->changeVolume(volume, min_, max_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
@@ -261,6 +261,14 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t AudioBackend::getVolume(PulseaudioTarget target) const {
|
||||||
|
if (target == PulseaudioTarget::Source) {
|
||||||
|
return source_volume_;
|
||||||
|
} else {
|
||||||
|
return volume_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioBackend::changeVolume(uint16_t volume, uint16_t min_volume, uint16_t max_volume) {
|
void AudioBackend::changeVolume(uint16_t volume, uint16_t min_volume, uint16_t max_volume) {
|
||||||
// Early return if context is not ready
|
// Early return if context is not ready
|
||||||
if ((context_ == nullptr) || pa_context_get_state(context_) != PA_CONTEXT_READY) {
|
if ((context_ == nullptr) || pa_context_get_state(context_) != PA_CONTEXT_READY) {
|
||||||
@@ -370,6 +378,14 @@ void AudioBackend::changeVolume(ChangeType change_type, double step, uint16_t ma
|
|||||||
pa_threaded_mainloop_unlock(mainloop_);
|
pa_threaded_mainloop_unlock(mainloop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AudioBackend::getMuted(PulseaudioTarget target) const {
|
||||||
|
if (target == PulseaudioTarget::Source) {
|
||||||
|
return source_muted_;
|
||||||
|
} else {
|
||||||
|
return muted_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioBackend::toggleSinkMute() {
|
void AudioBackend::toggleSinkMute() {
|
||||||
if (context_ == nullptr || pa_context_get_state(context_) != PA_CONTEXT_READY) return;
|
if (context_ == nullptr || pa_context_get_state(context_) != PA_CONTEXT_READY) return;
|
||||||
muted_ = !muted_;
|
muted_ = !muted_;
|
||||||
@@ -406,6 +422,14 @@ void AudioBackend::toggleSourceMute(bool mute) {
|
|||||||
pa_threaded_mainloop_unlock(mainloop_);
|
pa_threaded_mainloop_unlock(mainloop_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioBackend::unmute(PulseaudioTarget target) {
|
||||||
|
if (target == PulseaudioTarget::Source) {
|
||||||
|
toggleSourceMute(false);
|
||||||
|
} else {
|
||||||
|
toggleSinkMute(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioBackend::isBluetooth() {
|
bool AudioBackend::isBluetooth() {
|
||||||
return monitor_.find("a2dp_sink") != std::string::npos || // PulseAudio
|
return monitor_.find("a2dp_sink") != std::string::npos || // PulseAudio
|
||||||
monitor_.find("a2dp-sink") != std::string::npos || // PipeWire
|
monitor_.find("a2dp-sink") != std::string::npos || // PipeWire
|
||||||
|
|||||||
Reference in New Issue
Block a user