Skip to content

Commit

Permalink
Merge pull request #2612 from ErikReider/privacy-module
Browse files Browse the repository at this point in the history
Add Privacy Module
  • Loading branch information
Alexays authored Nov 6, 2023
2 parents 7d7a047 + f21b1df commit e24adbc
Show file tree
Hide file tree
Showing 21 changed files with 858 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- Network
- Bluetooth
- Pulseaudio
- Privacy Info
- Wireplumber
- Disk
- Memory
Expand Down
5 changes: 4 additions & 1 deletion include/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
#ifdef HAVE_UPOWER
#include "modules/upower/upower.hpp"
#endif
#ifdef HAVE_PIPEWIRE
#include "modules/privacy/privacy.hpp"
#endif
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio.hpp"
#endif
Expand Down Expand Up @@ -101,7 +104,7 @@ namespace waybar {
class Factory {
public:
Factory(const Bar& bar, const Json::Value& config);
AModule* makeModule(const std::string& name) const;
AModule* makeModule(const std::string& name, const std::string& pos) const;

private:
const Bar& bar_;
Expand Down
41 changes: 41 additions & 0 deletions include/modules/privacy/privacy.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <iostream>
#include <map>
#include <string>

#include "ALabel.hpp"
#include "gtkmm/box.h"
#include "modules/privacy/privacy_item.hpp"
#include "util/pipewire/pipewire_backend.hpp"
#include "util/pipewire/privacy_node_info.hpp"

using waybar::util::PipewireBackend::PrivacyNodeInfo;

namespace waybar::modules::privacy {

class Privacy : public AModule {
public:
Privacy(const std::string &, const Json::Value &, const std::string &pos);
auto update() -> void override;

void onPrivacyNodesChanged();

private:
std::list<PrivacyNodeInfo *> nodes_screenshare; // Screen is being shared
std::list<PrivacyNodeInfo *> nodes_audio_in; // Application is using the microphone
std::list<PrivacyNodeInfo *> nodes_audio_out; // Application is outputting audio

std::mutex mutex_;
sigc::connection visibility_conn;

// Config
Gtk::Box box_;
uint iconSpacing = 4;
uint iconSize = 20;
uint transition_duration = 250;

std::shared_ptr<util::PipewireBackend::PipewireBackend> backend = nullptr;
};

} // namespace waybar::modules::privacy
51 changes: 51 additions & 0 deletions include/modules/privacy/privacy_item.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#pragma once

#include <json/value.h>

#include <iostream>
#include <map>
#include <mutex>
#include <string>

#include "gtkmm/box.h"
#include "gtkmm/image.h"
#include "gtkmm/revealer.h"
#include "util/pipewire/privacy_node_info.hpp"

using waybar::util::PipewireBackend::PrivacyNodeInfo;
using waybar::util::PipewireBackend::PrivacyNodeType;

namespace waybar::modules::privacy {

class PrivacyItem : public Gtk::Revealer {
public:
PrivacyItem(const Json::Value &config_, enum PrivacyNodeType privacy_type_,
std::list<PrivacyNodeInfo *> *nodes, const std::string &pos, const uint icon_size,
const uint transition_duration);

enum PrivacyNodeType privacy_type;

void set_in_use(bool in_use);

private:
std::list<PrivacyNodeInfo *> *nodes;

sigc::connection signal_conn;

Gtk::Box tooltip_window;

bool init = false;
bool in_use = false;

// Config
std::string iconName = "image-missing-symbolic";
bool tooltip = true;
uint tooltipIconSize = 24;

Gtk::Box box_;
Gtk::Image icon_;

void update_tooltip();
};

} // namespace waybar::modules::privacy
40 changes: 40 additions & 0 deletions include/util/pipewire/pipewire_backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once

#include <pipewire/pipewire.h>

#include "util/backend_common.hpp"
#include "util/pipewire/privacy_node_info.hpp"

namespace waybar::util::PipewireBackend {

class PipewireBackend {
private:
pw_thread_loop* mainloop_;
pw_context* context_;
pw_core* core_;

spa_hook registry_listener;

/* 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 private_constructor_tag {};

public:
std::mutex mutex_;

pw_registry* registry;

sigc::signal<void> privacy_nodes_changed_signal_event;

std::unordered_map<uint32_t, PrivacyNodeInfo*> privacy_nodes;

static std::shared_ptr<PipewireBackend> getInstance();

PipewireBackend(private_constructor_tag tag);
~PipewireBackend();
};
} // namespace waybar::util::PipewireBackend
62 changes: 62 additions & 0 deletions include/util/pipewire/privacy_node_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once

#include <pipewire/pipewire.h>

#include <string>

#include "util/gtk_icon.hpp"

namespace waybar::util::PipewireBackend {

enum PrivacyNodeType {
PRIVACY_NODE_TYPE_NONE,
PRIVACY_NODE_TYPE_VIDEO_INPUT,
PRIVACY_NODE_TYPE_AUDIO_INPUT,
PRIVACY_NODE_TYPE_AUDIO_OUTPUT
};

class PrivacyNodeInfo {
public:
PrivacyNodeType type = PRIVACY_NODE_TYPE_NONE;
uint32_t id;
uint32_t client_id;
enum pw_node_state state = PW_NODE_STATE_IDLE;
std::string media_class;
std::string media_name;
std::string node_name;
std::string application_name;

std::string pipewire_access_portal_app_id;
std::string application_icon_name;

struct spa_hook object_listener;
struct spa_hook proxy_listener;

void *data;

std::string get_name() {
const std::vector<std::string *> names{&application_name, &node_name};
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() {
const std::vector<std::string *> names{&application_icon_name, &pipewire_access_portal_app_id,
&application_name, &node_name};
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
85 changes: 85 additions & 0 deletions man/waybar-privacy.5.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
waybar-privacy(5)

# NAME

waybar - privacy module

# DESCRIPTION

The *privacy* module displays if any application is capturing audio, sharing ++
the screen or playing audio.

# CONFIGURATION

*icon-spacing*: ++
typeof: integer ++
default: 4 ++
The spacing between each privacy icon.

*icon-size*: ++
typeof: integer ++
default: 20 ++
The size of each privacy icon.

*transition-duration*: ++
typeof: integer ++
default: 250 ++
Option to disable tooltip on hover.

*modules* ++
typeof: array of objects ++
default: [{"type": "screenshare"}, {"type": "audio-in"}] ++
Which privacy modules to monitor. See *MODULES CONFIGURATION* for++
more information.

# MODULES CONFIGURATION

*type*: ++
typeof: string ++
values: "screenshare", "audio-in", "audio-out" ++
Specifies which module to use and configure.

*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.

*tooltip-icon-size*: ++
typeof: integer ++
default: 24 ++
The size of each icon in the tooltip.

# EXAMPLES

```
"privacy": {
"icon-spacing": 4,
"icon-size": 18,
"transition-duration": 250,
"modules": [
{
"type": "screenshare",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-out",
"tooltip": true,
"tooltip-icon-size": 24
},
{
"type": "audio-in",
"tooltip": true,
"tooltip-icon-size": 24
}
]
},
```

# STYLE

- *#privacy*
- *#privacy-item*
- *#privacy-item.screenshare*
- *#privacy-item.audio-in*
- *#privacy-item.audio-out*
16 changes: 15 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ libinput = dependency('libinput', required: get_option('libinput'))
libnl = dependency('libnl-3.0', required: get_option('libnl'))
libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
upower_glib = dependency('upower-glib', required: get_option('upower_glib'))
pipewire = dependency('libpipewire-0.3', required: get_option('pipewire'))
playerctl = dependency('playerctl', version : ['>=2.0.0'], required: get_option('mpris'))
libpulse = dependency('libpulse', required: get_option('pulseaudio'))
libudev = dependency('libudev', required: get_option('libudev'))
Expand Down Expand Up @@ -273,6 +274,14 @@ if (upower_glib.found() and giounix.found() and not get_option('logind').disable
src_files += 'src/modules/upower/upower_tooltip.cpp'
endif


if (pipewire.found())
add_project_arguments('-DHAVE_PIPEWIRE', language: 'cpp')
src_files += 'src/modules/privacy/privacy.cpp'
src_files += 'src/modules/privacy/privacy_item.cpp'
src_files += 'src/util/pipewire_backend.cpp'
endif

if (playerctl.found() and giounix.found() and not get_option('logind').disabled())
add_project_arguments('-DHAVE_MPRIS', language: 'cpp')
src_files += 'src/modules/mpris/mpris.cpp'
Expand Down Expand Up @@ -373,9 +382,12 @@ endif

subdir('protocol')

app_resources = []
subdir('resources/icons')

executable(
'waybar',
src_files,
[src_files, app_resources],
dependencies: [
thread_dep,
client_protos,
Expand All @@ -392,6 +404,7 @@ executable(
libnl,
libnlgen,
upower_glib,
pipewire,
playerctl,
libpulse,
libjack,
Expand Down Expand Up @@ -454,6 +467,7 @@ if scdoc.found()
'waybar-network.5.scd',
'waybar-pulseaudio.5.scd',
'waybar-pulseaudio-slider.5.scd',
'waybar-privacy.5.scd',
'waybar-river-mode.5.scd',
'waybar-river-tags.5.scd',
'waybar-river-window.5.scd',
Expand Down
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ option('libudev', type: 'feature', value: 'auto', description: 'Enable libudev s
option('libevdev', type: 'feature', value: 'auto', description: 'Enable libevdev support for evdev related features')
option('pulseaudio', type: 'feature', value: 'auto', description: 'Enable support for pulseaudio')
option('upower_glib', type: 'feature', value: 'auto', description: 'Enable support for upower')
option('pipewire', type: 'feature', value: 'auto', description: 'Enable support for pipewire')
option('mpris', type: 'feature', value: 'auto', description: 'Enable support for mpris')
option('systemd', type: 'feature', value: 'auto', description: 'Install systemd user service unit')
option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable support for tray')
Expand Down
6 changes: 6 additions & 0 deletions resources/icons/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
gnome = import('gnome')

app_resources += gnome.compile_resources('icon-resources',
'waybar_icons.gresource.xml',
c_name: 'waybar_icons'
)
4 changes: 4 additions & 0 deletions resources/icons/waybar-privacy-audio-input-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions resources/icons/waybar-privacy-audio-output-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions resources/icons/waybar-privacy-screen-share-symbolic.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit e24adbc

Please sign in to comment.