Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikReider committed Oct 26, 2023
1 parent 9ecdbcc commit 590ed6d
Show file tree
Hide file tree
Showing 19 changed files with 654 additions and 7 deletions.
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
44 changes: 44 additions & 0 deletions include/modules/privacy/privacy.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#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

PrivacyItem privacy_item_screenshare;
PrivacyItem privacy_item_audio_input;
PrivacyItem privacy_item_audio_output;

sigc::connection visibility_conn;

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

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

} // namespace waybar::modules::privacy
46 changes: 46 additions & 0 deletions include/modules/privacy/privacy_item.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#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"

namespace waybar::modules::privacy {

class PrivacyItem : public Gtk::Revealer {
public:
PrivacyItem(const Json::Value&, enum util::PipewireBackend::PrivacyNodeType privacy_type_,
const std::string& pos);

bool is_enabled();

void set_in_use(bool in_use);

void set_icon_size(uint size);

private:
enum util::PipewireBackend::PrivacyNodeType privacy_type;

std::mutex mutex_;
sigc::connection signal_conn;

bool init = false;
bool in_use = false;
std::string lastStatus;

// Config
bool enabled = true;
std::string iconName = "image-missing-symbolic";

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

} // 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::pipewire::PipewireBackend
36 changes: 36 additions & 0 deletions include/util/pipewire/privacy_node_info.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <pipewire/pipewire.h>

#include <string>

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;

struct spa_hook node_listener;

bool changed = false;

void* data;

PrivacyNodeInfo(uint32_t id_, void* data_) : id(id_), data(data_) {}

~PrivacyNodeInfo() { spa_hook_remove(&node_listener); }
};
} // namespace waybar::util::pipewire::PipewireBackend
17 changes: 14 additions & 3 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ project(
meson_version: '>= 0.50.0',
default_options : [
'cpp_std=c++20',
'buildtype=release',
'default_library=static'
],
)

Expand Down Expand Up @@ -98,6 +96,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 +272,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 +380,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 +402,7 @@ executable(
libnl,
libnlgen,
upower_glib,
pipewire,
playerctl,
libpulse,
libjack,
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.
8 changes: 8 additions & 0 deletions resources/icons/waybar_icons.gresource.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/fr/arouillard/waybar/icons/scalable/actions">
<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-screen-share-symbolic.svg</file>
</gresource>
</gresources>
2 changes: 1 addition & 1 deletion src/bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
getModules(factory, ref, group_module);
module = group_module;
} else {
module = factory.makeModule(ref);
module = factory.makeModule(ref, pos);
}

std::shared_ptr<AModule> module_sp(module);
Expand Down
6 changes: 6 additions & 0 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <iostream>

#include "gtkmm/icontheme.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "util/clara.hpp"
#include "util/format.hpp"
Expand Down Expand Up @@ -244,6 +245,11 @@ int waybar::Client::main(int argc, char *argv[]) {
}
gtk_app = Gtk::Application::create(argc, argv, "fr.arouillard.waybar",
Gio::APPLICATION_HANDLES_COMMAND_LINE);

// Initialize Waybars GTK resources with our custom icons
auto theme = Gtk::IconTheme::get_default();
theme->add_resource_path("/fr/arouillard/waybar/icons");

gdk_display = Gdk::Display::get_default();
if (!gdk_display) {
throw std::runtime_error("Can't find display");
Expand Down
8 changes: 7 additions & 1 deletion src/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@

waybar::Factory::Factory(const Bar& bar, const Json::Value& config) : bar_(bar), config_(config) {}

waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
waybar::AModule* waybar::Factory::makeModule(const std::string& name,
const std::string& pos) const {
try {
auto hash_pos = name.find('#');
auto ref = name.substr(0, hash_pos);
Expand All @@ -30,6 +31,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
return new waybar::modules::upower::UPower(id, config_[name]);
}
#endif
#ifdef HAVE_PIPEWIRE
if (ref == "privacy") {
return new waybar::modules::privacy::Privacy(id, config_[name], pos);
}
#endif
#ifdef HAVE_MPRIS
if (ref == "mpris") {
return new waybar::modules::mpris::Mpris(id, config_[name]);
Expand Down
Loading

0 comments on commit 590ed6d

Please sign in to comment.