diff --git a/include/factory.hpp b/include/factory.hpp index 7afc89f..90d0ac1 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -31,6 +31,7 @@ #include "modules/hyprland/language.hpp" #include "modules/hyprland/submap.hpp" #include "modules/hyprland/window.hpp" +#include "modules/hyprland/workspaces.hpp" #endif #if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM)) #include "modules/battery.hpp" diff --git a/include/modules/hyprland/backend.hpp b/include/modules/hyprland/backend.hpp index d876781..179c82f 100644 --- a/include/modules/hyprland/backend.hpp +++ b/include/modules/hyprland/backend.hpp @@ -5,6 +5,7 @@ #include #include #include +#include "util/json.hpp" namespace waybar::modules::hyprland { @@ -22,12 +23,14 @@ class IPC { void unregisterForIPC(EventHandler*); std::string getSocket1Reply(const std::string& rq); + Json::Value getSocket1JsonReply(const std::string& rq); private: void startIPC(); void parseIPC(const std::string&); std::mutex callbackMutex; + util::JsonParser parser_; std::list> callbacks; }; diff --git a/include/modules/hyprland/workspaces.hpp b/include/modules/hyprland/workspaces.hpp new file mode 100644 index 0000000..7903fef --- /dev/null +++ b/include/modules/hyprland/workspaces.hpp @@ -0,0 +1,44 @@ +#include +#include + +#include "AModule.hpp" +#include "bar.hpp" +#include "modules/hyprland/backend.hpp" + +namespace waybar::modules::hyprland { + +class Workspace { + public: + Workspace(int id); + int id() { return id_; }; + Gtk::Button& button() { return button_; }; + + static Workspace parse(const Json::Value&); + void update(); + + private: + int id_; + + Gtk::Button button_; + Gtk::Box content_; + Gtk::Label label_; +}; + +class Workspaces : public AModule, public EventHandler { + public: + Workspaces(const std::string&, const waybar::Bar&, const Json::Value&); + virtual ~Workspaces(); + void update() override; + void init(); + + private: + void onEvent(const std::string&) override; + + std::vector workspaces; + + std::mutex mutex_; + const Bar& bar_; + Gtk::Box box_; +}; + +} // namespace waybar::modules::hyprland diff --git a/meson.build b/meson.build index beee053..9ef4db0 100644 --- a/meson.build +++ b/meson.build @@ -240,6 +240,7 @@ if true src_files += 'src/modules/hyprland/window.cpp' src_files += 'src/modules/hyprland/language.cpp' src_files += 'src/modules/hyprland/submap.cpp' + src_files += 'src/modules/hyprland/workspaces.cpp' endif if libnl.found() and libnlgen.found() @@ -479,15 +480,6 @@ if scdoc.found() endforeach endif -catch2 = dependency( - 'catch2', - version: '>=2.0.0', - fallback: ['catch2', 'catch2_dep'], - required: get_option('tests'), -) -if catch2.found() - subdir('test') -endif clangtidy = find_program('clang-tidy', required: false) diff --git a/src/factory.cpp b/src/factory.cpp index bd2e7a2..1d7a00b 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -83,6 +83,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "hyprland/submap") { return new waybar::modules::hyprland::Submap(id, bar_, config_[name]); } + if (ref == "hyprland/workspaces") { + return new waybar::modules::hyprland::Workspaces(id, bar_, config_[name]); + } #endif if (ref == "idle_inhibitor") { return new waybar::modules::IdleInhibitor(id, bar_, config_[name]); diff --git a/src/modules/hyprland/backend.cpp b/src/modules/hyprland/backend.cpp index 997fe11..79bc637 100644 --- a/src/modules/hyprland/backend.cpp +++ b/src/modules/hyprland/backend.cpp @@ -198,4 +198,8 @@ std::string IPC::getSocket1Reply(const std::string& rq) { return response; } +Json::Value IPC::getSocket1JsonReply(const std::string& rq) { + return parser_.parse(getSocket1Reply("j/" + rq)); +} + } // namespace waybar::modules::hyprland diff --git a/src/modules/hyprland/workspaces.cpp b/src/modules/hyprland/workspaces.cpp new file mode 100644 index 0000000..4a19a59 --- /dev/null +++ b/src/modules/hyprland/workspaces.cpp @@ -0,0 +1,72 @@ +#include "modules/hyprland/workspaces.hpp" + +#include + +#include +#include + +namespace waybar::modules::hyprland { +Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config) + : AModule(config, "workspaces", id, false, false), + bar_(bar), + box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { + box_.set_name("workspaces"); + if (!id.empty()) { + box_.get_style_context()->add_class(id); + } + event_box_.add(box_); + modulesReady = true; + if (!gIPC.get()) { + gIPC = std::make_unique(); + } + + init(); + + gIPC->registerForIPC("createworkspace", this); + gIPC->registerForIPC("destroyworkspace", this); + gIPC->registerForIPC("urgent", this); +} + +auto Workspaces::update() -> void { + std::lock_guard lock(mutex_); + for (Workspace &workspace : workspaces) { + workspace.update(); + } + AModule::update(); +} + +void Workspaces::onEvent(const std::string &ev) { dp.emit(); } + +void Workspaces::init() { + const auto activeWorkspace = Workspace::parse(gIPC->getSocket1JsonReply("activeworkspace")); + const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); + for (const Json::Value &workspace_json : workspaces_json) { + workspaces.push_back(Workspace::parse(workspace_json)); + } + std::sort(workspaces.begin(), workspaces.end(), + [](Workspace &lhs, Workspace &rhs) { return lhs.id() < rhs.id(); }); + for (auto &workspace : workspaces) { + box_.pack_start(workspace.button(), false, false); + } + + dp.emit(); +} + +Workspaces::~Workspaces() { + gIPC->unregisterForIPC(this); + // wait for possible event handler to finish + std::lock_guard lg(mutex_); +} + +Workspace Workspace::Workspace::parse(const Json::Value &value) { + return Workspace{value["id"].asInt()}; +} + +Workspace::Workspace(int id) : id_(id) { + button_.set_relief(Gtk::RELIEF_NONE); + content_.set_center_widget(label_); + button_.add(content_); +}; + +void Workspace::update() { label_.set_text(std::to_string(id_)); } +} // namespace waybar::modules::hyprland