mirror of
https://github.com/rad4day/Waybar.git
synced 2025-07-14 15:12:31 +02:00
Initial implementation
This commit is contained in:
138
src/modules/privacy/privacy.cpp
Normal file
138
src/modules/privacy/privacy.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "modules/privacy/privacy.hpp"
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "gtkmm/image.h"
|
||||
|
||||
namespace waybar::modules::privacy {
|
||||
|
||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_INPUT;
|
||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_NONE;
|
||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
||||
|
||||
Privacy::Privacy(const std::string& id, const Json::Value& config, const std::string& pos)
|
||||
: AModule(config, "privacy", id),
|
||||
nodes_screenshare(),
|
||||
nodes_audio_in(),
|
||||
nodes_audio_out(),
|
||||
privacy_item_screenshare(config["screenshare"], PRIVACY_NODE_TYPE_VIDEO_INPUT, pos),
|
||||
privacy_item_audio_input(config["audio-in"], PRIVACY_NODE_TYPE_AUDIO_INPUT, pos),
|
||||
privacy_item_audio_output(config["audio-out"], PRIVACY_NODE_TYPE_AUDIO_OUTPUT, pos),
|
||||
visibility_conn(),
|
||||
box_(Gtk::ORIENTATION_HORIZONTAL, 0) {
|
||||
box_.set_name(name_);
|
||||
box_.add(privacy_item_screenshare);
|
||||
box_.add(privacy_item_audio_output);
|
||||
box_.add(privacy_item_audio_input);
|
||||
|
||||
event_box_.add(box_);
|
||||
|
||||
// Icon Spacing
|
||||
if (config_["icon-spacing"].isUInt()) {
|
||||
iconSpacing = config_["icon-spacing"].asUInt();
|
||||
}
|
||||
box_.set_spacing(iconSpacing);
|
||||
|
||||
// Icon Size
|
||||
if (config_["icon-size"].isUInt()) {
|
||||
iconSize = config_["icon-size"].asUInt();
|
||||
}
|
||||
privacy_item_screenshare.set_icon_size(iconSize);
|
||||
privacy_item_audio_output.set_icon_size(iconSize);
|
||||
privacy_item_audio_input.set_icon_size(iconSize);
|
||||
|
||||
// Transition Duration
|
||||
if (config_["transition-duration"].isUInt()) {
|
||||
transition_duration = config_["transition-duration"].asUInt();
|
||||
}
|
||||
privacy_item_screenshare.set_transition_duration(transition_duration);
|
||||
privacy_item_audio_output.set_transition_duration(transition_duration);
|
||||
privacy_item_audio_input.set_transition_duration(transition_duration);
|
||||
|
||||
if (!privacy_item_screenshare.is_enabled() && !privacy_item_audio_input.is_enabled() &&
|
||||
!privacy_item_audio_output.is_enabled()) {
|
||||
throw std::runtime_error("No privacy modules enabled");
|
||||
}
|
||||
backend = util::PipewireBackend::PipewireBackend::getInstance();
|
||||
backend->privacy_nodes_changed_signal_event.connect(
|
||||
sigc::mem_fun(*this, &Privacy::onPrivacyNodesChanged));
|
||||
}
|
||||
|
||||
void Privacy::onPrivacyNodesChanged() {
|
||||
nodes_audio_out.clear();
|
||||
nodes_audio_in.clear();
|
||||
nodes_screenshare.clear();
|
||||
|
||||
bool screenshare = false;
|
||||
bool audio_in = false;
|
||||
bool audio_out = false;
|
||||
for (auto& node : backend->privacy_nodes) {
|
||||
if (screenshare && audio_in && audio_out) break;
|
||||
switch (node.second->state) {
|
||||
case PW_NODE_STATE_RUNNING:
|
||||
switch (node.second->type) {
|
||||
case PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
||||
screenshare = true;
|
||||
nodes_screenshare.push_back(node.second);
|
||||
break;
|
||||
case PRIVACY_NODE_TYPE_AUDIO_INPUT:
|
||||
audio_in = true;
|
||||
nodes_audio_in.push_back(node.second);
|
||||
break;
|
||||
case PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
||||
audio_out = true;
|
||||
nodes_audio_out.push_back(node.second);
|
||||
break;
|
||||
case PRIVACY_NODE_TYPE_NONE:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dp.emit();
|
||||
}
|
||||
|
||||
auto Privacy::update() -> void {
|
||||
bool screenshare = !nodes_screenshare.empty();
|
||||
bool audio_in = !nodes_audio_in.empty();
|
||||
bool audio_out = !nodes_audio_out.empty();
|
||||
|
||||
privacy_item_screenshare.set_in_use(screenshare);
|
||||
privacy_item_audio_input.set_in_use(audio_in);
|
||||
privacy_item_audio_output.set_in_use(audio_out);
|
||||
|
||||
// Hide the whole widget if none are in use
|
||||
bool is_visible = screenshare || audio_in || audio_out;
|
||||
if (is_visible != event_box_.get_visible()) {
|
||||
// Disconnect any previous connection so that it doesn't get activated in
|
||||
// the future, hiding the module when it should be visible
|
||||
visibility_conn.disconnect();
|
||||
if (is_visible) {
|
||||
event_box_.set_visible(true);
|
||||
} else {
|
||||
visibility_conn = Glib::signal_timeout().connect(sigc::track_obj(
|
||||
[this] {
|
||||
event_box_.set_visible(false);
|
||||
return false;
|
||||
},
|
||||
*this),
|
||||
transition_duration);
|
||||
}
|
||||
}
|
||||
|
||||
// Call parent update
|
||||
AModule::update();
|
||||
}
|
||||
|
||||
} // namespace waybar::modules::privacy
|
140
src/modules/privacy/privacy_item.cpp
Normal file
140
src/modules/privacy/privacy_item.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include "modules/privacy/privacy_item.hpp"
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "glibmm/main.h"
|
||||
#include "glibmm/priorities.h"
|
||||
#include "gtkmm/enums.h"
|
||||
#include "gtkmm/label.h"
|
||||
#include "gtkmm/revealer.h"
|
||||
#include "gtkmm/tooltip.h"
|
||||
#include "sigc++/adaptors/bind.h"
|
||||
#include "util/gtk_icon.hpp"
|
||||
#include "util/pipewire/privacy_node_info.hpp"
|
||||
|
||||
namespace waybar::modules::privacy {
|
||||
|
||||
PrivacyItem::PrivacyItem(const Json::Value& config_,
|
||||
enum util::PipewireBackend::PrivacyNodeType privacy_type_,
|
||||
const std::string& pos)
|
||||
: Gtk::Revealer(),
|
||||
privacy_type(privacy_type_),
|
||||
mutex_(),
|
||||
signal_conn(),
|
||||
box_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||
icon_() {
|
||||
switch (privacy_type) {
|
||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_INPUT:
|
||||
get_style_context()->add_class("audio-in");
|
||||
iconName = "waybar-privacy-audio-input-symbolic";
|
||||
break;
|
||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
||||
get_style_context()->add_class("audio-out");
|
||||
iconName = "waybar-privacy-audio-output-symbolic";
|
||||
break;
|
||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
||||
get_style_context()->add_class("screenshare");
|
||||
iconName = "waybar-privacy-screen-share-symbolic";
|
||||
break;
|
||||
default:
|
||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_NONE:
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the reveal transition to not look weird when sliding in
|
||||
if (pos == "modules-left") {
|
||||
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_SLIDE_RIGHT);
|
||||
} else if (pos == "modules-center") {
|
||||
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_CROSSFADE);
|
||||
} else if (pos == "modules-right") {
|
||||
set_transition_type(Gtk::REVEALER_TRANSITION_TYPE_SLIDE_LEFT);
|
||||
}
|
||||
|
||||
box_.set_name("privacy-item");
|
||||
box_.add(icon_);
|
||||
add(box_);
|
||||
|
||||
// Icon Name
|
||||
if (config_["enabled"].isBool()) {
|
||||
enabled = config_["enabled"].asBool();
|
||||
}
|
||||
|
||||
// Icon Name
|
||||
if (config_["icon-name"].isString()) {
|
||||
iconName = config_["icon-name"].asString();
|
||||
}
|
||||
icon_.set_from_icon_name(iconName, Gtk::ICON_SIZE_INVALID);
|
||||
|
||||
// Don't show by default
|
||||
set_reveal_child(true);
|
||||
set_visible(false);
|
||||
}
|
||||
|
||||
bool PrivacyItem::is_enabled() { return enabled; }
|
||||
|
||||
void PrivacyItem::set_in_use(bool in_use) {
|
||||
mutex_.lock();
|
||||
if (this->in_use == in_use && init) {
|
||||
mutex_.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if (init) {
|
||||
// Disconnect any previous connection so that it doesn't get activated in
|
||||
// the future, hiding the module when it should be visible
|
||||
signal_conn.disconnect();
|
||||
|
||||
this->in_use = in_use;
|
||||
if (this->in_use) {
|
||||
set_visible(true);
|
||||
signal_conn = Glib::signal_timeout().connect(sigc::track_obj(
|
||||
[this] {
|
||||
set_reveal_child(true);
|
||||
return false;
|
||||
},
|
||||
*this),
|
||||
0);
|
||||
} else {
|
||||
set_reveal_child(false);
|
||||
signal_conn = Glib::signal_timeout().connect(sigc::track_obj(
|
||||
[this] {
|
||||
set_visible(false);
|
||||
return false;
|
||||
},
|
||||
*this),
|
||||
get_transition_duration());
|
||||
}
|
||||
} else {
|
||||
set_visible(false);
|
||||
set_reveal_child(false);
|
||||
}
|
||||
this->init = true;
|
||||
|
||||
// CSS status class
|
||||
const std::string status = this->in_use ? "in-use" : "";
|
||||
// Remove last status if it exists
|
||||
if (!lastStatus.empty() && get_style_context()->has_class(lastStatus)) {
|
||||
get_style_context()->remove_class(lastStatus);
|
||||
}
|
||||
// Add the new status class to the Box
|
||||
if (!status.empty() && !get_style_context()->has_class(status)) {
|
||||
get_style_context()->add_class(status);
|
||||
}
|
||||
lastStatus = status;
|
||||
|
||||
mutex_.unlock();
|
||||
}
|
||||
|
||||
void PrivacyItem::set_icon_size(uint size) { icon_.set_pixel_size(size); }
|
||||
|
||||
} // namespace waybar::modules::privacy
|
Reference in New Issue
Block a user