Merge pull request #4366 from winkelnp/wp-bluetooth

`format-bluetooth` and `device.form-factor` support for wireplumber module
This commit is contained in:
Alexis Rouillard
2026-07-03 23:59:05 +02:00
committed by GitHub
2 changed files with 77 additions and 18 deletions
+2
View File
@@ -33,6 +33,7 @@ class Wireplumber : public ALabel {
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self); static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
bool handleScroll(GdkEventScroll* e) override; bool handleScroll(GdkEventScroll* e) override;
std::vector<std::string> getWPIcon();
static std::list<waybar::modules::Wireplumber*> modules; static std::list<waybar::modules::Wireplumber*> modules;
@@ -54,6 +55,7 @@ class Wireplumber : public ALabel {
bool source_muted_; bool source_muted_;
double source_volume_; double source_volume_;
gchar* default_source_name_; gchar* default_source_name_;
std::string form_factor_;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+70 -13
View File
@@ -28,7 +28,8 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
source_node_id_(0), source_node_id_(0),
source_muted_(false), source_muted_(false),
source_volume_(0.0), source_volume_(0.0),
default_source_name_(nullptr) { default_source_name_(nullptr),
form_factor_("") {
waybar::modules::Wireplumber::modules.push_back(this); waybar::modules::Wireplumber::modules.push_back(this);
wp_init(WP_INIT_PIPEWIRE); wp_init(WP_INIT_PIPEWIRE);
@@ -111,6 +112,21 @@ void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber*
: description != nullptr ? description : description != nullptr ? description
: "Unknown node name"; : "Unknown node name";
spdlog::debug("[{}]: Updating '{}' node name to: {}", self->name_, self->type_, self->node_name_); spdlog::debug("[{}]: Updating '{}' node name to: {}", self->name_, self->type_, self->node_name_);
// find form-factor
const auto* devid = wp_properties_get(properties, "device.id");
spdlog::debug("[{}]: '{}' device.id is {}", self->name_, self->type_, devid);
auto* dev = static_cast<WpDevice*>(wp_object_manager_lookup(
self->om_, WP_TYPE_DEVICE, WP_CONSTRAINT_TYPE_G_PROPERTY, "bound-id", "=s", devid, nullptr));
if (const auto* ff =
wp_pipewire_object_get_property(WP_PIPEWIRE_OBJECT(dev), "device.form-factor")) {
self->form_factor_ = ff;
spdlog::debug("[{}]: Updating node form factor to: {}", self->name_, self->form_factor_);
} else {
self->form_factor_ = "";
}
} }
void waybar::modules::Wireplumber::updateSourceName(waybar::modules::Wireplumber* self, void waybar::modules::Wireplumber::updateSourceName(waybar::modules::Wireplumber* self,
@@ -373,6 +389,8 @@ void waybar::modules::Wireplumber::prepare(waybar::modules::Wireplumber* self) {
"=s", self->type_, nullptr); "=s", self->type_, nullptr);
wp_object_manager_add_interest(om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class", wp_object_manager_add_interest(om_, WP_TYPE_NODE, WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class",
"=s", "Audio/Source", nullptr); "=s", "Audio/Source", nullptr);
wp_object_manager_add_interest(om_, WP_TYPE_DEVICE, WP_CONSTRAINT_TYPE_PW_PROPERTY, "media.class",
"=s", "Audio/Device", nullptr);
} }
void waybar::modules::Wireplumber::onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res, void waybar::modules::Wireplumber::onDefaultNodesApiLoaded(WpObject* p, GAsyncResult* res,
@@ -430,13 +448,55 @@ void waybar::modules::Wireplumber::asyncLoadRequiredApiModules() {
this); this);
} }
static const std::array<std::string, 7> ports = {
"headphone", "speaker", "headset", "hands-free", "portable", "car", "hifi",
};
std::vector<std::string> waybar::modules::Wireplumber::getWPIcon() {
std::vector<std::string> res;
if (muted_) {
res.emplace_back(node_name_ + "-muted");
}
res.push_back(node_name_);
res.push_back(source_name_);
std::transform(form_factor_.begin(), form_factor_.end(), form_factor_.begin(), ::tolower);
for (auto const& port : ports) {
if (form_factor_.find(port) != std::string::npos) {
if (muted_) {
res.emplace_back(port + "-muted");
}
res.push_back(port);
break;
}
}
if (muted_) {
res.emplace_back("default-muted");
}
return res;
}
auto waybar::modules::Wireplumber::update() -> void { auto waybar::modules::Wireplumber::update() -> void {
auto format = format_; auto format = format_;
std::string tooltipFormat; std::string tooltipFormat;
std::string format_name = "format";
// Handle sink bluetooth state
const std::string name = default_node_name_ != nullptr ? default_node_name_ : "";
auto bt = name.find("bluez") != std::string::npos || name.find("a2dp-sink") != std::string::npos;
if (bt) {
format_name += "-bluetooth";
label_.get_style_context()->add_class("bluetooth");
} else {
label_.get_style_context()->remove_class("bluetooth");
}
// Handle sink mute state // Handle sink mute state
if (muted_) { if (muted_) {
format = config_["format-muted"].isString() ? config_["format-muted"].asString() : format; // Check muted bluetooth format exists, otherwise fall back to default muted format.
if (format_name != "format" && !config_[format_name + "-muted"].isString())
format_name = "format";
format_name += "-muted";
label_.get_style_context()->add_class("muted"); label_.get_style_context()->add_class("muted");
label_.get_style_context()->add_class("sink-muted"); label_.get_style_context()->add_class("sink-muted");
} else { } else {
@@ -462,13 +522,10 @@ auto waybar::modules::Wireplumber::update() -> void {
// Get the state and apply state-specific format if available // Get the state and apply state-specific format if available
auto state = getState(vol); auto state = getState(vol);
if (!state.empty()) { if (!state.empty() && config_[format_name + "-" + state].isString())
std::string format_name = muted_ ? "format-muted" : "format"; format = config_[format_name + "-" + state].asString();
std::string state_format_name = format_name + "-" + state; else if (config_[format_name].isString())
if (config_[state_format_name].isString()) { format = config_[format_name].asString();
format = config_[state_format_name].asString();
}
}
// Prepare source format string (similar to PulseAudio) // Prepare source format string (similar to PulseAudio)
std::string format_source = "{volume}%"; std::string format_source = "{volume}%";
@@ -486,9 +543,9 @@ auto waybar::modules::Wireplumber::update() -> void {
std::string formatted_source = std::string formatted_source =
fmt::format(fmt::runtime(format_source), fmt::arg("volume", source_vol)); fmt::format(fmt::runtime(format_source), fmt::arg("volume", source_vol));
std::string markup = std::string markup = fmt::format(
fmt::format(fmt::runtime(format), fmt::arg("node_name", node_name_), fmt::arg("volume", vol), fmt::runtime(format), fmt::arg("node_name", node_name_), fmt::arg("volume", vol),
fmt::arg("icon", getIcon(vol)), fmt::arg("format_source", formatted_source), fmt::arg("icon", getIcon(vol, getWPIcon())), fmt::arg("format_source", formatted_source),
fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_), fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_),
fmt::arg("volume_linear", volume_), fmt::arg("volume_cubic", vol_cube), fmt::arg("volume_linear", volume_), fmt::arg("volume_cubic", vol_cube),
fmt::arg("volume_db", vol_db), fmt::arg("source_volume_linear", source_volume_), fmt::arg("volume_db", vol_db), fmt::arg("source_volume_linear", source_volume_),
@@ -504,7 +561,7 @@ auto waybar::modules::Wireplumber::update() -> void {
if (!tooltipFormat.empty()) { if (!tooltipFormat.empty()) {
label_.set_tooltip_markup(fmt::format( label_.set_tooltip_markup(fmt::format(
fmt::runtime(tooltipFormat), fmt::arg("node_name", node_name_), fmt::arg("volume", vol), fmt::runtime(tooltipFormat), fmt::arg("node_name", node_name_), fmt::arg("volume", vol),
fmt::arg("icon", getIcon(vol)), fmt::arg("format_source", formatted_source), fmt::arg("icon", getIcon(vol, getWPIcon())), fmt::arg("format_source", formatted_source),
fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_), fmt::arg("source_volume", source_vol), fmt::arg("source_desc", source_name_),
fmt::arg("volume_linear", volume_), fmt::arg("volume_cubic", vol_cube), fmt::arg("volume_linear", volume_), fmt::arg("volume_cubic", vol_cube),
fmt::arg("volume_db", vol_db), fmt::arg("source_volume_linear", source_volume_), fmt::arg("volume_db", vol_db), fmt::arg("source_volume_linear", source_volume_),