refactor(privacy): clean up the module
parent
b652b4296d
commit
fe15530f34
|
@ -13,7 +13,8 @@ class PipewireBackend {
|
||||||
pw_context* context_;
|
pw_context* context_;
|
||||||
pw_core* core_;
|
pw_core* core_;
|
||||||
|
|
||||||
spa_hook registry_listener;
|
pw_registry* registry_;
|
||||||
|
spa_hook registryListener_;
|
||||||
|
|
||||||
/* Hack to keep constructor inaccessible but still public.
|
/* Hack to keep constructor inaccessible but still public.
|
||||||
* This is required to be able to use std::make_shared.
|
* This is required to be able to use std::make_shared.
|
||||||
|
@ -21,20 +22,22 @@ class PipewireBackend {
|
||||||
* pointer because the destructor will manually free memory, and this could be
|
* pointer because the destructor will manually free memory, and this could be
|
||||||
* a problem with C++20's copy and move semantics.
|
* a problem with C++20's copy and move semantics.
|
||||||
*/
|
*/
|
||||||
struct private_constructor_tag {};
|
struct PrivateConstructorTag {};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::mutex mutex_;
|
|
||||||
|
|
||||||
pw_registry* registry;
|
|
||||||
|
|
||||||
sigc::signal<void> privacy_nodes_changed_signal_event;
|
sigc::signal<void> privacy_nodes_changed_signal_event;
|
||||||
|
|
||||||
std::unordered_map<uint32_t, PrivacyNodeInfo*> privacy_nodes;
|
std::unordered_map<uint32_t, PrivacyNodeInfo*> privacy_nodes;
|
||||||
|
std::mutex mutex_;
|
||||||
|
|
||||||
static std::shared_ptr<PipewireBackend> getInstance();
|
static std::shared_ptr<PipewireBackend> getInstance();
|
||||||
|
|
||||||
PipewireBackend(private_constructor_tag tag);
|
// Handlers for PipeWire events
|
||||||
|
void handleRegistryEventGlobal(uint32_t id, uint32_t permissions, const char* type,
|
||||||
|
uint32_t version, const struct spa_dict* props);
|
||||||
|
void handleRegistryEventGlobalRemove(uint32_t id);
|
||||||
|
|
||||||
|
PipewireBackend(PrivateConstructorTag tag);
|
||||||
~PipewireBackend();
|
~PipewireBackend();
|
||||||
};
|
};
|
||||||
} // namespace waybar::util::PipewireBackend
|
} // namespace waybar::util::PipewireBackend
|
||||||
|
|
|
@ -34,29 +34,12 @@ class PrivacyNodeInfo {
|
||||||
|
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
std::string get_name() {
|
std::string getName();
|
||||||
const std::vector<std::string *> names{&application_name, &node_name};
|
std::string getIconName();
|
||||||
std::string name = "Unknown Application";
|
|
||||||
for (auto &name_ : names) {
|
|
||||||
if (name_ != nullptr && name_->length() > 0) {
|
|
||||||
name = *name_;
|
|
||||||
name[0] = toupper(name[0]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string get_icon_name() {
|
// Handlers for PipeWire events
|
||||||
const std::vector<std::string *> names{&application_icon_name, &pipewire_access_portal_app_id,
|
void handleProxyEventDestroy();
|
||||||
&application_name, &node_name};
|
void handleNodeEventInfo(const struct pw_node_info *info);
|
||||||
const std::string name = "application-x-executable-symbolic";
|
|
||||||
for (auto &name_ : names) {
|
|
||||||
if (name_ != nullptr && name_->length() > 0 && DefaultGtkIconThemeWrapper::has_icon(*name_)) {
|
|
||||||
return *name_;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::util::PipewireBackend
|
} // namespace waybar::util::PipewireBackend
|
||||||
|
|
|
@ -348,7 +348,8 @@ if pipewire.found()
|
||||||
src_files += files(
|
src_files += files(
|
||||||
'src/modules/privacy/privacy.cpp',
|
'src/modules/privacy/privacy.cpp',
|
||||||
'src/modules/privacy/privacy_item.cpp',
|
'src/modules/privacy/privacy_item.cpp',
|
||||||
'src/util/pipewire_backend.cpp',
|
'src/util/pipewire/pipewire_backend.cpp',
|
||||||
|
'src/util/pipewire/privacy_node_info.cpp',
|
||||||
)
|
)
|
||||||
man_files += files('man/waybar-privacy.5.scd')
|
man_files += files('man/waybar-privacy.5.scd')
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
#include "modules/privacy/privacy.hpp"
|
#include "modules/privacy/privacy.hpp"
|
||||||
|
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <json/value.h>
|
#include <json/value.h>
|
||||||
#include <pipewire/pipewire.h>
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
|
|
|
@ -1,23 +1,14 @@
|
||||||
#include "modules/privacy/privacy_item.hpp"
|
#include "modules/privacy/privacy_item.hpp"
|
||||||
|
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <pipewire/pipewire.h>
|
|
||||||
#include <spdlog/spdlog.h>
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstring>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "glibmm/main.h"
|
#include "glibmm/main.h"
|
||||||
#include "glibmm/priorities.h"
|
|
||||||
#include "gtkmm/enums.h"
|
|
||||||
#include "gtkmm/label.h"
|
#include "gtkmm/label.h"
|
||||||
#include "gtkmm/revealer.h"
|
#include "gtkmm/revealer.h"
|
||||||
#include "gtkmm/tooltip.h"
|
#include "gtkmm/tooltip.h"
|
||||||
#include "sigc++/adaptors/bind.h"
|
#include "sigc++/adaptors/bind.h"
|
||||||
#include "util/gtk_icon.hpp"
|
|
||||||
#include "util/pipewire/privacy_node_info.hpp"
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
@ -108,12 +99,12 @@ void PrivacyItem::update_tooltip() {
|
||||||
// Set device icon
|
// Set device icon
|
||||||
Gtk::Image *node_icon = new Gtk::Image();
|
Gtk::Image *node_icon = new Gtk::Image();
|
||||||
node_icon->set_pixel_size(tooltipIconSize);
|
node_icon->set_pixel_size(tooltipIconSize);
|
||||||
node_icon->set_from_icon_name(node->get_icon_name(), Gtk::ICON_SIZE_INVALID);
|
node_icon->set_from_icon_name(node->getIconName(), Gtk::ICON_SIZE_INVALID);
|
||||||
box->add(*node_icon);
|
box->add(*node_icon);
|
||||||
|
|
||||||
// Set model
|
// Set model
|
||||||
Gtk::Label *node_name = new Gtk::Label(node->get_name());
|
auto *nodeName = new Gtk::Label(node->getName());
|
||||||
box->add(*node_name);
|
box->add(*nodeName);
|
||||||
|
|
||||||
tooltip_window.add(*box);
|
tooltip_window.add(*box);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include "util/pipewire/pipewire_backend.hpp"
|
||||||
|
|
||||||
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
|
namespace waybar::util::PipewireBackend {
|
||||||
|
|
||||||
|
static void getNodeInfo(void *data_, const struct pw_node_info *info) {
|
||||||
|
auto *pNodeInfo = static_cast<PrivacyNodeInfo *>(data_);
|
||||||
|
pNodeInfo->handleNodeEventInfo(info);
|
||||||
|
|
||||||
|
static_cast<PipewireBackend *>(pNodeInfo->data)->privacy_nodes_changed_signal_event.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_node_events NODE_EVENTS = {
|
||||||
|
.version = PW_VERSION_NODE_EVENTS,
|
||||||
|
.info = getNodeInfo,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void proxyDestroy(void *data) {
|
||||||
|
static_cast<PrivacyNodeInfo *>(data)->handleProxyEventDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_proxy_events PROXY_EVENTS = {
|
||||||
|
.version = PW_VERSION_PROXY_EVENTS,
|
||||||
|
.destroy = proxyDestroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void registryEventGlobal(void *_data, uint32_t id, uint32_t permissions, const char *type,
|
||||||
|
uint32_t version, const struct spa_dict *props) {
|
||||||
|
static_cast<PipewireBackend *>(_data)->handleRegistryEventGlobal(id, permissions, type, version,
|
||||||
|
props);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registryEventGlobalRemove(void *_data, uint32_t id) {
|
||||||
|
static_cast<PipewireBackend *>(_data)->handleRegistryEventGlobalRemove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pw_registry_events REGISTRY_EVENTS = {
|
||||||
|
.version = PW_VERSION_REGISTRY_EVENTS,
|
||||||
|
.global = registryEventGlobal,
|
||||||
|
.global_remove = registryEventGlobalRemove,
|
||||||
|
};
|
||||||
|
|
||||||
|
PipewireBackend::PipewireBackend(PrivateConstructorTag tag)
|
||||||
|
: mainloop_(nullptr), context_(nullptr), core_(nullptr) {
|
||||||
|
pw_init(nullptr, nullptr);
|
||||||
|
mainloop_ = pw_thread_loop_new("waybar", nullptr);
|
||||||
|
if (mainloop_ == nullptr) {
|
||||||
|
throw std::runtime_error("pw_thread_loop_new() failed.");
|
||||||
|
}
|
||||||
|
context_ = pw_context_new(pw_thread_loop_get_loop(mainloop_), nullptr, 0);
|
||||||
|
if (context_ == nullptr) {
|
||||||
|
throw std::runtime_error("pa_context_new() failed.");
|
||||||
|
}
|
||||||
|
core_ = pw_context_connect(context_, nullptr, 0);
|
||||||
|
if (core_ == nullptr) {
|
||||||
|
throw std::runtime_error("pw_context_connect() failed");
|
||||||
|
}
|
||||||
|
registry_ = pw_core_get_registry(core_, PW_VERSION_REGISTRY, 0);
|
||||||
|
|
||||||
|
spa_zero(registryListener_);
|
||||||
|
pw_registry_add_listener(registry_, ®istryListener_, ®ISTRY_EVENTS, this);
|
||||||
|
if (pw_thread_loop_start(mainloop_) < 0) {
|
||||||
|
throw std::runtime_error("pw_thread_loop_start() failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PipewireBackend::~PipewireBackend() {
|
||||||
|
if (registry_ != nullptr) {
|
||||||
|
pw_proxy_destroy((struct pw_proxy *)registry_);
|
||||||
|
}
|
||||||
|
|
||||||
|
spa_zero(registryListener_);
|
||||||
|
|
||||||
|
if (core_ != nullptr) {
|
||||||
|
pw_core_disconnect(core_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context_ != nullptr) {
|
||||||
|
pw_context_destroy(context_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainloop_ != nullptr) {
|
||||||
|
pw_thread_loop_stop(mainloop_);
|
||||||
|
pw_thread_loop_destroy(mainloop_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<PipewireBackend> PipewireBackend::getInstance() {
|
||||||
|
PrivateConstructorTag tag;
|
||||||
|
return std::make_shared<PipewireBackend>(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipewireBackend::handleRegistryEventGlobal(uint32_t id, uint32_t permissions, const char *type,
|
||||||
|
uint32_t version, const struct spa_dict *props) {
|
||||||
|
if (props == nullptr || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) return;
|
||||||
|
|
||||||
|
const char *lookupStr = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
||||||
|
if (lookupStr == nullptr) return;
|
||||||
|
std::string mediaClass = lookupStr;
|
||||||
|
enum PrivacyNodeType mediaType = PRIVACY_NODE_TYPE_NONE;
|
||||||
|
if (mediaClass == "Stream/Input/Video") {
|
||||||
|
mediaType = PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
||||||
|
} else if (mediaClass == "Stream/Input/Audio") {
|
||||||
|
mediaType = PRIVACY_NODE_TYPE_AUDIO_INPUT;
|
||||||
|
} else if (mediaClass == "Stream/Output/Audio") {
|
||||||
|
mediaType = PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *proxy = (pw_proxy *)pw_registry_bind(registry_, id, type, version, sizeof(PrivacyNodeInfo));
|
||||||
|
|
||||||
|
if (proxy == nullptr) return;
|
||||||
|
|
||||||
|
auto *pNodeInfo = (PrivacyNodeInfo *)pw_proxy_get_user_data(proxy);
|
||||||
|
pNodeInfo->id = id;
|
||||||
|
pNodeInfo->data = this;
|
||||||
|
pNodeInfo->type = mediaType;
|
||||||
|
pNodeInfo->media_class = mediaClass;
|
||||||
|
|
||||||
|
pw_proxy_add_listener(proxy, &pNodeInfo->proxy_listener, &PROXY_EVENTS, pNodeInfo);
|
||||||
|
|
||||||
|
pw_proxy_add_object_listener(proxy, &pNodeInfo->object_listener, &NODE_EVENTS, pNodeInfo);
|
||||||
|
|
||||||
|
privacy_nodes.insert_or_assign(id, pNodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipewireBackend::handleRegistryEventGlobalRemove(uint32_t id) {
|
||||||
|
mutex_.lock();
|
||||||
|
auto iter = privacy_nodes.find(id);
|
||||||
|
if (iter != privacy_nodes.end()) {
|
||||||
|
privacy_nodes.erase(id);
|
||||||
|
}
|
||||||
|
mutex_.unlock();
|
||||||
|
|
||||||
|
privacy_nodes_changed_signal_event.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::util::PipewireBackend
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
|
namespace waybar::util::PipewireBackend {
|
||||||
|
|
||||||
|
std::string PrivacyNodeInfo::getName() {
|
||||||
|
const std::vector<std::string *> names{&application_name, &node_name};
|
||||||
|
std::string name = "Unknown Application";
|
||||||
|
for (const auto &item : names) {
|
||||||
|
if (item != nullptr && !item->empty()) {
|
||||||
|
name = *item;
|
||||||
|
name[0] = toupper(name[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PrivacyNodeInfo::getIconName() {
|
||||||
|
const std::vector<std::string *> names{&application_icon_name, &pipewire_access_portal_app_id,
|
||||||
|
&application_name, &node_name};
|
||||||
|
std::string name = "application-x-executable-symbolic";
|
||||||
|
for (const auto &item : names) {
|
||||||
|
if (item != nullptr && !item->empty() && DefaultGtkIconThemeWrapper::has_icon(*item)) {
|
||||||
|
return *item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrivacyNodeInfo::handleProxyEventDestroy() {
|
||||||
|
spa_hook_remove(&proxy_listener);
|
||||||
|
spa_hook_remove(&object_listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrivacyNodeInfo::handleNodeEventInfo(const struct pw_node_info *info) {
|
||||||
|
state = info->state;
|
||||||
|
|
||||||
|
const struct spa_dict_item *item;
|
||||||
|
spa_dict_for_each(item, info->props) {
|
||||||
|
if (strcmp(item->key, PW_KEY_CLIENT_ID) == 0) {
|
||||||
|
client_id = strtoul(item->value, nullptr, 10);
|
||||||
|
} else if (strcmp(item->key, PW_KEY_MEDIA_NAME) == 0) {
|
||||||
|
media_name = item->value;
|
||||||
|
} else if (strcmp(item->key, PW_KEY_NODE_NAME) == 0) {
|
||||||
|
node_name = item->value;
|
||||||
|
} else if (strcmp(item->key, PW_KEY_APP_NAME) == 0) {
|
||||||
|
application_name = item->value;
|
||||||
|
} else if (strcmp(item->key, "pipewire.access.portal.app_id") == 0) {
|
||||||
|
pipewire_access_portal_app_id = item->value;
|
||||||
|
} else if (strcmp(item->key, PW_KEY_APP_ICON_NAME) == 0) {
|
||||||
|
application_icon_name = item->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::util::PipewireBackend
|
|
@ -1,155 +0,0 @@
|
||||||
#include "util/pipewire/pipewire_backend.hpp"
|
|
||||||
|
|
||||||
#include "util/pipewire/privacy_node_info.hpp"
|
|
||||||
|
|
||||||
namespace waybar::util::PipewireBackend {
|
|
||||||
|
|
||||||
static void get_node_info(void *data_, const struct pw_node_info *info) {
|
|
||||||
PrivacyNodeInfo *p_node_info = static_cast<PrivacyNodeInfo *>(data_);
|
|
||||||
PipewireBackend *backend = (PipewireBackend *)p_node_info->data;
|
|
||||||
|
|
||||||
p_node_info->state = info->state;
|
|
||||||
|
|
||||||
const struct spa_dict_item *item;
|
|
||||||
spa_dict_for_each(item, info->props) {
|
|
||||||
if (strcmp(item->key, PW_KEY_CLIENT_ID) == 0) {
|
|
||||||
p_node_info->client_id = strtoul(item->value, NULL, 10);
|
|
||||||
} else if (strcmp(item->key, PW_KEY_MEDIA_NAME) == 0) {
|
|
||||||
p_node_info->media_name = item->value;
|
|
||||||
} else if (strcmp(item->key, PW_KEY_NODE_NAME) == 0) {
|
|
||||||
p_node_info->node_name = item->value;
|
|
||||||
} else if (strcmp(item->key, PW_KEY_APP_NAME) == 0) {
|
|
||||||
p_node_info->application_name = item->value;
|
|
||||||
} else if (strcmp(item->key, "pipewire.access.portal.app_id") == 0) {
|
|
||||||
p_node_info->pipewire_access_portal_app_id = item->value;
|
|
||||||
} else if (strcmp(item->key, PW_KEY_APP_ICON_NAME) == 0) {
|
|
||||||
p_node_info->application_icon_name = item->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
backend->privacy_nodes_changed_signal_event.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_node_events node_events = {
|
|
||||||
.version = PW_VERSION_NODE_EVENTS,
|
|
||||||
.info = get_node_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void proxy_destroy(void *data) {
|
|
||||||
PrivacyNodeInfo *node = (PrivacyNodeInfo *)data;
|
|
||||||
|
|
||||||
spa_hook_remove(&node->proxy_listener);
|
|
||||||
spa_hook_remove(&node->object_listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_proxy_events proxy_events = {
|
|
||||||
.version = PW_VERSION_PROXY_EVENTS,
|
|
||||||
.destroy = proxy_destroy,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void registry_event_global(void *_data, uint32_t id, uint32_t permissions, const char *type,
|
|
||||||
uint32_t version, const struct spa_dict *props) {
|
|
||||||
if (!props || strcmp(type, PW_TYPE_INTERFACE_Node) != 0) return;
|
|
||||||
|
|
||||||
const char *lookup_str = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
|
||||||
if (!lookup_str) return;
|
|
||||||
std::string media_class = lookup_str;
|
|
||||||
enum PrivacyNodeType media_type = PRIVACY_NODE_TYPE_NONE;
|
|
||||||
if (media_class == "Stream/Input/Video") {
|
|
||||||
media_type = PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
|
||||||
} else if (media_class == "Stream/Input/Audio") {
|
|
||||||
media_type = PRIVACY_NODE_TYPE_AUDIO_INPUT;
|
|
||||||
} else if (media_class == "Stream/Output/Audio") {
|
|
||||||
media_type = PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PipewireBackend *backend = static_cast<PipewireBackend *>(_data);
|
|
||||||
struct pw_proxy *proxy =
|
|
||||||
(pw_proxy *)pw_registry_bind(backend->registry, id, type, version, sizeof(PrivacyNodeInfo));
|
|
||||||
|
|
||||||
if (!proxy) return;
|
|
||||||
|
|
||||||
PrivacyNodeInfo *p_node_info = (PrivacyNodeInfo *)pw_proxy_get_user_data(proxy);
|
|
||||||
p_node_info->id = id;
|
|
||||||
p_node_info->data = backend;
|
|
||||||
p_node_info->type = media_type;
|
|
||||||
p_node_info->media_class = media_class;
|
|
||||||
|
|
||||||
pw_proxy_add_listener(proxy, &p_node_info->proxy_listener, &proxy_events, p_node_info);
|
|
||||||
|
|
||||||
pw_proxy_add_object_listener(proxy, &p_node_info->object_listener, &node_events, p_node_info);
|
|
||||||
|
|
||||||
backend->privacy_nodes.insert_or_assign(id, p_node_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void registry_event_global_remove(void *_data, uint32_t id) {
|
|
||||||
auto backend = static_cast<PipewireBackend *>(_data);
|
|
||||||
|
|
||||||
backend->mutex_.lock();
|
|
||||||
auto iter = backend->privacy_nodes.find(id);
|
|
||||||
if (iter != backend->privacy_nodes.end()) {
|
|
||||||
backend->privacy_nodes.erase(id);
|
|
||||||
}
|
|
||||||
backend->mutex_.unlock();
|
|
||||||
|
|
||||||
backend->privacy_nodes_changed_signal_event.emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_registry_events registry_events = {
|
|
||||||
.version = PW_VERSION_REGISTRY_EVENTS,
|
|
||||||
.global = registry_event_global,
|
|
||||||
.global_remove = registry_event_global_remove,
|
|
||||||
};
|
|
||||||
|
|
||||||
PipewireBackend::PipewireBackend(private_constructor_tag tag)
|
|
||||||
: mainloop_(nullptr), context_(nullptr), core_(nullptr) {
|
|
||||||
pw_init(nullptr, nullptr);
|
|
||||||
mainloop_ = pw_thread_loop_new("waybar", nullptr);
|
|
||||||
if (mainloop_ == nullptr) {
|
|
||||||
throw std::runtime_error("pw_thread_loop_new() failed.");
|
|
||||||
}
|
|
||||||
context_ = pw_context_new(pw_thread_loop_get_loop(mainloop_), nullptr, 0);
|
|
||||||
if (context_ == nullptr) {
|
|
||||||
throw std::runtime_error("pa_context_new() failed.");
|
|
||||||
}
|
|
||||||
core_ = pw_context_connect(context_, nullptr, 0);
|
|
||||||
if (core_ == nullptr) {
|
|
||||||
throw std::runtime_error("pw_context_connect() failed");
|
|
||||||
}
|
|
||||||
registry = pw_core_get_registry(core_, PW_VERSION_REGISTRY, 0);
|
|
||||||
|
|
||||||
spa_zero(registry_listener);
|
|
||||||
pw_registry_add_listener(registry, ®istry_listener, ®istry_events, this);
|
|
||||||
if (pw_thread_loop_start(mainloop_) < 0) {
|
|
||||||
throw std::runtime_error("pw_thread_loop_start() failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PipewireBackend::~PipewireBackend() {
|
|
||||||
if (registry != nullptr) {
|
|
||||||
pw_proxy_destroy((struct pw_proxy *)registry);
|
|
||||||
}
|
|
||||||
|
|
||||||
spa_zero(registry_listener);
|
|
||||||
|
|
||||||
if (core_ != nullptr) {
|
|
||||||
pw_core_disconnect(core_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context_ != nullptr) {
|
|
||||||
pw_context_destroy(context_);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainloop_ != nullptr) {
|
|
||||||
pw_thread_loop_stop(mainloop_);
|
|
||||||
pw_thread_loop_destroy(mainloop_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<PipewireBackend> PipewireBackend::getInstance() {
|
|
||||||
private_constructor_tag tag;
|
|
||||||
return std::make_shared<PipewireBackend>(tag);
|
|
||||||
}
|
|
||||||
} // namespace waybar::util::PipewireBackend
|
|
Loading…
Reference in New Issue