Merge pull request #4504 from ErikReider/geoclue-privacy
Add GeoClue2 location privacy item
This commit is contained in:
@@ -1,13 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "gtkmm/box.h"
|
#include "gtkmm/box.h"
|
||||||
#include "modules/privacy/privacy_item.hpp"
|
#include "modules/privacy/privacy_item.hpp"
|
||||||
|
#include "util/geoclue_backend.hpp"
|
||||||
#include "util/pipewire/pipewire_backend.hpp"
|
#include "util/pipewire/pipewire_backend.hpp"
|
||||||
#include "util/pipewire/privacy_node_info.hpp"
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
using waybar::util::PipewireBackend::PrivacyNodeInfo;
|
using waybar::util::PipewireBackend::PrivacyNodeType;
|
||||||
|
using waybar::util::PipewireBackend::PWPrivacyNodeInfo;
|
||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
@@ -16,15 +19,15 @@ class Privacy : public AModule {
|
|||||||
Privacy(const std::string&, const Json::Value&, Gtk::Orientation, const std::string& pos);
|
Privacy(const std::string&, const Json::Value&, Gtk::Orientation, const std::string& pos);
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
void onPrivacyNodesChanged();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<PrivacyNodeInfo*> nodes_screenshare; // Screen is being shared
|
std::list<PWPrivacyNodeInfo*> nodes_screenshare; // Screen is being shared
|
||||||
std::list<PrivacyNodeInfo*> nodes_audio_in; // Application is using the microphone
|
std::list<PWPrivacyNodeInfo*> nodes_audio_in; // Application is using the microphone
|
||||||
std::list<PrivacyNodeInfo*> nodes_audio_out; // Application is outputting audio
|
std::list<PWPrivacyNodeInfo*> nodes_audio_out; // Application is outputting audio
|
||||||
|
std::atomic<bool> location_in_use; // GeoClue is being used
|
||||||
|
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
sigc::connection visibility_conn;
|
sigc::connection visibility_conn;
|
||||||
|
sigc::connection geoclue_timeout_conn;
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
@@ -35,7 +38,12 @@ class Privacy : public AModule {
|
|||||||
std::set<std::pair<PrivacyNodeType, std::string>> ignore;
|
std::set<std::pair<PrivacyNodeType, std::string>> ignore;
|
||||||
bool ignore_monitor = true;
|
bool ignore_monitor = true;
|
||||||
|
|
||||||
std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
|
std::shared_ptr<util::PipewireBackend::PipewireBackend> pw_backend = nullptr;
|
||||||
|
std::shared_ptr<util::GeoClueBackend::GeoClueBackend> geoclue_backend = nullptr;
|
||||||
|
|
||||||
|
void onPWPrivacyNodesChanged();
|
||||||
|
bool locationTimeout(bool in_use);
|
||||||
|
void onGeoCluePrivacyNodesChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::privacy
|
} // namespace waybar::modules::privacy
|
||||||
|
|||||||
@@ -9,35 +9,36 @@
|
|||||||
#include "gtkmm/revealer.h"
|
#include "gtkmm/revealer.h"
|
||||||
#include "util/pipewire/privacy_node_info.hpp"
|
#include "util/pipewire/privacy_node_info.hpp"
|
||||||
|
|
||||||
using waybar::util::PipewireBackend::PrivacyNodeInfo;
|
|
||||||
using waybar::util::PipewireBackend::PrivacyNodeType;
|
using waybar::util::PipewireBackend::PrivacyNodeType;
|
||||||
|
using waybar::util::PipewireBackend::PWPrivacyNodeInfo;
|
||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
class PrivacyItem : public Gtk::Revealer {
|
class PrivacyItem : public Gtk::Revealer {
|
||||||
public:
|
protected:
|
||||||
PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
||||||
std::list<PrivacyNodeInfo*>* nodes, Gtk::Orientation orientation,
|
Gtk::Orientation orientation, const std::string& pos, const uint icon_size,
|
||||||
const std::string& pos, const uint icon_size, const uint transition_duration);
|
const uint transition_duration);
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void set_tooltip() = 0;
|
||||||
|
|
||||||
enum PrivacyNodeType privacy_type;
|
enum PrivacyNodeType privacy_type;
|
||||||
|
|
||||||
void set_in_use(bool in_use);
|
void set_in_use(bool in_use);
|
||||||
|
|
||||||
private:
|
uint tooltipIconSize = 24;
|
||||||
std::list<PrivacyNodeInfo*>* nodes;
|
|
||||||
|
|
||||||
sigc::connection signal_conn;
|
|
||||||
|
|
||||||
Gtk::Box tooltip_window;
|
Gtk::Box tooltip_window;
|
||||||
|
|
||||||
|
private:
|
||||||
|
sigc::connection signal_conn;
|
||||||
|
|
||||||
bool init = false;
|
bool init = false;
|
||||||
bool in_use = false;
|
bool in_use = false;
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
std::string iconName = "image-missing-symbolic";
|
std::string iconName = "image-missing-symbolic";
|
||||||
bool tooltip = true;
|
bool tooltip = true;
|
||||||
uint tooltipIconSize = 24;
|
|
||||||
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
Gtk::Image icon_;
|
Gtk::Image icon_;
|
||||||
@@ -45,4 +46,28 @@ class PrivacyItem : public Gtk::Revealer {
|
|||||||
void update_tooltip();
|
void update_tooltip();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GeoCluePrivacyItem : public PrivacyItem {
|
||||||
|
public:
|
||||||
|
GeoCluePrivacyItem(const Json::Value& config_, Gtk::Orientation orientation,
|
||||||
|
const std::string& pos, const uint icon_size, const uint transition_duration)
|
||||||
|
: PrivacyItem(config_, util::PipewireBackend::PRIVACY_NODE_TYPE_LOCATION, orientation, pos,
|
||||||
|
icon_size, transition_duration) {}
|
||||||
|
|
||||||
|
void set_tooltip() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PWPrivacyItem : public PrivacyItem {
|
||||||
|
public:
|
||||||
|
PWPrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
||||||
|
std::list<PWPrivacyNodeInfo*>* nodes_, Gtk::Orientation orientation,
|
||||||
|
const std::string& pos, const uint icon_size, const uint transition_duration)
|
||||||
|
: PrivacyItem(config_, privacy_type_, orientation, pos, icon_size, transition_duration),
|
||||||
|
nodes(nodes_) {}
|
||||||
|
|
||||||
|
void set_tooltip() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::list<PWPrivacyNodeInfo*>* nodes;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::privacy
|
} // namespace waybar::modules::privacy
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <giomm/dbusconnection.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "giomm/dbusproxy.h"
|
||||||
|
|
||||||
|
namespace waybar::util::GeoClueBackend {
|
||||||
|
|
||||||
|
class GeoClueBackend {
|
||||||
|
private:
|
||||||
|
guint watcherID_;
|
||||||
|
sigc::connection signal_conn;
|
||||||
|
Glib::RefPtr<Gio::DBus::Proxy> proxy;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
/* Hack to keep constructor inaccessible but still public.
|
||||||
|
* This is required to be able to use std::make_shared.
|
||||||
|
* It is important to keep this class only accessible via a reference-counted
|
||||||
|
* pointer because the destructor will manually free memory, and this could be
|
||||||
|
* a problem with C++20's copy and move semantics.
|
||||||
|
*/
|
||||||
|
struct PrivateConstructorTag {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
sigc::signal<void> in_use_changed_signal_event;
|
||||||
|
|
||||||
|
std::atomic<bool> location_in_use; // GeoClue is being used
|
||||||
|
|
||||||
|
static std::shared_ptr<GeoClueBackend> getInstance();
|
||||||
|
|
||||||
|
// DBus callbacks
|
||||||
|
void onAppear(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&,
|
||||||
|
const Glib::ustring&);
|
||||||
|
void onVanished(const Glib::RefPtr<Gio::DBus::Connection>&, const Glib::ustring&);
|
||||||
|
void propertyChanged(const Gio::DBus::Proxy::MapChangedProperties& changedProperties,
|
||||||
|
const std::vector<Glib::ustring>& invalidatedProperties);
|
||||||
|
|
||||||
|
GeoClueBackend(PrivateConstructorTag tag);
|
||||||
|
~GeoClueBackend();
|
||||||
|
};
|
||||||
|
} // namespace waybar::util::GeoClueBackend
|
||||||
@@ -29,7 +29,7 @@ class PipewireBackend {
|
|||||||
public:
|
public:
|
||||||
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, PWPrivacyNodeInfo*> privacy_nodes;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
|
|
||||||
static std::shared_ptr<PipewireBackend> getInstance();
|
static std::shared_ptr<PipewireBackend> getInstance();
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ enum PrivacyNodeType {
|
|||||||
PRIVACY_NODE_TYPE_NONE,
|
PRIVACY_NODE_TYPE_NONE,
|
||||||
PRIVACY_NODE_TYPE_VIDEO_INPUT,
|
PRIVACY_NODE_TYPE_VIDEO_INPUT,
|
||||||
PRIVACY_NODE_TYPE_AUDIO_INPUT,
|
PRIVACY_NODE_TYPE_AUDIO_INPUT,
|
||||||
PRIVACY_NODE_TYPE_AUDIO_OUTPUT
|
PRIVACY_NODE_TYPE_AUDIO_OUTPUT,
|
||||||
|
PRIVACY_NODE_TYPE_LOCATION
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrivacyNodeInfo {
|
class PWPrivacyNodeInfo {
|
||||||
public:
|
public:
|
||||||
PrivacyNodeType type = PRIVACY_NODE_TYPE_NONE;
|
PrivacyNodeType type = PRIVACY_NODE_TYPE_NONE;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ the screen or playing audio.
|
|||||||
|
|
||||||
*modules* ++
|
*modules* ++
|
||||||
typeof: array of objects ++
|
typeof: array of objects ++
|
||||||
default: [{"type": "screenshare"}, {"type": "audio-in"}] ++
|
default: [{"type": "screenshare"}, {"type": "audio-in"}, {"type": "location"}] ++
|
||||||
Which privacy modules to monitor. See *MODULES CONFIGURATION* for++
|
Which privacy modules to monitor. See *MODULES CONFIGURATION* for++
|
||||||
more information.
|
more information.
|
||||||
|
|
||||||
@@ -52,9 +52,13 @@ the screen or playing audio.
|
|||||||
|
|
||||||
*type*: ++
|
*type*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
values: "screenshare", "audio-in", "audio-out" ++
|
values: "screenshare", "audio-in", "audio-out", "location" ++
|
||||||
Specifies which module to use and configure.
|
Specifies which module to use and configure.
|
||||||
|
|
||||||
|
*icon-name*: ++
|
||||||
|
typeof: string ++
|
||||||
|
If set, changes the modules icon.
|
||||||
|
|
||||||
*tooltip*: ++
|
*tooltip*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: true ++
|
default: true ++
|
||||||
@@ -95,6 +99,10 @@ the screen or playing audio.
|
|||||||
"type": "audio-in",
|
"type": "audio-in",
|
||||||
"tooltip": true,
|
"tooltip": true,
|
||||||
"tooltip-icon-size": 24
|
"tooltip-icon-size": 24
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "location",
|
||||||
|
"icon-name": "location-services-active-symbolic"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ignore-monitor": true,
|
"ignore-monitor": true,
|
||||||
@@ -118,3 +126,4 @@ the screen or playing audio.
|
|||||||
- *#privacy-item.screenshare*
|
- *#privacy-item.screenshare*
|
||||||
- *#privacy-item.audio-in*
|
- *#privacy-item.audio-in*
|
||||||
- *#privacy-item.audio-out*
|
- *#privacy-item.audio-out*
|
||||||
|
- *#privacy-item.location*
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ if pipewire.found()
|
|||||||
'src/modules/privacy/privacy_item.cpp',
|
'src/modules/privacy/privacy_item.cpp',
|
||||||
'src/util/pipewire/pipewire_backend.cpp',
|
'src/util/pipewire/pipewire_backend.cpp',
|
||||||
'src/util/pipewire/privacy_node_info.cpp',
|
'src/util/pipewire/privacy_node_info.cpp',
|
||||||
|
'src/util/geoclue_backend.cpp',
|
||||||
)
|
)
|
||||||
man_files += files('man/waybar-privacy.5.scd')
|
man_files += files('man/waybar-privacy.5.scd')
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="16px" viewBox="0 0 16 16" width="16px"><path d="m 13.703125 1.046875 c -1.691406 0.5625 -4.636719 2.054687 -7.273437 3.4375 c -2.636719 1.382813 -4.898438 2.636719 -4.898438 2.636719 c -0.898438 0.503906 -0.542969 1.875 0.488281 1.875 h 5 v 5 c 0 1.03125 1.371094 1.386718 1.871094 0.488281 c 0 0 1.257813 -2.261719 2.640625 -4.898437 c 1.382812 -2.636719 2.875 -5.582032 3.4375 -7.273438 c 0.261719 -0.78125 -0.484375 -1.527344 -1.265625 -1.265625 z m 0 0" fill="#222222"/></svg>
|
||||||
|
After Width: | Height: | Size: 568 B |
@@ -4,5 +4,6 @@
|
|||||||
<file preprocess="xml-stripblanks">waybar-privacy-audio-input-symbolic.svg</file>
|
<file preprocess="xml-stripblanks">waybar-privacy-audio-input-symbolic.svg</file>
|
||||||
<file preprocess="xml-stripblanks">waybar-privacy-audio-output-symbolic.svg</file>
|
<file preprocess="xml-stripblanks">waybar-privacy-audio-output-symbolic.svg</file>
|
||||||
<file preprocess="xml-stripblanks">waybar-privacy-screen-share-symbolic.svg</file>
|
<file preprocess="xml-stripblanks">waybar-privacy-screen-share-symbolic.svg</file>
|
||||||
|
<file preprocess="xml-stripblanks">waybar-privacy-location-symbolic.svg</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
|||||||
@@ -325,3 +325,7 @@ label:focus {
|
|||||||
#privacy-item.audio-out {
|
#privacy-item.audio-out {
|
||||||
background-color: #0069d4;
|
background-color: #0069d4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#privacy-item.location {
|
||||||
|
background-color: #00afff;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,10 +10,11 @@
|
|||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_INPUT;
|
using waybar::util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_INPUT;
|
||||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
using waybar::util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT;
|
||||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_NONE;
|
using waybar::util::PipewireBackend::PRIVACY_NODE_TYPE_LOCATION;
|
||||||
using util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
using waybar::util::PipewireBackend::PRIVACY_NODE_TYPE_NONE;
|
||||||
|
using waybar::util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT;
|
||||||
|
|
||||||
Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientation orientation,
|
Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientation orientation,
|
||||||
const std::string& pos)
|
const std::string& pos)
|
||||||
@@ -21,7 +22,9 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientat
|
|||||||
nodes_screenshare(),
|
nodes_screenshare(),
|
||||||
nodes_audio_in(),
|
nodes_audio_in(),
|
||||||
nodes_audio_out(),
|
nodes_audio_out(),
|
||||||
|
location_in_use(false),
|
||||||
visibility_conn(),
|
visibility_conn(),
|
||||||
|
geoclue_timeout_conn(),
|
||||||
box_(orientation, 0) {
|
box_(orientation, 0) {
|
||||||
box_.set_name(name_);
|
box_.set_name(name_);
|
||||||
|
|
||||||
@@ -45,20 +48,21 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientat
|
|||||||
|
|
||||||
// Initialize each privacy module
|
// Initialize each privacy module
|
||||||
Json::Value modules = config_["modules"];
|
Json::Value modules = config_["modules"];
|
||||||
// Add Screenshare and Mic usage as default modules if none are specified
|
// Add Screenshare, Mic, and Location usage as default modules if none are specified
|
||||||
if (!modules.isArray() || modules.empty()) {
|
if (!modules.isArray() || modules.empty()) {
|
||||||
modules = Json::Value(Json::arrayValue);
|
modules = Json::Value(Json::arrayValue);
|
||||||
for (const auto& type : {"screenshare", "audio-in"}) {
|
for (const auto& type : {"screenshare", "audio-in", "location"}) {
|
||||||
Json::Value obj = Json::Value(Json::objectValue);
|
Json::Value obj = Json::Value(Json::objectValue);
|
||||||
obj["type"] = type;
|
obj["type"] = type;
|
||||||
modules.append(obj);
|
modules.append(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::tuple<decltype(&nodes_audio_in), PrivacyNodeType> > typeMap = {
|
std::map<std::string, std::tuple<std::list<PWPrivacyNodeInfo*>*, PrivacyNodeType>> typeMap = {
|
||||||
{"screenshare", {&nodes_screenshare, PRIVACY_NODE_TYPE_VIDEO_INPUT}},
|
{"screenshare", {&nodes_screenshare, PRIVACY_NODE_TYPE_VIDEO_INPUT}},
|
||||||
{"audio-in", {&nodes_audio_in, PRIVACY_NODE_TYPE_AUDIO_INPUT}},
|
{"audio-in", {&nodes_audio_in, PRIVACY_NODE_TYPE_AUDIO_INPUT}},
|
||||||
{"audio-out", {&nodes_audio_out, PRIVACY_NODE_TYPE_AUDIO_OUTPUT}},
|
{"audio-out", {&nodes_audio_out, PRIVACY_NODE_TYPE_AUDIO_OUTPUT}},
|
||||||
|
{"location", {nullptr, PRIVACY_NODE_TYPE_LOCATION}},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& module : modules) {
|
for (const auto& module : modules) {
|
||||||
@@ -68,8 +72,21 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientat
|
|||||||
auto iter = typeMap.find(type);
|
auto iter = typeMap.find(type);
|
||||||
if (iter != typeMap.end()) {
|
if (iter != typeMap.end()) {
|
||||||
auto& [nodePtr, nodeType] = iter->second;
|
auto& [nodePtr, nodeType] = iter->second;
|
||||||
auto* item = Gtk::make_managed<PrivacyItem>(module, nodeType, nodePtr, orientation, pos,
|
PrivacyItem* item = nullptr;
|
||||||
|
switch (nodeType) {
|
||||||
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
||||||
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_INPUT:
|
||||||
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
||||||
|
item = Gtk::make_managed<PWPrivacyItem>(module, nodeType, nodePtr, orientation, pos,
|
||||||
iconSize, transition_duration);
|
iconSize, transition_duration);
|
||||||
|
break;
|
||||||
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_LOCATION:
|
||||||
|
item = Gtk::make_managed<GeoCluePrivacyItem>(module, orientation, pos, iconSize,
|
||||||
|
transition_duration);
|
||||||
|
break;
|
||||||
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_NONE:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
box_.add(*item);
|
box_.add(*item);
|
||||||
modules_.push_back(item);
|
modules_.push_back(item);
|
||||||
}
|
}
|
||||||
@@ -93,20 +110,24 @@ Privacy::Privacy(const std::string& id, const Json::Value& config, Gtk::Orientat
|
|||||||
ignore_monitor = config_["ignore-monitor"].asBool();
|
ignore_monitor = config_["ignore-monitor"].asBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
backend = util::PipewireBackend::PipewireBackend::getInstance();
|
pw_backend = util::PipewireBackend::PipewireBackend::getInstance();
|
||||||
backend->privacy_nodes_changed_signal_event.connect(
|
pw_backend->privacy_nodes_changed_signal_event.connect(
|
||||||
sigc::mem_fun(*this, &Privacy::onPrivacyNodesChanged));
|
sigc::mem_fun(*this, &Privacy::onPWPrivacyNodesChanged));
|
||||||
|
|
||||||
|
geoclue_backend = util::GeoClueBackend::GeoClueBackend::getInstance();
|
||||||
|
geoclue_backend->in_use_changed_signal_event.connect(
|
||||||
|
sigc::mem_fun(*this, &Privacy::onGeoCluePrivacyNodesChanged));
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Privacy::onPrivacyNodesChanged() {
|
void Privacy::onPWPrivacyNodesChanged() {
|
||||||
mutex_.lock();
|
mutex_.lock();
|
||||||
nodes_audio_out.clear();
|
nodes_audio_out.clear();
|
||||||
nodes_audio_in.clear();
|
nodes_audio_in.clear();
|
||||||
nodes_screenshare.clear();
|
nodes_screenshare.clear();
|
||||||
|
|
||||||
for (auto& node : backend->privacy_nodes) {
|
for (auto& node : pw_backend->privacy_nodes) {
|
||||||
if (ignore_monitor && node.second->is_monitor) continue;
|
if (ignore_monitor && node.second->is_monitor) continue;
|
||||||
|
|
||||||
auto iter = ignore.find(std::pair(node.second->type, node.second->node_name));
|
auto iter = ignore.find(std::pair(node.second->type, node.second->node_name));
|
||||||
@@ -124,7 +145,7 @@ void Privacy::onPrivacyNodesChanged() {
|
|||||||
case PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
case PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
||||||
nodes_audio_out.push_back(node.second);
|
nodes_audio_out.push_back(node.second);
|
||||||
break;
|
break;
|
||||||
case PRIVACY_NODE_TYPE_NONE:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -137,36 +158,63 @@ void Privacy::onPrivacyNodesChanged() {
|
|||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Privacy::locationTimeout(bool in_use) {
|
||||||
|
location_in_use.store(geoclue_backend->location_in_use);
|
||||||
|
dp.emit();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void Privacy::onGeoCluePrivacyNodesChanged() {
|
||||||
|
geoclue_timeout_conn.disconnect();
|
||||||
|
|
||||||
|
const bool in_use = geoclue_backend->location_in_use;
|
||||||
|
if (in_use) {
|
||||||
|
locationTimeout(in_use);
|
||||||
|
} else {
|
||||||
|
// The GeoClue service is really fast, so wait before hiding, so that the
|
||||||
|
// widget is at least visible for 3 seconds.
|
||||||
|
geoclue_timeout_conn = Glib::signal_timeout().connect_seconds(
|
||||||
|
sigc::bind(sigc::mem_fun(*this, &Privacy::locationTimeout), in_use), 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto Privacy::update() -> void {
|
auto Privacy::update() -> void {
|
||||||
// set in modules or not
|
// set in modules or not
|
||||||
bool setScreenshare = false;
|
bool setScreenshare = false;
|
||||||
bool setAudioIn = false;
|
bool setAudioIn = false;
|
||||||
bool setAudioOut = false;
|
bool setAudioOut = false;
|
||||||
|
bool setLocation = false;
|
||||||
|
|
||||||
// used or not
|
// used or not
|
||||||
bool useScreenshare = false;
|
bool useScreenshare = false;
|
||||||
bool useAudioIn = false;
|
bool useAudioIn = false;
|
||||||
bool useAudioOut = false;
|
bool useAudioOut = false;
|
||||||
|
bool useLocation = false;
|
||||||
|
|
||||||
mutex_.lock();
|
mutex_.lock();
|
||||||
for (PrivacyItem* module : modules_) {
|
for (PrivacyItem* module : modules_) {
|
||||||
switch (module->privacy_type) {
|
switch (module->privacy_type) {
|
||||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
case PRIVACY_NODE_TYPE_VIDEO_INPUT:
|
||||||
setScreenshare = true;
|
setScreenshare = true;
|
||||||
useScreenshare = !nodes_screenshare.empty();
|
useScreenshare = !nodes_screenshare.empty();
|
||||||
module->set_in_use(useScreenshare);
|
module->set_in_use(useScreenshare);
|
||||||
break;
|
break;
|
||||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_INPUT:
|
case PRIVACY_NODE_TYPE_AUDIO_INPUT:
|
||||||
setAudioIn = true;
|
setAudioIn = true;
|
||||||
useAudioIn = !nodes_audio_in.empty();
|
useAudioIn = !nodes_audio_in.empty();
|
||||||
module->set_in_use(useAudioIn);
|
module->set_in_use(useAudioIn);
|
||||||
break;
|
break;
|
||||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
case PRIVACY_NODE_TYPE_AUDIO_OUTPUT:
|
||||||
setAudioOut = true;
|
setAudioOut = true;
|
||||||
useAudioOut = !nodes_audio_out.empty();
|
useAudioOut = !nodes_audio_out.empty();
|
||||||
module->set_in_use(useAudioOut);
|
module->set_in_use(useAudioOut);
|
||||||
break;
|
break;
|
||||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_NONE:
|
case PRIVACY_NODE_TYPE_LOCATION:
|
||||||
|
setLocation = true;
|
||||||
|
useLocation = location_in_use;
|
||||||
|
module->set_in_use(useLocation);
|
||||||
|
break;
|
||||||
|
case PRIVACY_NODE_TYPE_NONE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +222,7 @@ auto Privacy::update() -> void {
|
|||||||
|
|
||||||
// Hide the whole widget if none are in use
|
// Hide the whole widget if none are in use
|
||||||
bool isVisible = (setScreenshare && useScreenshare) || (setAudioIn && useAudioIn) ||
|
bool isVisible = (setScreenshare && useScreenshare) || (setAudioIn && useAudioIn) ||
|
||||||
(setAudioOut && useAudioOut);
|
(setAudioOut && useAudioOut) || (setLocation && useLocation);
|
||||||
|
|
||||||
if (isVisible != event_box_.get_visible()) {
|
if (isVisible != event_box_.get_visible()) {
|
||||||
// Disconnect any previous connection so that it doesn't get activated in
|
// Disconnect any previous connection so that it doesn't get activated in
|
||||||
@@ -187,12 +235,13 @@ auto Privacy::update() -> void {
|
|||||||
// have finished animating
|
// have finished animating
|
||||||
visibility_conn = Glib::signal_timeout().connect(
|
visibility_conn = Glib::signal_timeout().connect(
|
||||||
sigc::track_obj(
|
sigc::track_obj(
|
||||||
[this, setScreenshare, setAudioOut, setAudioIn]() {
|
[this, setScreenshare, setAudioOut, setAudioIn, setLocation]() {
|
||||||
mutex_.lock();
|
mutex_.lock();
|
||||||
bool visible = false;
|
bool visible = false;
|
||||||
visible |= setScreenshare && !nodes_screenshare.empty();
|
visible |= setScreenshare && !nodes_screenshare.empty();
|
||||||
visible |= setAudioIn && !nodes_audio_in.empty();
|
visible |= setAudioIn && !nodes_audio_in.empty();
|
||||||
visible |= setAudioOut && !nodes_audio_out.empty();
|
visible |= setAudioOut && !nodes_audio_out.empty();
|
||||||
|
visible |= setLocation && location_in_use;
|
||||||
mutex_.unlock();
|
mutex_.unlock();
|
||||||
event_box_.set_visible(visible);
|
event_box_.set_visible(visible);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -8,19 +8,16 @@
|
|||||||
#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 "util/pipewire/privacy_node_info.hpp"
|
|
||||||
|
|
||||||
namespace waybar::modules::privacy {
|
namespace waybar::modules::privacy {
|
||||||
|
|
||||||
PrivacyItem::PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
PrivacyItem::PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privacy_type_,
|
||||||
std::list<PrivacyNodeInfo*>* nodes_, Gtk::Orientation orientation,
|
Gtk::Orientation orientation, const std::string& pos, const uint icon_size,
|
||||||
const std::string& pos, const uint icon_size,
|
|
||||||
const uint transition_duration)
|
const uint transition_duration)
|
||||||
: Gtk::Revealer(),
|
: Gtk::Revealer(),
|
||||||
privacy_type(privacy_type_),
|
privacy_type(privacy_type_),
|
||||||
nodes(nodes_),
|
|
||||||
signal_conn(),
|
|
||||||
tooltip_window(Gtk::ORIENTATION_VERTICAL, 0),
|
tooltip_window(Gtk::ORIENTATION_VERTICAL, 0),
|
||||||
|
signal_conn(),
|
||||||
box_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
box_(Gtk::ORIENTATION_HORIZONTAL, 0),
|
||||||
icon_() {
|
icon_() {
|
||||||
switch (privacy_type) {
|
switch (privacy_type) {
|
||||||
@@ -36,7 +33,10 @@ PrivacyItem::PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privac
|
|||||||
box_.get_style_context()->add_class("screenshare");
|
box_.get_style_context()->add_class("screenshare");
|
||||||
iconName = "waybar-privacy-screen-share-symbolic";
|
iconName = "waybar-privacy-screen-share-symbolic";
|
||||||
break;
|
break;
|
||||||
default:
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_LOCATION:
|
||||||
|
box_.get_style_context()->add_class("location");
|
||||||
|
iconName = "waybar-privacy-location-symbolic";
|
||||||
|
break;
|
||||||
case util::PipewireBackend::PRIVACY_NODE_TYPE_NONE:
|
case util::PipewireBackend::PRIVACY_NODE_TYPE_NONE:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,6 @@ PrivacyItem::PrivacyItem(const Json::Value& config_, enum PrivacyNodeType privac
|
|||||||
set_has_tooltip(tooltip);
|
set_has_tooltip(tooltip);
|
||||||
if (tooltip) {
|
if (tooltip) {
|
||||||
// Sets the window to use when showing the tooltip
|
// Sets the window to use when showing the tooltip
|
||||||
update_tooltip();
|
|
||||||
this->signal_query_tooltip().connect(sigc::track_obj(
|
this->signal_query_tooltip().connect(sigc::track_obj(
|
||||||
[this](int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) {
|
[this](int x, int y, bool keyboard_tooltip, const Glib::RefPtr<Gtk::Tooltip>& tooltip) {
|
||||||
tooltip->set_custom(tooltip_window);
|
tooltip->set_custom(tooltip_window);
|
||||||
@@ -103,21 +102,8 @@ void PrivacyItem::update_tooltip() {
|
|||||||
// work differently in GTK4.
|
// work differently in GTK4.
|
||||||
delete child;
|
delete child;
|
||||||
}
|
}
|
||||||
for (auto* node : *nodes) {
|
|
||||||
auto* box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL, 4);
|
|
||||||
|
|
||||||
// Set device icon
|
set_tooltip();
|
||||||
auto* node_icon = Gtk::make_managed<Gtk::Image>();
|
|
||||||
node_icon->set_pixel_size(tooltipIconSize);
|
|
||||||
node_icon->set_from_icon_name(node->getIconName(), Gtk::ICON_SIZE_INVALID);
|
|
||||||
box->add(*node_icon);
|
|
||||||
|
|
||||||
// Set model
|
|
||||||
auto* nodeName = Gtk::make_managed<Gtk::Label>(node->getName());
|
|
||||||
box->add(*nodeName);
|
|
||||||
|
|
||||||
tooltip_window.add(*box);
|
|
||||||
}
|
|
||||||
|
|
||||||
tooltip_window.show_all();
|
tooltip_window.show_all();
|
||||||
}
|
}
|
||||||
@@ -161,4 +147,27 @@ void PrivacyItem::set_in_use(bool in_use) {
|
|||||||
this->init = true;
|
this->init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeoCluePrivacyItem::set_tooltip() {
|
||||||
|
auto* nodeName = Gtk::make_managed<Gtk::Label>("Location in use");
|
||||||
|
tooltip_window.add(*nodeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PWPrivacyItem::set_tooltip() {
|
||||||
|
for (auto* node : *nodes) {
|
||||||
|
auto* box = Gtk::make_managed<Gtk::Box>(Gtk::ORIENTATION_HORIZONTAL, 4);
|
||||||
|
|
||||||
|
// Set device icon
|
||||||
|
auto* node_icon = Gtk::make_managed<Gtk::Image>();
|
||||||
|
node_icon->set_pixel_size(tooltipIconSize);
|
||||||
|
node_icon->set_from_icon_name(node->getIconName(), Gtk::ICON_SIZE_INVALID);
|
||||||
|
box->add(*node_icon);
|
||||||
|
|
||||||
|
// Set model
|
||||||
|
auto* nodeName = Gtk::make_managed<Gtk::Label>(node->getName());
|
||||||
|
box->add(*nodeName);
|
||||||
|
|
||||||
|
tooltip_window.add(*box);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace waybar::modules::privacy
|
} // namespace waybar::modules::privacy
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
#include "util/geoclue_backend.hpp"
|
||||||
|
|
||||||
|
#include <giomm/dbuswatchname.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace waybar::util::GeoClueBackend {
|
||||||
|
|
||||||
|
GeoClueBackend::GeoClueBackend(PrivateConstructorTag tag)
|
||||||
|
: watcherID_(0), signal_conn(), connected(false), location_in_use(false) {
|
||||||
|
// Start watching DBUS
|
||||||
|
watcherID_ =
|
||||||
|
Gio::DBus::watch_name(Gio::DBus::BusType::BUS_TYPE_SYSTEM, "org.freedesktop.GeoClue2",
|
||||||
|
sigc::mem_fun(*this, &GeoClueBackend::onAppear),
|
||||||
|
sigc::mem_fun(*this, &GeoClueBackend::onVanished),
|
||||||
|
Gio::DBus::BusNameWatcherFlags::BUS_NAME_WATCHER_FLAGS_AUTO_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
GeoClueBackend::~GeoClueBackend() {
|
||||||
|
if (watcherID_ > 0) {
|
||||||
|
Gio::DBus::unwatch_name(watcherID_);
|
||||||
|
watcherID_ = 0;
|
||||||
|
}
|
||||||
|
signal_conn.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<GeoClueBackend> GeoClueBackend::getInstance() {
|
||||||
|
PrivateConstructorTag tag;
|
||||||
|
return std::make_shared<GeoClueBackend>(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoClueBackend::propertyChanged(
|
||||||
|
const Gio::DBus::Proxy::MapChangedProperties& changedProperties,
|
||||||
|
const std::vector<Glib::ustring>& invalidatedProperties) {
|
||||||
|
if (!connected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto in_use_variant = changedProperties.find("InUse");
|
||||||
|
in_use_variant != changedProperties.end()) {
|
||||||
|
bool in_use =
|
||||||
|
Glib::VariantBase::cast_dynamic<Glib::Variant<bool>>(in_use_variant->second).get();
|
||||||
|
location_in_use.store(in_use);
|
||||||
|
in_use_changed_signal_event.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoClueBackend::onAppear(const Glib::RefPtr<Gio::DBus::Connection>& conn,
|
||||||
|
const Glib::ustring& name, const Glib::ustring& name_owner) {
|
||||||
|
location_in_use.store(false);
|
||||||
|
signal_conn.disconnect();
|
||||||
|
connected = true;
|
||||||
|
|
||||||
|
proxy = Gio::DBus::Proxy::create_sync(conn, "org.freedesktop.GeoClue2",
|
||||||
|
"/org/freedesktop/GeoClue2/Manager",
|
||||||
|
"org.freedesktop.GeoClue2.Manager");
|
||||||
|
|
||||||
|
// Subscribe DBus events
|
||||||
|
signal_conn = proxy->signal_properties_changed().connect(
|
||||||
|
sigc::mem_fun(*this, &GeoClueBackend::propertyChanged));
|
||||||
|
|
||||||
|
// Get the initial value
|
||||||
|
auto callArgs = Glib::Variant<std::tuple<Glib::ustring, Glib::ustring>>::create(
|
||||||
|
std::make_tuple("org.freedesktop.GeoClue2.Manager", "InUse"));
|
||||||
|
Glib::VariantContainerBase base =
|
||||||
|
proxy->call_sync("org.freedesktop.DBus.Properties.Get", callArgs);
|
||||||
|
if (base.is_of_type(Glib::VariantType("(v)"))) {
|
||||||
|
Glib::Variant<std::tuple<bool>> variant_value;
|
||||||
|
base.get_child(variant_value, 0);
|
||||||
|
auto [value] = variant_value.get();
|
||||||
|
if (location_in_use != value) {
|
||||||
|
location_in_use.store(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
in_use_changed_signal_event.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeoClueBackend::onVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn,
|
||||||
|
const Glib::ustring& name) {
|
||||||
|
signal_conn.disconnect();
|
||||||
|
connected = false;
|
||||||
|
|
||||||
|
location_in_use.store(false);
|
||||||
|
in_use_changed_signal_event.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::util::GeoClueBackend
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
namespace waybar::util::PipewireBackend {
|
namespace waybar::util::PipewireBackend {
|
||||||
|
|
||||||
static void getNodeInfo(void* data_, const struct pw_node_info* info) {
|
static void getNodeInfo(void* data_, const struct pw_node_info* info) {
|
||||||
auto* pNodeInfo = static_cast<PrivacyNodeInfo*>(data_);
|
auto* pNodeInfo = static_cast<PWPrivacyNodeInfo*>(data_);
|
||||||
pNodeInfo->handleNodeEventInfo(info);
|
pNodeInfo->handleNodeEventInfo(info);
|
||||||
|
|
||||||
static_cast<PipewireBackend*>(pNodeInfo->data)->privacy_nodes_changed_signal_event.emit();
|
static_cast<PipewireBackend*>(pNodeInfo->data)->privacy_nodes_changed_signal_event.emit();
|
||||||
@@ -17,7 +17,7 @@ static const struct pw_node_events NODE_EVENTS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void proxyDestroy(void* data) {
|
static void proxyDestroy(void* data) {
|
||||||
static_cast<PrivacyNodeInfo*>(data)->handleProxyEventDestroy();
|
static_cast<PWPrivacyNodeInfo*>(data)->handleProxyEventDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_proxy_events PROXY_EVENTS = {
|
static const struct pw_proxy_events PROXY_EVENTS = {
|
||||||
@@ -127,12 +127,13 @@ void PipewireBackend::handleRegistryEventGlobal(uint32_t id, uint32_t permission
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* proxy = (pw_proxy*)pw_registry_bind(registry_, id, type, version, sizeof(PrivacyNodeInfo));
|
auto* proxy =
|
||||||
|
(pw_proxy*)pw_registry_bind(registry_, id, type, version, sizeof(PWPrivacyNodeInfo));
|
||||||
|
|
||||||
if (proxy == nullptr) return;
|
if (proxy == nullptr) return;
|
||||||
|
|
||||||
auto* pNodeInfo = (PrivacyNodeInfo*)pw_proxy_get_user_data(proxy);
|
auto* pNodeInfo = (PWPrivacyNodeInfo*)pw_proxy_get_user_data(proxy);
|
||||||
new (pNodeInfo) PrivacyNodeInfo{};
|
new (pNodeInfo) PWPrivacyNodeInfo{};
|
||||||
pNodeInfo->id = id;
|
pNodeInfo->id = id;
|
||||||
pNodeInfo->data = this;
|
pNodeInfo->data = this;
|
||||||
pNodeInfo->type = mediaType;
|
pNodeInfo->type = mediaType;
|
||||||
@@ -152,7 +153,7 @@ void PipewireBackend::handleRegistryEventGlobalRemove(uint32_t id) {
|
|||||||
mutex_.lock();
|
mutex_.lock();
|
||||||
auto iter = privacy_nodes.find(id);
|
auto iter = privacy_nodes.find(id);
|
||||||
if (iter != privacy_nodes.end()) {
|
if (iter != privacy_nodes.end()) {
|
||||||
privacy_nodes[id]->~PrivacyNodeInfo();
|
privacy_nodes[id]->~PWPrivacyNodeInfo();
|
||||||
privacy_nodes.erase(id);
|
privacy_nodes.erase(id);
|
||||||
}
|
}
|
||||||
mutex_.unlock();
|
mutex_.unlock();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace waybar::util::PipewireBackend {
|
namespace waybar::util::PipewireBackend {
|
||||||
|
|
||||||
std::string PrivacyNodeInfo::getName() {
|
std::string PWPrivacyNodeInfo::getName() {
|
||||||
const std::vector<std::string*> names{&application_name, &node_name};
|
const std::vector<std::string*> names{&application_name, &node_name};
|
||||||
std::string name = "Unknown Application";
|
std::string name = "Unknown Application";
|
||||||
for (const auto& item : names) {
|
for (const auto& item : names) {
|
||||||
@@ -15,7 +15,7 @@ std::string PrivacyNodeInfo::getName() {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string PrivacyNodeInfo::getIconName() {
|
std::string PWPrivacyNodeInfo::getIconName() {
|
||||||
const std::vector<std::string*> names{&application_icon_name, &pipewire_access_portal_app_id,
|
const std::vector<std::string*> names{&application_icon_name, &pipewire_access_portal_app_id,
|
||||||
&application_name, &node_name};
|
&application_name, &node_name};
|
||||||
std::string name = "application-x-executable-symbolic";
|
std::string name = "application-x-executable-symbolic";
|
||||||
@@ -27,12 +27,12 @@ std::string PrivacyNodeInfo::getIconName() {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrivacyNodeInfo::handleProxyEventDestroy() {
|
void PWPrivacyNodeInfo::handleProxyEventDestroy() {
|
||||||
spa_hook_remove(&proxy_listener);
|
spa_hook_remove(&proxy_listener);
|
||||||
spa_hook_remove(&object_listener);
|
spa_hook_remove(&object_listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrivacyNodeInfo::handleNodeEventInfo(const struct pw_node_info* info) {
|
void PWPrivacyNodeInfo::handleNodeEventInfo(const struct pw_node_info* info) {
|
||||||
state = info->state;
|
state = info->state;
|
||||||
|
|
||||||
const struct spa_dict_item* item;
|
const struct spa_dict_item* item;
|
||||||
|
|||||||
Reference in New Issue
Block a user