From d4e498877ad278a2b286aebbf1e9e10c8016842b Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 00:03:57 +0530 Subject: [PATCH 01/14] Create native GTK-based Workbar module --- include/modules/hyprland/workbar.hpp | 18 ++++++++++++++++ include/modules/hyprland/workbar_widget.hpp | 16 ++++++++++++++ meson.build | 2 ++ src/factory.cpp | 4 ++++ src/modules/hyprland/workbar.cpp | 24 +++++++++++++++++++++ src/modules/hyprland/workbar_widget.cpp | 14 ++++++++++++ 6 files changed, 78 insertions(+) create mode 100644 include/modules/hyprland/workbar.hpp create mode 100644 include/modules/hyprland/workbar_widget.hpp create mode 100644 src/modules/hyprland/workbar.cpp create mode 100644 src/modules/hyprland/workbar_widget.cpp diff --git a/include/modules/hyprland/workbar.hpp b/include/modules/hyprland/workbar.hpp new file mode 100644 index 0000000000..53e875284c --- /dev/null +++ b/include/modules/hyprland/workbar.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "AModule.hpp" +#include "modules/hyprland/workbar_widget.hpp" + +namespace waybar::modules::hyprland { + +class Workbar : public AModule { + public: + Workbar(const std::string& id, const Json::Value& config); + + void update() override; + + private: + WorkbarWidget widget_; +}; + +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/include/modules/hyprland/workbar_widget.hpp b/include/modules/hyprland/workbar_widget.hpp new file mode 100644 index 0000000000..2f1b44f2d1 --- /dev/null +++ b/include/modules/hyprland/workbar_widget.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +namespace waybar::modules::hyprland { + +class WorkbarWidget : public Gtk::Box { + public: + WorkbarWidget(); + + private: + Gtk::Label label_; +}; + +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/meson.build b/meson.build index 0c494eb22c..df626f865a 100644 --- a/meson.build +++ b/meson.build @@ -323,6 +323,8 @@ if true 'src/modules/hyprland/windowcount.cpp', 'src/modules/hyprland/workspace.cpp', 'src/modules/hyprland/workspaces.cpp', + 'src/modules/hyprland/workbar.cpp', + 'src/modules/hyprland/workbar_widget.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', ) man_files += files( diff --git a/src/factory.cpp b/src/factory.cpp index 2fd3e3b816..758748a78d 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -36,6 +36,7 @@ #include "modules/hyprland/window.hpp" #include "modules/hyprland/windowcount.hpp" #include "modules/hyprland/workspaces.hpp" +#include "modules/hyprland/workbar.hpp" #endif #ifdef HAVE_NIRI #include "modules/niri/language.hpp" @@ -219,6 +220,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, if (ref == "hyprland/workspaces") { return new waybar::modules::hyprland::Workspaces(id, bar_, config_[name]); } + if (ref == "hyprland/workbar") { + return new waybar::modules::hyprland::Workbar(id, config_[name]); + } #endif #ifdef HAVE_NIRI if (ref == "niri/language") { diff --git a/src/modules/hyprland/workbar.cpp b/src/modules/hyprland/workbar.cpp new file mode 100644 index 0000000000..666c9b7595 --- /dev/null +++ b/src/modules/hyprland/workbar.cpp @@ -0,0 +1,24 @@ +#include "modules/hyprland/workbar.hpp" + +namespace waybar::modules::hyprland { + +Workbar::Workbar(const std::string& id, const Json::Value& config) + : AModule(config, "workbar", id) { + widget_.set_name("workbar"); + + widget_.get_style_context()->add_class(MODULE_CLASS); + + if (!id.empty()) { + widget_.get_style_context()->add_class(id); + } + + event_box_.add(widget_); + + dp.emit(); +} + +void Workbar::update() { + AModule::update(); +} + +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/workbar_widget.cpp b/src/modules/hyprland/workbar_widget.cpp new file mode 100644 index 0000000000..64a1b02430 --- /dev/null +++ b/src/modules/hyprland/workbar_widget.cpp @@ -0,0 +1,14 @@ +#include "modules/hyprland/workbar_widget.hpp" + +namespace waybar::modules::hyprland { + +WorkbarWidget::WorkbarWidget() + : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { + label_.set_text("Hello from WorkbarWidget"); + + pack_start(label_, Gtk::PACK_SHRINK); + + show_all(); +} + +} // namespace waybar::modules::hyprland \ No newline at end of file From 5a0c9dc0bef7eab6222cf793b4ef507012cfd5ac Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 01:20:55 +0530 Subject: [PATCH 02/14] Refactor WorkbarWidget to support dynamic workspace buttons --- include/modules/hyprland/workbar_widget.hpp | 18 +++++++--- include/modules/hyprland/workspace_button.hpp | 19 ++++++++++ meson.build | 1 + src/modules/hyprland/workbar_widget.cpp | 35 +++++++++++++++---- src/modules/hyprland/workspace_button.cpp | 19 ++++++++++ 5 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 include/modules/hyprland/workspace_button.hpp create mode 100644 src/modules/hyprland/workspace_button.cpp diff --git a/include/modules/hyprland/workbar_widget.hpp b/include/modules/hyprland/workbar_widget.hpp index 2f1b44f2d1..5c4bf8ed53 100644 --- a/include/modules/hyprland/workbar_widget.hpp +++ b/include/modules/hyprland/workbar_widget.hpp @@ -1,16 +1,24 @@ #pragma once #include -#include + +#include "modules/hyprland/workspace_button.hpp" + +#include +#include namespace waybar::modules::hyprland { class WorkbarWidget : public Gtk::Box { - public: - WorkbarWidget(); + public: + WorkbarWidget(); + + void setWorkspaces(const std::vector& workspaces); + + private: + void clearWorkspaces(); - private: - Gtk::Label label_; + std::vector> workspaces_; }; } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/include/modules/hyprland/workspace_button.hpp b/include/modules/hyprland/workspace_button.hpp new file mode 100644 index 0000000000..e2d0e0cffc --- /dev/null +++ b/include/modules/hyprland/workspace_button.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +namespace waybar::modules::hyprland { + +class WorkspaceButton : public Gtk::Button { + public: + explicit WorkspaceButton(int number); + + private: + Gtk::Box box_; + Gtk::Label number_; + Gtk::Box icons_; +}; + +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/meson.build b/meson.build index df626f865a..2af7d3f009 100644 --- a/meson.build +++ b/meson.build @@ -325,6 +325,7 @@ if true 'src/modules/hyprland/workspaces.cpp', 'src/modules/hyprland/workbar.cpp', 'src/modules/hyprland/workbar_widget.cpp', + 'src/modules/hyprland/workspace_button.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', ) man_files += files( diff --git a/src/modules/hyprland/workbar_widget.cpp b/src/modules/hyprland/workbar_widget.cpp index 64a1b02430..cf10612476 100644 --- a/src/modules/hyprland/workbar_widget.cpp +++ b/src/modules/hyprland/workbar_widget.cpp @@ -1,14 +1,37 @@ #include "modules/hyprland/workbar_widget.hpp" +#include + namespace waybar::modules::hyprland { -WorkbarWidget::WorkbarWidget() - : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { - label_.set_text("Hello from WorkbarWidget"); + WorkbarWidget::WorkbarWidget() + : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { + + setWorkspaces({1, 2, 3, 4}); + + show_all(); + } + + void WorkbarWidget::clearWorkspaces() { + for (auto& button : workspaces_) { + remove(*button); + } + + workspaces_.clear(); + } + + void WorkbarWidget::setWorkspaces(const std::vector& workspaces) { + clearWorkspaces(); + + for (int ws : workspaces) { + auto button = std::make_unique(ws); + + pack_start(*button, Gtk::PACK_SHRINK); - pack_start(label_, Gtk::PACK_SHRINK); + workspaces_.push_back(std::move(button)); + } - show_all(); -} + show_all(); + } } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/workspace_button.cpp b/src/modules/hyprland/workspace_button.cpp new file mode 100644 index 0000000000..a9e6cb3adb --- /dev/null +++ b/src/modules/hyprland/workspace_button.cpp @@ -0,0 +1,19 @@ +#include "modules/hyprland/workspace_button.hpp" + +namespace waybar::modules::hyprland { + +WorkspaceButton::WorkspaceButton(int number) + : box_(Gtk::ORIENTATION_HORIZONTAL), + icons_(Gtk::ORIENTATION_HORIZONTAL) { + + number_.set_text(std::to_string(number)); + + box_.pack_start(number_, Gtk::PACK_SHRINK); + box_.pack_start(icons_, Gtk::PACK_SHRINK); + + add(box_); + + show_all(); +} + +} // namespace waybar::modules::hyprland \ No newline at end of file From d73db3f8ef6a0cd881bb54c72f1123ecafbae48a Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 15:32:24 +0530 Subject: [PATCH 03/14] Refactor workbar into modular architecture --- include/modules/hyprland/workbar.hpp | 18 -------- include/modules/hyprland/workbar/model.hpp | 13 ++++++ include/modules/hyprland/workbar/module.hpp | 18 ++++++++ include/modules/hyprland/workbar/widget.hpp | 25 +++++++++++ .../{ => workbar}/workspace_button.hpp | 2 +- include/modules/hyprland/workbar_widget.hpp | 24 ----------- meson.build | 7 ++-- src/factory.cpp | 4 +- src/modules/hyprland/workbar/model.cpp | 1 + .../{workbar.cpp => workbar/module.cpp} | 10 ++--- src/modules/hyprland/workbar/widget.cpp | 42 +++++++++++++++++++ .../{ => workbar}/workspace_button.cpp | 4 +- src/modules/hyprland/workbar_widget.cpp | 37 ---------------- 13 files changed, 113 insertions(+), 92 deletions(-) delete mode 100644 include/modules/hyprland/workbar.hpp create mode 100644 include/modules/hyprland/workbar/model.hpp create mode 100644 include/modules/hyprland/workbar/module.hpp create mode 100644 include/modules/hyprland/workbar/widget.hpp rename include/modules/hyprland/{ => workbar}/workspace_button.hpp (86%) delete mode 100644 include/modules/hyprland/workbar_widget.hpp create mode 100644 src/modules/hyprland/workbar/model.cpp rename src/modules/hyprland/{workbar.cpp => workbar/module.cpp} (53%) create mode 100644 src/modules/hyprland/workbar/widget.cpp rename src/modules/hyprland/{ => workbar}/workspace_button.cpp (76%) delete mode 100644 src/modules/hyprland/workbar_widget.cpp diff --git a/include/modules/hyprland/workbar.hpp b/include/modules/hyprland/workbar.hpp deleted file mode 100644 index 53e875284c..0000000000 --- a/include/modules/hyprland/workbar.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "AModule.hpp" -#include "modules/hyprland/workbar_widget.hpp" - -namespace waybar::modules::hyprland { - -class Workbar : public AModule { - public: - Workbar(const std::string& id, const Json::Value& config); - - void update() override; - - private: - WorkbarWidget widget_; -}; - -} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp new file mode 100644 index 0000000000..6fb41dbea3 --- /dev/null +++ b/include/modules/hyprland/workbar/model.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace waybar::modules::hyprland::workbar { + +struct WorkspaceState { + int id; +}; + +using WorkspaceList = std::vector; + +} // namespace waybar::modules::hyprland::workbar diff --git a/include/modules/hyprland/workbar/module.hpp b/include/modules/hyprland/workbar/module.hpp new file mode 100644 index 0000000000..8f91971508 --- /dev/null +++ b/include/modules/hyprland/workbar/module.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "AModule.hpp" +#include "modules/hyprland/workbar/widget.hpp" + +namespace waybar::modules::hyprland::workbar { + +class Module : public AModule { + public: + Module(const std::string& id, const Json::Value& config); + + void update() override; + + private: + Widget widget_; +}; + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/widget.hpp b/include/modules/hyprland/workbar/widget.hpp new file mode 100644 index 0000000000..5cb7236c59 --- /dev/null +++ b/include/modules/hyprland/workbar/widget.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "modules/hyprland/workbar/model.hpp" +#include "modules/hyprland/workbar/workspace_button.hpp" + +#include +#include + +namespace waybar::modules::hyprland::workbar { + +class Widget : public Gtk::Box { + public: + Widget(); + + void setWorkspaces(const WorkspaceList& workspaces); + + private: + void clearWorkspaces(); + + std::vector> workspaces_; +}; + +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/include/modules/hyprland/workspace_button.hpp b/include/modules/hyprland/workbar/workspace_button.hpp similarity index 86% rename from include/modules/hyprland/workspace_button.hpp rename to include/modules/hyprland/workbar/workspace_button.hpp index e2d0e0cffc..945637f0ba 100644 --- a/include/modules/hyprland/workspace_button.hpp +++ b/include/modules/hyprland/workbar/workspace_button.hpp @@ -4,7 +4,7 @@ #include #include -namespace waybar::modules::hyprland { +namespace waybar::modules::hyprland::workbar { class WorkspaceButton : public Gtk::Button { public: diff --git a/include/modules/hyprland/workbar_widget.hpp b/include/modules/hyprland/workbar_widget.hpp deleted file mode 100644 index 5c4bf8ed53..0000000000 --- a/include/modules/hyprland/workbar_widget.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include "modules/hyprland/workspace_button.hpp" - -#include -#include - -namespace waybar::modules::hyprland { - -class WorkbarWidget : public Gtk::Box { - public: - WorkbarWidget(); - - void setWorkspaces(const std::vector& workspaces); - - private: - void clearWorkspaces(); - - std::vector> workspaces_; -}; - -} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/meson.build b/meson.build index 2af7d3f009..3cc4d925b6 100644 --- a/meson.build +++ b/meson.build @@ -323,9 +323,10 @@ if true 'src/modules/hyprland/windowcount.cpp', 'src/modules/hyprland/workspace.cpp', 'src/modules/hyprland/workspaces.cpp', - 'src/modules/hyprland/workbar.cpp', - 'src/modules/hyprland/workbar_widget.cpp', - 'src/modules/hyprland/workspace_button.cpp', + 'src/modules/hyprland/workbar/module.cpp', + 'src/modules/hyprland/workbar/widget.cpp', + 'src/modules/hyprland/workbar/workspace_button.cpp', + 'src/modules/hyprland/workbar/model.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', ) man_files += files( diff --git a/src/factory.cpp b/src/factory.cpp index 758748a78d..63260bb10d 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -36,7 +36,7 @@ #include "modules/hyprland/window.hpp" #include "modules/hyprland/windowcount.hpp" #include "modules/hyprland/workspaces.hpp" -#include "modules/hyprland/workbar.hpp" +#include "modules/hyprland/workbar/module.hpp" #endif #ifdef HAVE_NIRI #include "modules/niri/language.hpp" @@ -221,7 +221,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, return new waybar::modules::hyprland::Workspaces(id, bar_, config_[name]); } if (ref == "hyprland/workbar") { - return new waybar::modules::hyprland::Workbar(id, config_[name]); + return new waybar::modules::hyprland::workbar::Module(id, config_[name]); } #endif #ifdef HAVE_NIRI diff --git a/src/modules/hyprland/workbar/model.cpp b/src/modules/hyprland/workbar/model.cpp new file mode 100644 index 0000000000..f6e925fe98 --- /dev/null +++ b/src/modules/hyprland/workbar/model.cpp @@ -0,0 +1 @@ +#include "modules/hyprland/workbar/model.hpp" \ No newline at end of file diff --git a/src/modules/hyprland/workbar.cpp b/src/modules/hyprland/workbar/module.cpp similarity index 53% rename from src/modules/hyprland/workbar.cpp rename to src/modules/hyprland/workbar/module.cpp index 666c9b7595..60abf2ae16 100644 --- a/src/modules/hyprland/workbar.cpp +++ b/src/modules/hyprland/workbar/module.cpp @@ -1,8 +1,8 @@ -#include "modules/hyprland/workbar.hpp" +#include "modules/hyprland/workbar/module.hpp" -namespace waybar::modules::hyprland { +namespace waybar::modules::hyprland::workbar { -Workbar::Workbar(const std::string& id, const Json::Value& config) +Module::Module(const std::string& id, const Json::Value& config) : AModule(config, "workbar", id) { widget_.set_name("workbar"); @@ -17,8 +17,8 @@ Workbar::Workbar(const std::string& id, const Json::Value& config) dp.emit(); } -void Workbar::update() { +void Module::update() { AModule::update(); } -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp new file mode 100644 index 0000000000..3d9a0a4377 --- /dev/null +++ b/src/modules/hyprland/workbar/widget.cpp @@ -0,0 +1,42 @@ +#include "modules/hyprland/workbar/widget.hpp" + +#include + +namespace waybar::modules::hyprland::workbar { + + Widget::Widget() + : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { + + setWorkspaces({ + {1}, + {2}, + {3}, + {4}, + }); + + show_all(); + } + + void Widget::clearWorkspaces() { + for (auto& button : workspaces_) { + remove(*button); + } + + workspaces_.clear(); + } + + void Widget::setWorkspaces(const WorkspaceList& workspaces) { + clearWorkspaces(); + + for (const auto& ws : workspaces) { + auto button = std::make_unique(ws.id); + + pack_start(*button, Gtk::PACK_SHRINK); + + workspaces_.push_back(std::move(button)); + } + + show_all(); + } + +} // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp similarity index 76% rename from src/modules/hyprland/workspace_button.cpp rename to src/modules/hyprland/workbar/workspace_button.cpp index a9e6cb3adb..5cf4588a27 100644 --- a/src/modules/hyprland/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -1,6 +1,6 @@ -#include "modules/hyprland/workspace_button.hpp" +#include "modules/hyprland/workbar/workspace_button.hpp" -namespace waybar::modules::hyprland { +namespace waybar::modules::hyprland::workbar { WorkspaceButton::WorkspaceButton(int number) : box_(Gtk::ORIENTATION_HORIZONTAL), diff --git a/src/modules/hyprland/workbar_widget.cpp b/src/modules/hyprland/workbar_widget.cpp deleted file mode 100644 index cf10612476..0000000000 --- a/src/modules/hyprland/workbar_widget.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "modules/hyprland/workbar_widget.hpp" - -#include - -namespace waybar::modules::hyprland { - - WorkbarWidget::WorkbarWidget() - : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { - - setWorkspaces({1, 2, 3, 4}); - - show_all(); - } - - void WorkbarWidget::clearWorkspaces() { - for (auto& button : workspaces_) { - remove(*button); - } - - workspaces_.clear(); - } - - void WorkbarWidget::setWorkspaces(const std::vector& workspaces) { - clearWorkspaces(); - - for (int ws : workspaces) { - auto button = std::make_unique(ws); - - pack_start(*button, Gtk::PACK_SHRINK); - - workspaces_.push_back(std::move(button)); - } - - show_all(); - } - -} // namespace waybar::modules::hyprland \ No newline at end of file From e9cc0939d7f5638b666ce0604c97e176711eb73b Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 16:47:54 +0530 Subject: [PATCH 04/14] Add live Hyprland IPC backend for workbar --- include/modules/hyprland/workbar/backend.hpp | 26 ++++++++++++++ include/modules/hyprland/workbar/module.hpp | 2 ++ meson.build | 1 + src/modules/hyprland/workbar/backend.cpp | 36 ++++++++++++++++++++ src/modules/hyprland/workbar/module.cpp | 32 ++++++++++------- 5 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 include/modules/hyprland/workbar/backend.hpp create mode 100644 src/modules/hyprland/workbar/backend.cpp diff --git a/include/modules/hyprland/workbar/backend.hpp b/include/modules/hyprland/workbar/backend.hpp new file mode 100644 index 0000000000..c443158bcb --- /dev/null +++ b/include/modules/hyprland/workbar/backend.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "modules/hyprland/backend.hpp" +#include "modules/hyprland/workbar/model.hpp" + +namespace waybar::modules::hyprland::workbar { + +class Backend : public EventHandler { + public: + Backend(); + + WorkspaceList getWorkspaces(); + + void onEvent(const std::string& ev) override; + void setUpdateCallback(std::function callback); + + private: + IPC& ipc_; + + std::function update_callback_; +}; + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/module.hpp b/include/modules/hyprland/workbar/module.hpp index 8f91971508..b584a01e55 100644 --- a/include/modules/hyprland/workbar/module.hpp +++ b/include/modules/hyprland/workbar/module.hpp @@ -2,6 +2,7 @@ #include "AModule.hpp" #include "modules/hyprland/workbar/widget.hpp" +#include "modules/hyprland/workbar/backend.hpp" namespace waybar::modules::hyprland::workbar { @@ -12,6 +13,7 @@ class Module : public AModule { void update() override; private: + Backend backend_; Widget widget_; }; diff --git a/meson.build b/meson.build index 3cc4d925b6..d3184fe185 100644 --- a/meson.build +++ b/meson.build @@ -327,6 +327,7 @@ if true 'src/modules/hyprland/workbar/widget.cpp', 'src/modules/hyprland/workbar/workspace_button.cpp', 'src/modules/hyprland/workbar/model.cpp', + 'src/modules/hyprland/workbar/backend.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', ) man_files += files( diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp new file mode 100644 index 0000000000..c06e7079a1 --- /dev/null +++ b/src/modules/hyprland/workbar/backend.cpp @@ -0,0 +1,36 @@ +#include +#include "modules/hyprland/workbar/backend.hpp" + + +namespace waybar::modules::hyprland::workbar { + +Backend::Backend() + : ipc_(IPC::inst()) { + ipc_.registerForIPC("workspacev2", this); +} + +WorkspaceList Backend::getWorkspaces() { + auto json = ipc_.getSocket1JsonReply("workspaces"); + + WorkspaceList workspaces; + + for (const auto& ws : json) { + workspaces.push_back({ + ws["id"].asInt() + }); + } + + return workspaces; +} + +void Backend::setUpdateCallback(std::function callback) { + update_callback_ = std::move(callback); +} + +void Backend::onEvent(const std::string&) { + if (update_callback_) { + update_callback_(); + } +} + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/module.cpp b/src/modules/hyprland/workbar/module.cpp index 60abf2ae16..f4587a1648 100644 --- a/src/modules/hyprland/workbar/module.cpp +++ b/src/modules/hyprland/workbar/module.cpp @@ -2,23 +2,29 @@ namespace waybar::modules::hyprland::workbar { -Module::Module(const std::string& id, const Json::Value& config) - : AModule(config, "workbar", id) { - widget_.set_name("workbar"); + Module::Module(const std::string& id, const Json::Value& config) + : AModule(config, "workbar", id) { + widget_.set_name("workbar"); - widget_.get_style_context()->add_class(MODULE_CLASS); + widget_.get_style_context()->add_class(MODULE_CLASS); - if (!id.empty()) { - widget_.get_style_context()->add_class(id); - } + if (!id.empty()) { + widget_.get_style_context()->add_class(id); + } + + event_box_.add(widget_); - event_box_.add(widget_); + backend_.setUpdateCallback([this]() { + dp.emit(); + }); - dp.emit(); -} + dp.emit(); + } -void Module::update() { - AModule::update(); -} + void Module::update() { + widget_.setWorkspaces(backend_.getWorkspaces()); + + AModule::update(); + } } // namespace waybar::modules::hyprland::workbar \ No newline at end of file From c3cfe856b835e4d12c3854c4e5955ce1aa736205 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 17:44:01 +0530 Subject: [PATCH 05/14] Add active workspace state to workbar --- include/modules/hyprland/workbar/model.hpp | 10 +++++++++- .../hyprland/workbar/workspace_button.hpp | 3 ++- src/modules/hyprland/workbar/backend.cpp | 16 +++++++++++++++- src/modules/hyprland/workbar/widget.cpp | 9 +-------- .../hyprland/workbar/workspace_button.cpp | 16 +++++++++++++--- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp index 6fb41dbea3..b856b3ae56 100644 --- a/include/modules/hyprland/workbar/model.hpp +++ b/include/modules/hyprland/workbar/model.hpp @@ -1,11 +1,19 @@ #pragma once +#include #include namespace waybar::modules::hyprland::workbar { struct WorkspaceState { - int id; + int id; + + bool active = false; + bool visible = false; + + std::string monitor; + + int windows = 0; }; using WorkspaceList = std::vector; diff --git a/include/modules/hyprland/workbar/workspace_button.hpp b/include/modules/hyprland/workbar/workspace_button.hpp index 945637f0ba..5516322c82 100644 --- a/include/modules/hyprland/workbar/workspace_button.hpp +++ b/include/modules/hyprland/workbar/workspace_button.hpp @@ -3,12 +3,13 @@ #include #include #include +#include "modules/hyprland/workbar/model.hpp" namespace waybar::modules::hyprland::workbar { class WorkspaceButton : public Gtk::Button { public: - explicit WorkspaceButton(int number); + WorkspaceButton(const WorkspaceState& workspace); private: Gtk::Box box_; diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index c06e7079a1..39d3dbc9b9 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -1,4 +1,5 @@ #include +#include #include "modules/hyprland/workbar/backend.hpp" @@ -14,9 +15,22 @@ WorkspaceList Backend::getWorkspaces() { WorkspaceList workspaces; + auto monitors = ipc_.getSocket1JsonReply("monitors"); + + std::unordered_set active_workspaces; + + for (const auto& monitor : monitors) { + active_workspaces.insert( + monitor["activeWorkspace"]["id"].asInt() + ); +} + for (const auto& ws : json) { workspaces.push_back({ - ws["id"].asInt() + .id = ws["id"].asInt(), + .active = active_workspaces.contains(ws["id"].asInt()), + .monitor = ws["monitor"].asString(), + .windows = ws["windows"].asInt(), }); } diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp index 3d9a0a4377..9854421160 100644 --- a/src/modules/hyprland/workbar/widget.cpp +++ b/src/modules/hyprland/workbar/widget.cpp @@ -7,13 +7,6 @@ namespace waybar::modules::hyprland::workbar { Widget::Widget() : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { - setWorkspaces({ - {1}, - {2}, - {3}, - {4}, - }); - show_all(); } @@ -29,7 +22,7 @@ namespace waybar::modules::hyprland::workbar { clearWorkspaces(); for (const auto& ws : workspaces) { - auto button = std::make_unique(ws.id); + auto button = std::make_unique(ws); pack_start(*button, Gtk::PACK_SHRINK); diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index 5cf4588a27..084e1de7fa 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -2,11 +2,21 @@ namespace waybar::modules::hyprland::workbar { -WorkspaceButton::WorkspaceButton(int number) +WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) : box_(Gtk::ORIENTATION_HORIZONTAL), icons_(Gtk::ORIENTATION_HORIZONTAL) { - number_.set_text(std::to_string(number)); + number_.set_text(std::to_string(workspace.id)); + + auto context = get_style_context(); + + context->add_class("workspace"); + + if (workspace.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } box_.pack_start(number_, Gtk::PACK_SHRINK); box_.pack_start(icons_, Gtk::PACK_SHRINK); @@ -16,4 +26,4 @@ WorkspaceButton::WorkspaceButton(int number) show_all(); } -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file From c45266cefa1aed1ca7fd732c8a0d95f6d804c9a3 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 21:07:54 +0530 Subject: [PATCH 06/14] Add active and visible workspace state --- src/modules/hyprland/workbar/backend.cpp | 27 ++++++++++++------- .../hyprland/workbar/workspace_button.cpp | 6 +++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index 39d3dbc9b9..b8fd75256c 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -7,7 +7,8 @@ namespace waybar::modules::hyprland::workbar { Backend::Backend() : ipc_(IPC::inst()) { - ipc_.registerForIPC("workspacev2", this); + ipc_.registerForIPC("workspacev2", this); + ipc_.registerForIPC("focusedmonv2", this); } WorkspaceList Backend::getWorkspaces() { @@ -18,17 +19,23 @@ WorkspaceList Backend::getWorkspaces() { auto monitors = ipc_.getSocket1JsonReply("monitors"); std::unordered_set active_workspaces; + std::unordered_set visible_workspaces; for (const auto& monitor : monitors) { - active_workspaces.insert( - monitor["activeWorkspace"]["id"].asInt() - ); -} + int ws = monitor["activeWorkspace"]["id"].asInt(); + + visible_workspaces.insert(ws); + + if (monitor["focused"].asBool()) { + active_workspaces.insert(ws); + } + } for (const auto& ws : json) { workspaces.push_back({ .id = ws["id"].asInt(), .active = active_workspaces.contains(ws["id"].asInt()), + .visible = visible_workspaces.contains(ws["id"].asInt()), .monitor = ws["monitor"].asString(), .windows = ws["windows"].asInt(), }); @@ -41,10 +48,12 @@ void Backend::setUpdateCallback(std::function callback) { update_callback_ = std::move(callback); } -void Backend::onEvent(const std::string&) { - if (update_callback_) { - update_callback_(); - } +void Backend::onEvent(const std::string& ev) { + std::cout << "IPC Event: " << ev << std::endl; + + if (update_callback_) { + update_callback_(); + } } } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index 084e1de7fa..f48a9694d1 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -18,6 +18,12 @@ WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) context->remove_class("active"); } + if (workspace.visible) { + context->add_class("visible"); + } else { + context->remove_class("visible"); + } + box_.pack_start(number_, Gtk::PACK_SHRINK); box_.pack_start(icons_, Gtk::PACK_SHRINK); From d0a867702db674383304dee068494819a53a43be Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 29 Jun 2026 21:38:25 +0530 Subject: [PATCH 07/14] Populate workbar model with Hyprland clients --- include/modules/hyprland/workbar/model.hpp | 8 +++++- src/modules/hyprland/workbar/backend.cpp | 33 ++++++++++++++++------ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp index b856b3ae56..68afe9f596 100644 --- a/include/modules/hyprland/workbar/model.hpp +++ b/include/modules/hyprland/workbar/model.hpp @@ -5,6 +5,12 @@ namespace waybar::modules::hyprland::workbar { +struct WindowState { + std::string address; + std::string class_name; + std::string title; +}; + struct WorkspaceState { int id; @@ -13,7 +19,7 @@ struct WorkspaceState { std::string monitor; - int windows = 0; + std::vector windows; }; using WorkspaceList = std::vector; diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index b8fd75256c..ef3164bf37 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -13,6 +13,7 @@ Backend::Backend() WorkspaceList Backend::getWorkspaces() { auto json = ipc_.getSocket1JsonReply("workspaces"); + auto clients = ipc_.getSocket1JsonReply("clients"); WorkspaceList workspaces; @@ -32,13 +33,30 @@ WorkspaceList Backend::getWorkspaces() { } for (const auto& ws : json) { - workspaces.push_back({ - .id = ws["id"].asInt(), - .active = active_workspaces.contains(ws["id"].asInt()), - .visible = visible_workspaces.contains(ws["id"].asInt()), - .monitor = ws["monitor"].asString(), - .windows = ws["windows"].asInt(), - }); + WorkspaceState state; + + state.id = ws["id"].asInt(); + state.active = active_workspaces.contains(state.id); + state.visible = visible_workspaces.contains(state.id); + state.monitor = ws["monitor"].asString(); + + for (const auto& client : clients) { + if (client["workspace"]["id"].asInt() != state.id) { + continue; + } + + state.windows.push_back({ + client["address"].asString(), + client["class"].asString(), + client["title"].asString(), + }); + } + + std::cout << "Workspace " << state.id + << " has " << state.windows.size() + << " windows\n"; + + workspaces.push_back(std::move(state)); } return workspaces; @@ -49,7 +67,6 @@ void Backend::setUpdateCallback(std::function callback) { } void Backend::onEvent(const std::string& ev) { - std::cout << "IPC Event: " << ev << std::endl; if (update_callback_) { update_callback_(); From 723c58b76753ef788201f736c68fe0ac2bb414e4 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Tue, 30 Jun 2026 15:29:39 +0530 Subject: [PATCH 08/14] Display application icons in workbar --- include/modules/hyprland/workbar/widget.hpp | 3 +- .../modules/hyprland/workbar/window_icon.hpp | 20 +++++++ .../hyprland/workbar/workspace_button.hpp | 12 ++++ meson.build | 1 + src/modules/hyprland/workbar/backend.cpp | 8 +-- src/modules/hyprland/workbar/widget.cpp | 39 ++++++++++++- src/modules/hyprland/workbar/window_icon.cpp | 27 +++++++++ .../hyprland/workbar/workspace_button.cpp | 56 +++++++++++++------ 8 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 include/modules/hyprland/workbar/window_icon.hpp create mode 100644 src/modules/hyprland/workbar/window_icon.cpp diff --git a/include/modules/hyprland/workbar/widget.hpp b/include/modules/hyprland/workbar/widget.hpp index 5cb7236c59..83ade965cc 100644 --- a/include/modules/hyprland/workbar/widget.hpp +++ b/include/modules/hyprland/workbar/widget.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "modules/hyprland/workbar/model.hpp" #include "modules/hyprland/workbar/workspace_button.hpp" @@ -19,7 +20,7 @@ class Widget : public Gtk::Box { private: void clearWorkspaces(); - std::vector> workspaces_; + std::unordered_map> workspaces_; }; } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/include/modules/hyprland/workbar/window_icon.hpp b/include/modules/hyprland/workbar/window_icon.hpp new file mode 100644 index 0000000000..1694d1bc51 --- /dev/null +++ b/include/modules/hyprland/workbar/window_icon.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "modules/hyprland/workbar/model.hpp" + +namespace waybar::modules::hyprland::workbar { + +class WindowIcon : public Gtk::Button { + public: + explicit WindowIcon(const WindowState& window); + + void setWindow(const WindowState& window); + + private: + Gtk::Image image_; +}; + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/workspace_button.hpp b/include/modules/hyprland/workbar/workspace_button.hpp index 5516322c82..2aa00a5ace 100644 --- a/include/modules/hyprland/workbar/workspace_button.hpp +++ b/include/modules/hyprland/workbar/workspace_button.hpp @@ -1,9 +1,14 @@ #pragma once +#include +#include #include #include #include +#include + #include "modules/hyprland/workbar/model.hpp" +#include "modules/hyprland/workbar/window_icon.hpp" namespace waybar::modules::hyprland::workbar { @@ -11,10 +16,17 @@ class WorkspaceButton : public Gtk::Button { public: WorkspaceButton(const WorkspaceState& workspace); + void setWorkspace(const WorkspaceState& workspace); + private: + Gtk::Box box_; Gtk::Label number_; Gtk::Box icons_; + + std::vector> window_icons_; }; + + } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/meson.build b/meson.build index d3184fe185..ef84223a6e 100644 --- a/meson.build +++ b/meson.build @@ -328,6 +328,7 @@ if true 'src/modules/hyprland/workbar/workspace_button.cpp', 'src/modules/hyprland/workbar/model.cpp', 'src/modules/hyprland/workbar/backend.cpp', + 'src/modules/hyprland/workbar/window_icon.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', ) man_files += files( diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index ef3164bf37..84cf420dd9 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -9,6 +9,10 @@ Backend::Backend() : ipc_(IPC::inst()) { ipc_.registerForIPC("workspacev2", this); ipc_.registerForIPC("focusedmonv2", this); + + ipc_.registerForIPC("openwindow", this); + ipc_.registerForIPC("closewindow", this); + ipc_.registerForIPC("movewindowv2", this); } WorkspaceList Backend::getWorkspaces() { @@ -52,10 +56,6 @@ WorkspaceList Backend::getWorkspaces() { }); } - std::cout << "Workspace " << state.id - << " has " << state.windows.size() - << " windows\n"; - workspaces.push_back(std::move(state)); } diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp index 9854421160..8a15135771 100644 --- a/src/modules/hyprland/workbar/widget.cpp +++ b/src/modules/hyprland/workbar/widget.cpp @@ -1,6 +1,8 @@ #include "modules/hyprland/workbar/widget.hpp" #include +#include +#include namespace waybar::modules::hyprland::workbar { @@ -11,7 +13,7 @@ namespace waybar::modules::hyprland::workbar { } void Widget::clearWorkspaces() { - for (auto& button : workspaces_) { + for (auto& [id, button] : workspaces_) { remove(*button); } @@ -19,14 +21,45 @@ namespace waybar::modules::hyprland::workbar { } void Widget::setWorkspaces(const WorkspaceList& workspaces) { - clearWorkspaces(); + std::unordered_set seen; for (const auto& ws : workspaces) { + seen.insert(ws.id); + + auto it = workspaces_.find(ws.id); + + if (it != workspaces_.end()) { + it->second->setWorkspace(ws); + continue; + } + auto button = std::make_unique(ws); pack_start(*button, Gtk::PACK_SHRINK); - workspaces_.push_back(std::move(button)); + workspaces_.emplace(ws.id, std::move(button)); + } + + for (auto it = workspaces_.begin(); it != workspaces_.end();) { + if (!seen.contains(it->first)) { + remove(*it->second); + it = workspaces_.erase(it); + } else { + ++it; + } + } + + std::vector ids; + ids.reserve(workspaces_.size()); + + for (const auto& [id, _] : workspaces_) { + ids.push_back(id); + } + + std::sort(ids.begin(), ids.end()); + + for (int id : ids) { + reorder_child(*workspaces_.at(id), id - 1); } show_all(); diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp new file mode 100644 index 0000000000..9afd2aba2c --- /dev/null +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -0,0 +1,27 @@ +#include + +#include "modules/hyprland/workbar/window_icon.hpp" + +namespace waybar::modules::hyprland::workbar { + +WindowIcon::WindowIcon(const WindowState& window) { + setWindow(window); +} + +void WindowIcon::setWindow(const WindowState& window) { + auto theme = Gtk::IconTheme::get_default(); + + if (theme->has_icon(window.class_name)) { + image_.set_from_icon_name(window.class_name, + Gtk::ICON_SIZE_MENU); + } else { + image_.set_from_icon_name("application-x-executable", + Gtk::ICON_SIZE_MENU); + } + + add(image_); + + show_all(); +} + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index f48a9694d1..0cd9ec165b 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -6,30 +6,52 @@ WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) : box_(Gtk::ORIENTATION_HORIZONTAL), icons_(Gtk::ORIENTATION_HORIZONTAL) { - number_.set_text(std::to_string(workspace.id)); + box_.pack_start(number_, Gtk::PACK_SHRINK); + box_.pack_start(icons_, Gtk::PACK_SHRINK); - auto context = get_style_context(); + add(box_); - context->add_class("workspace"); + setWorkspace(workspace); - if (workspace.active) { - context->add_class("active"); - } else { - context->remove_class("active"); - } + show_all(); +} + +void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { + + window_icons_.clear(); + + for (auto* child : icons_.get_children()) { + icons_.remove(*child); + } + + number_.set_text(std::to_string(workspace.id)); - if (workspace.visible) { - context->add_class("visible"); - } else { - context->remove_class("visible"); - } + auto context = get_style_context(); - box_.pack_start(number_, Gtk::PACK_SHRINK); - box_.pack_start(icons_, Gtk::PACK_SHRINK); + context->add_class("workspace"); - add(box_); + if (workspace.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } - show_all(); + if (workspace.visible) { + context->add_class("visible"); + } else { + context->remove_class("visible"); + } + + for (const auto& window : workspace.windows) { + auto icon = std::make_unique(window); + + icons_.pack_start(*icon, Gtk::PACK_SHRINK); + + window_icons_.push_back(std::move(icon)); + } + + show_all(); } + } // namespace waybar::modules::hyprland::workbar \ No newline at end of file From f65f7011e1a491faab68b8f0bf9a74cb78c6290c Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Wed, 1 Jul 2026 16:43:42 +0530 Subject: [PATCH 09/14] Implement draggable workbar icons --- .../modules/hyprland/workbar/drag_state.hpp | 15 ++ include/modules/hyprland/workbar/model.hpp | 2 + include/modules/hyprland/workbar/widget.hpp | 11 +- .../modules/hyprland/workbar/window_icon.hpp | 11 ++ .../hyprland/workbar/workspace_button.hpp | 10 +- .../hyprland/workbar/workspace_number.hpp | 26 +++ meson.build | 2 + src/modules/hyprland/workbar/backend.cpp | 1 + src/modules/hyprland/workbar/drag_state.cpp | 7 + src/modules/hyprland/workbar/widget.cpp | 149 ++++++++++++++++++ src/modules/hyprland/workbar/window_icon.cpp | 133 +++++++++++++++- .../hyprland/workbar/workspace_button.cpp | 42 ++++- .../hyprland/workbar/workspace_number.cpp | 61 +++++++ 13 files changed, 457 insertions(+), 13 deletions(-) create mode 100644 include/modules/hyprland/workbar/drag_state.hpp create mode 100644 include/modules/hyprland/workbar/workspace_number.hpp create mode 100644 src/modules/hyprland/workbar/drag_state.cpp create mode 100644 src/modules/hyprland/workbar/workspace_number.cpp diff --git a/include/modules/hyprland/workbar/drag_state.hpp b/include/modules/hyprland/workbar/drag_state.hpp new file mode 100644 index 0000000000..a59aee00c7 --- /dev/null +++ b/include/modules/hyprland/workbar/drag_state.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace waybar::modules::hyprland::workbar { + +struct DragState { + bool dragging = false; + std::string window_address; + int source_workspace = -1; +}; + +extern DragState drag_state; + +} \ No newline at end of file diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp index 68afe9f596..28ad4c08ad 100644 --- a/include/modules/hyprland/workbar/model.hpp +++ b/include/modules/hyprland/workbar/model.hpp @@ -9,6 +9,8 @@ struct WindowState { std::string address; std::string class_name; std::string title; + + int workspace_id; }; struct WorkspaceState { diff --git a/include/modules/hyprland/workbar/widget.hpp b/include/modules/hyprland/workbar/widget.hpp index 83ade965cc..6c045eb041 100644 --- a/include/modules/hyprland/workbar/widget.hpp +++ b/include/modules/hyprland/workbar/widget.hpp @@ -14,13 +14,20 @@ namespace waybar::modules::hyprland::workbar { class Widget : public Gtk::Box { public: Widget(); - + static Widget* instance(); + WorkspaceButton* workspaceAt(int x, int y); void setWorkspaces(const WorkspaceList& workspaces); + void beginDrag(const WindowState& window); + void updateDrag(double x, double y); + void endDrag(); private: void clearWorkspaces(); - + static Widget* instance_; std::unordered_map> workspaces_; + bool dragging_ = false; + WindowState dragged_window_; + WorkspaceButton* hovered_workspace_ = nullptr; }; } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/include/modules/hyprland/workbar/window_icon.hpp b/include/modules/hyprland/workbar/window_icon.hpp index 1694d1bc51..39a2648847 100644 --- a/include/modules/hyprland/workbar/window_icon.hpp +++ b/include/modules/hyprland/workbar/window_icon.hpp @@ -12,9 +12,20 @@ class WindowIcon : public Gtk::Button { explicit WindowIcon(const WindowState& window); void setWindow(const WindowState& window); + + protected: + bool on_button_press_event(GdkEventButton* event) override; + bool on_motion_notify_event(GdkEventMotion* event) override; + bool on_button_release_event(GdkEventButton* event) override; private: Gtk::Image image_; + WindowState window_; + + bool left_pressed_ = false; + bool dragging_ = false; + double press_x_ = 0; + double press_y_ = 0; }; } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/workspace_button.hpp b/include/modules/hyprland/workbar/workspace_button.hpp index 2aa00a5ace..9cfcdd14e6 100644 --- a/include/modules/hyprland/workbar/workspace_button.hpp +++ b/include/modules/hyprland/workbar/workspace_button.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,22 +10,25 @@ #include "modules/hyprland/workbar/model.hpp" #include "modules/hyprland/workbar/window_icon.hpp" +#include "modules/hyprland/workbar/workspace_number.hpp" namespace waybar::modules::hyprland::workbar { -class WorkspaceButton : public Gtk::Button { +class WorkspaceButton : public Gtk::Box { public: WorkspaceButton(const WorkspaceState& workspace); + int id() const; void setWorkspace(const WorkspaceState& workspace); private: Gtk::Box box_; - Gtk::Label number_; Gtk::Box icons_; - std::vector> window_icons_; + WorkspaceNumber number_; + + std::unordered_map> window_icons_; }; diff --git a/include/modules/hyprland/workbar/workspace_number.hpp b/include/modules/hyprland/workbar/workspace_number.hpp new file mode 100644 index 0000000000..6ba52e4c35 --- /dev/null +++ b/include/modules/hyprland/workbar/workspace_number.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "modules/hyprland/workbar/workspace_number.hpp" + +namespace waybar::modules::hyprland::workbar { + +class WorkspaceNumber : public Gtk::Button { + public: + explicit WorkspaceNumber(int workspace_id); + int workspaceId() const; + void setWorkspace(int workspace_id); + + protected: + bool on_enter_notify_event(GdkEventCrossing* event) override; + bool on_leave_notify_event(GdkEventCrossing* event) override; + + private: + int workspace_id_; + + Gtk::Label label_; +}; + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/meson.build b/meson.build index ef84223a6e..8eda36a76c 100644 --- a/meson.build +++ b/meson.build @@ -329,6 +329,8 @@ if true 'src/modules/hyprland/workbar/model.cpp', 'src/modules/hyprland/workbar/backend.cpp', 'src/modules/hyprland/workbar/window_icon.cpp', + 'src/modules/hyprland/workbar/workspace_number.cpp', + 'src/modules/hyprland/workbar/drag_state.cpp', 'src/modules/hyprland/windowcreationpayload.cpp', ) man_files += files( diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index 84cf420dd9..d82f810c53 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -53,6 +53,7 @@ WorkspaceList Backend::getWorkspaces() { client["address"].asString(), client["class"].asString(), client["title"].asString(), + state.id, }); } diff --git a/src/modules/hyprland/workbar/drag_state.cpp b/src/modules/hyprland/workbar/drag_state.cpp new file mode 100644 index 0000000000..50c1039492 --- /dev/null +++ b/src/modules/hyprland/workbar/drag_state.cpp @@ -0,0 +1,7 @@ +#include "modules/hyprland/workbar/drag_state.hpp" + +namespace waybar::modules::hyprland::workbar { + +DragState drag_state; + +} \ No newline at end of file diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp index 8a15135771..35ffb6b5c4 100644 --- a/src/modules/hyprland/workbar/widget.cpp +++ b/src/modules/hyprland/workbar/widget.cpp @@ -1,14 +1,19 @@ #include "modules/hyprland/workbar/widget.hpp" +#include "modules/hyprland/workbar/workspace_button.hpp" +#include #include #include #include namespace waybar::modules::hyprland::workbar { + Widget* Widget::instance_ = nullptr; + Widget::Widget() : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { + instance_ = this; show_all(); } @@ -65,4 +70,148 @@ namespace waybar::modules::hyprland::workbar { show_all(); } + Widget* Widget::instance() { + return instance_; + } + + WorkspaceButton* Widget::workspaceAt(int x, int y) { + + std::cout << "Testing: " << x << ", " << y << std::endl; + + auto children = get_children(); + + for (size_t i = 0; i < children.size(); ++i) { + + auto* button = dynamic_cast(children[i]); + + if (!button) { + std::cout << "Child " << i << " is NOT a WorkspaceButton" << std::endl; + continue; + } + + std::cout << "Child " << i + << " is workspace " + << button->id() + << std::endl; + + int left, top; + button->translate_coordinates(*this, 0, 0, left, top); + + + int right; + + if (i + 1 < children.size()) { + + auto* next = + dynamic_cast(children[i + 1]); + + int next_left, next_top; + next->translate_coordinates(*this, 0, 0, next_left, next_top); + + right = next_left; + + } else { + + right = get_allocation().get_width(); + } + + std::cout + << "Workspace " + << button->id() + << " left=" << left + << " right=" << right + << std::endl; + + + std::cout + << "Check: " + << (x >= left) + << " " + << (x < right) + << std::endl; + + + if (x >= left && + x < right) { + + std::cout << "MATCH " << button->id() << std::endl; + + return button; + } + } + + return nullptr; +} + +void Widget::beginDrag(const WindowState& window) { + + dragging_ = true; + dragged_window_ = window; + hovered_workspace_ = nullptr; + + std::cout + << "Begin drag, hovered=" + << hovered_workspace_ + << '\n'; +} + +void Widget::updateDrag(double x, double y) { + + static int count = 0; + + std::cout << "\n===== updateDrag #" << ++count << " =====\n"; + + if (!dragging_) { + std::cout << "dragging = false\n"; + return; + } + + int wx, wy; + get_window()->get_origin(wx, wy); + + auto* ws = workspaceAt(x - wx, y - wy); + + std::cout + << "ws = " << ws << '\n' + << "hovered = " << hovered_workspace_ << '\n'; + + if (ws != hovered_workspace_) { + + std::cout << "ENTERED IF\n"; + + hovered_workspace_ = ws; + + if (ws) { + std::cout << "Hover workspace " + << ws->id() + << '\n'; + } + } +} + +void Widget::endDrag() { + + if (!dragging_) + return; + + dragging_ = false; + + if (hovered_workspace_) { + + std::cout << "Drop on " + << hovered_workspace_->id() + << std::endl; + + std::string cmd = + "hyprctl dispatch movetoworkspacesilent " + + std::to_string(hovered_workspace_->id()) + + ",address:" + + dragged_window_.address; + + std::system(cmd.c_str()); + } + + hovered_workspace_ = nullptr; +} + } // namespace waybar::modules::hyprland \ No newline at end of file diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp index 9afd2aba2c..a06add3d3b 100644 --- a/src/modules/hyprland/workbar/window_icon.cpp +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -1,11 +1,37 @@ +#include +#include +#include +#include +#include +#include + #include #include "modules/hyprland/workbar/window_icon.hpp" +#include "modules/hyprland/workbar/drag_state.hpp" +#include "modules/hyprland/workbar/widget.hpp" + +using WorkbarWidget = waybar::modules::hyprland::workbar::Widget; namespace waybar::modules::hyprland::workbar { WindowIcon::WindowIcon(const WindowState& window) { + + add(image_); + + add_events( + Gdk::BUTTON_PRESS_MASK | + Gdk::BUTTON_RELEASE_MASK | + Gdk::POINTER_MOTION_MASK + ); + + // Existing signal_clicked() + // Existing signal_button_press_event() + // ... + setWindow(window); + + show_all(); } void WindowIcon::setWindow(const WindowState& window) { @@ -19,9 +45,114 @@ void WindowIcon::setWindow(const WindowState& window) { Gtk::ICON_SIZE_MENU); } - add(image_); + window_ = window; show_all(); + + signal_clicked().connect([this]() { + + std::string cmd = + std::string(std::getenv("HOME")) + + "/.config/hypr/scripts/smart-workspace " + + std::to_string(window_.workspace_id); + + std::system(cmd.c_str()); + + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + + cmd = "hyprctl dispatch focuswindow address:" + window_.address; + + std::system(cmd.c_str()); + }); + + std::vector targets = { + Gtk::TargetEntry("WORKBAR_WINDOW") + }; + + add_events(Gdk::BUTTON_PRESS_MASK); + + +} + + +bool WindowIcon::on_button_press_event(GdkEventButton* event) { + + if (event->button == 1) { + left_pressed_ = true; + + press_x_ = event->x; + press_y_ = event->y; + dragging_ = false; + } + + return Gtk::Button::on_button_press_event(event); +} + +bool WindowIcon::on_motion_notify_event(GdkEventMotion* event) { + if (!left_pressed_) { + return Gtk::Button::on_motion_notify_event(event); + } + + if (!dragging_) { + + double dx = event->x - press_x_; + double dy = event->y - press_y_; + + if (dx * dx + dy * dy > 36) { + dragging_ = true; + + auto* widget = WorkbarWidget::instance(); + + if (widget) { + widget->beginDrag(window_); + } + } + } + + // <-- ADD THIS NEW BLOCK + if (dragging_) { + + auto* widget = WorkbarWidget::instance(); + + if (widget) { + widget->updateDrag(event->x_root, event->y_root); + } + } + + return Gtk::Button::on_motion_notify_event(event); +} + +bool WindowIcon::on_button_release_event(GdkEventButton* event) { + + left_pressed_ = false; + + if (dragging_) { + + dragging_ = false; + + auto* widget = WorkbarWidget::instance(); + if (widget) { + widget->endDrag(); + } + + } else if (event->button == 1) { + + std::string cmd = + std::string(std::getenv("HOME")) + + "/.config/hypr/scripts/smart-workspace " + + std::to_string(window_.workspace_id); + + std::system(cmd.c_str()); + + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + + cmd = "hyprctl dispatch focuswindow address:" + window_.address; + + std::system(cmd.c_str()); + + } + + return true; } } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index 0cd9ec165b..d12e037ed8 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -1,15 +1,27 @@ #include "modules/hyprland/workbar/workspace_button.hpp" +#include + namespace waybar::modules::hyprland::workbar { +int WorkspaceButton::id() const { + return number_.workspaceId(); +} + WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) - : box_(Gtk::ORIENTATION_HORIZONTAL), - icons_(Gtk::ORIENTATION_HORIZONTAL) { + : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL), + number_(workspace.id), + box_(Gtk::ORIENTATION_HORIZONTAL), + icons_(Gtk::ORIENTATION_HORIZONTAL) { + + get_style_context()->add_class("workspace"); + + box_.get_style_context()->add_class("workspace-content"); box_.pack_start(number_, Gtk::PACK_SHRINK); box_.pack_start(icons_, Gtk::PACK_SHRINK); - add(box_); + pack_start(box_, Gtk::PACK_EXPAND_WIDGET); setWorkspace(workspace); @@ -24,11 +36,9 @@ void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { icons_.remove(*child); } - number_.set_text(std::to_string(workspace.id)); - auto context = get_style_context(); - context->add_class("workspace"); + std::unordered_set seen; if (workspace.active) { context->add_class("active"); @@ -43,11 +53,29 @@ void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { } for (const auto& window : workspace.windows) { + seen.insert(window.address); + + auto it = window_icons_.find(window.address); + + if (it != window_icons_.end()) { + it->second->setWindow(window); + continue; + } + auto icon = std::make_unique(window); icons_.pack_start(*icon, Gtk::PACK_SHRINK); - window_icons_.push_back(std::move(icon)); + window_icons_.emplace(window.address, std::move(icon)); + } + + for (auto it = window_icons_.begin(); it != window_icons_.end();) { + if (!seen.contains(it->first)) { + icons_.remove(*it->second); + it = window_icons_.erase(it); + } else { + ++it; + } } show_all(); diff --git a/src/modules/hyprland/workbar/workspace_number.cpp b/src/modules/hyprland/workbar/workspace_number.cpp new file mode 100644 index 0000000000..24627450ab --- /dev/null +++ b/src/modules/hyprland/workbar/workspace_number.cpp @@ -0,0 +1,61 @@ +#include +#include +#include + +#include "modules/hyprland/workbar/workspace_number.hpp" +#include "modules/hyprland/workbar/drag_state.hpp" + +namespace waybar::modules::hyprland::workbar { + +int WorkspaceNumber::workspaceId() const { + return workspace_id_; +} + +WorkspaceNumber::WorkspaceNumber(int workspace_id) { + add(label_); + + add_events( + Gdk::ENTER_NOTIFY_MASK | + Gdk::LEAVE_NOTIFY_MASK + ); + + setWorkspace(workspace_id); + show_all(); + + drag_dest_set({ Gtk::TargetEntry("WORKBAR_WINDOW") }, Gtk::DEST_DEFAULT_ALL, Gdk::DragAction::ACTION_MOVE); + + signal_drag_data_received().connect( + [this](const Glib::RefPtr&, + int, + int, + const Gtk::SelectionData&, + guint, + guint) { + }); + + signal_clicked().connect([this]() { + std::string cmd = + std::string(std::getenv("HOME")) + + "/.config/hypr/scripts/smart-workspace " + + std::to_string(workspace_id_); + + std::system(cmd.c_str()); + }); +} + +void WorkspaceNumber::setWorkspace(int workspace_id) { + workspace_id_ = workspace_id; + label_.set_text(std::to_string(workspace_id)); +} + +bool WorkspaceNumber::on_enter_notify_event(GdkEventCrossing* event) { + + return Gtk::Button::on_enter_notify_event(event); +} + +bool WorkspaceNumber::on_leave_notify_event(GdkEventCrossing* event) { + + return Gtk::Button::on_leave_notify_event(event); +} + +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file From 7bc733c806ea21caae84c05e6176ce1a6bf74d19 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Sat, 4 Jul 2026 18:30:10 +0530 Subject: [PATCH 10/14] Implement custom Hyprland workbar with drag-and-drop and active window highlighting --- include/modules/hyprland/workbar/model.hpp | 2 + .../hyprland/workbar/workspace_number.hpp | 3 ++ src/modules/hyprland/workbar/backend.cpp | 6 +++ src/modules/hyprland/workbar/widget.cpp | 50 ++----------------- src/modules/hyprland/workbar/window_icon.cpp | 46 ++++++++++++++--- .../hyprland/workbar/workspace_button.cpp | 18 ++++++- .../hyprland/workbar/workspace_number.cpp | 6 +++ 7 files changed, 77 insertions(+), 54 deletions(-) diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp index 28ad4c08ad..73a79c5636 100644 --- a/include/modules/hyprland/workbar/model.hpp +++ b/include/modules/hyprland/workbar/model.hpp @@ -11,6 +11,8 @@ struct WindowState { std::string title; int workspace_id; + + bool active = false; }; struct WorkspaceState { diff --git a/include/modules/hyprland/workbar/workspace_number.hpp b/include/modules/hyprland/workbar/workspace_number.hpp index 6ba52e4c35..0e2ae8ef54 100644 --- a/include/modules/hyprland/workbar/workspace_number.hpp +++ b/include/modules/hyprland/workbar/workspace_number.hpp @@ -12,6 +12,9 @@ class WorkspaceNumber : public Gtk::Button { explicit WorkspaceNumber(int workspace_id); int workspaceId() const; void setWorkspace(int workspace_id); + Glib::RefPtr style() { + return get_style_context(); + } protected: bool on_enter_notify_event(GdkEventCrossing* event) override; diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index d82f810c53..b17850ccf3 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -13,11 +13,16 @@ Backend::Backend() ipc_.registerForIPC("openwindow", this); ipc_.registerForIPC("closewindow", this); ipc_.registerForIPC("movewindowv2", this); + + ipc_.registerForIPC("activewindowv2", this); + //ipc_.registerForIPC("windowtitlev2", this);//Turn this if you see bug } WorkspaceList Backend::getWorkspaces() { auto json = ipc_.getSocket1JsonReply("workspaces"); auto clients = ipc_.getSocket1JsonReply("clients"); + auto active_window = ipc_.getSocket1JsonReply("activewindow"); + std::string active_address = active_window["address"].asString(); WorkspaceList workspaces; @@ -54,6 +59,7 @@ WorkspaceList Backend::getWorkspaces() { client["class"].asString(), client["title"].asString(), state.id, + client["address"].asString() == active_address }); } diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp index 35ffb6b5c4..6a7cf8fb40 100644 --- a/src/modules/hyprland/workbar/widget.cpp +++ b/src/modules/hyprland/workbar/widget.cpp @@ -76,7 +76,7 @@ namespace waybar::modules::hyprland::workbar { WorkspaceButton* Widget::workspaceAt(int x, int y) { - std::cout << "Testing: " << x << ", " << y << std::endl; + auto children = get_children(); @@ -85,15 +85,10 @@ namespace waybar::modules::hyprland::workbar { auto* button = dynamic_cast(children[i]); if (!button) { - std::cout << "Child " << i << " is NOT a WorkspaceButton" << std::endl; + continue; } - std::cout << "Child " << i - << " is workspace " - << button->id() - << std::endl; - int left, top; button->translate_coordinates(*this, 0, 0, left, top); @@ -115,26 +110,9 @@ namespace waybar::modules::hyprland::workbar { right = get_allocation().get_width(); } - std::cout - << "Workspace " - << button->id() - << " left=" << left - << " right=" << right - << std::endl; - - - std::cout - << "Check: " - << (x >= left) - << " " - << (x < right) - << std::endl; - if (x >= left && x < right) { - - std::cout << "MATCH " << button->id() << std::endl; return button; } @@ -148,21 +126,14 @@ void Widget::beginDrag(const WindowState& window) { dragging_ = true; dragged_window_ = window; hovered_workspace_ = nullptr; - - std::cout - << "Begin drag, hovered=" - << hovered_workspace_ - << '\n'; } void Widget::updateDrag(double x, double y) { static int count = 0; - std::cout << "\n===== updateDrag #" << ++count << " =====\n"; - if (!dragging_) { - std::cout << "dragging = false\n"; + return; } @@ -171,21 +142,10 @@ void Widget::updateDrag(double x, double y) { auto* ws = workspaceAt(x - wx, y - wy); - std::cout - << "ws = " << ws << '\n' - << "hovered = " << hovered_workspace_ << '\n'; - if (ws != hovered_workspace_) { - std::cout << "ENTERED IF\n"; - hovered_workspace_ = ws; - if (ws) { - std::cout << "Hover workspace " - << ws->id() - << '\n'; - } } } @@ -198,10 +158,6 @@ void Widget::endDrag() { if (hovered_workspace_) { - std::cout << "Drop on " - << hovered_workspace_->id() - << std::endl; - std::string cmd = "hyprctl dispatch movetoworkspacesilent " + std::to_string(hovered_workspace_->id()) diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp index a06add3d3b..86c8c5930e 100644 --- a/src/modules/hyprland/workbar/window_icon.cpp +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -19,6 +19,8 @@ WindowIcon::WindowIcon(const WindowState& window) { add(image_); + get_style_context()->add_class("window-icon"); + add_events( Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | @@ -32,21 +34,53 @@ WindowIcon::WindowIcon(const WindowState& window) { setWindow(window); show_all(); + + int min_h, nat_h; + get_preferred_height(min_h, nat_h); + + std::cout + << "WindowIcon min=" << min_h + << " nat=" << nat_h + << '\n'; } void WindowIcon::setWindow(const WindowState& window) { auto theme = Gtk::IconTheme::get_default(); - if (theme->has_icon(window.class_name)) { - image_.set_from_icon_name(window.class_name, - Gtk::ICON_SIZE_MENU); - } else { - image_.set_from_icon_name("application-x-executable", - Gtk::ICON_SIZE_MENU); + try { + auto pixbuf = theme->load_icon( + theme->has_icon(window.class_name) + ? window.class_name + : "application-x-executable", + 64, // load a large icon + Gtk::ICON_LOOKUP_FORCE_SIZE); + + auto scaled = pixbuf->scale_simple( + 16, 16, + Gdk::INTERP_BILINEAR); + + image_.set(scaled); + + std::cout + << "Image size: " + << image_.get_pixbuf()->get_width() + << "x" + << image_.get_pixbuf()->get_height() + << '\n'; + + } catch (...) { } window_ = window; + auto context = get_style_context(); + + if (window.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } + show_all(); signal_clicked().connect([this]() { diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index d12e037ed8..6ae7267a94 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -1,3 +1,4 @@ +#include #include "modules/hyprland/workbar/workspace_button.hpp" #include @@ -16,8 +17,15 @@ WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) get_style_context()->add_class("workspace"); + std::cout << "Workspace classes:\n"; + for (auto& c : get_style_context()->list_classes()) + std::cout << " " << c << '\n'; + box_.get_style_context()->add_class("workspace-content"); + icons_.get_style_context()->add_class("workspace-icons"); + number_.get_style_context()->add_class("workspace-number"); + box_.pack_start(number_, Gtk::PACK_SHRINK); box_.pack_start(icons_, Gtk::PACK_SHRINK); @@ -26,6 +34,14 @@ WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) setWorkspace(workspace); show_all(); + + int min_h, nat_h; + get_preferred_height(min_h, nat_h); + + std::cout + << "WorkspaceButton min=" << min_h + << " nat=" << nat_h + << '\n'; } void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { @@ -36,7 +52,7 @@ void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { icons_.remove(*child); } - auto context = get_style_context(); + auto context = number_.style(); std::unordered_set seen; diff --git a/src/modules/hyprland/workbar/workspace_number.cpp b/src/modules/hyprland/workbar/workspace_number.cpp index 24627450ab..7e83876a0e 100644 --- a/src/modules/hyprland/workbar/workspace_number.cpp +++ b/src/modules/hyprland/workbar/workspace_number.cpp @@ -14,6 +14,12 @@ int WorkspaceNumber::workspaceId() const { WorkspaceNumber::WorkspaceNumber(int workspace_id) { add(label_); + get_style_context()->add_class("workspace-number"); + + std::cout << "Number classes:\n"; + for (auto& c : get_style_context()->list_classes()) + std::cout << " " << c << '\n'; + add_events( Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK From 2088542a8ba3490b2bf1a391d4626dcae2b74a1a Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Sat, 4 Jul 2026 23:44:14 +0530 Subject: [PATCH 11/14] Added middle click to close window --- src/modules/hyprland/workbar/window_icon.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp index 86c8c5930e..80c2fc859c 100644 --- a/src/modules/hyprland/workbar/window_icon.cpp +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -158,6 +158,15 @@ bool WindowIcon::on_motion_notify_event(GdkEventMotion* event) { bool WindowIcon::on_button_release_event(GdkEventButton* event) { + if (event->button == 2) { + std::string cmd = + "hyprctl dispatch closewindow address:" + window_.address; + + std::system(cmd.c_str()); + + return true; + } + left_pressed_ = false; if (dragging_) { From 677049d50dcea0784e23057abaa3f509009eee39 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Sun, 5 Jul 2026 01:11:40 +0530 Subject: [PATCH 12/14] Cleaned Workbar --- src/client.cpp | 2 - src/modules/hyprland/workbar/backend.cpp | 4 +- src/modules/hyprland/workbar/window_icon.cpp | 58 +++++-------------- .../hyprland/workbar/workspace_button.cpp | 22 +------ .../hyprland/workbar/workspace_number.cpp | 5 -- 5 files changed, 20 insertions(+), 71 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index d148918679..1288b90b03 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -275,11 +275,9 @@ int waybar::Client::main(int argc, char* argv[]) { return 1; } if (show_help) { - std::cout << cli << '\n'; return 0; } if (show_version) { - std::cout << "Waybar v" << VERSION << '\n'; return 0; } if (!log_level.empty()) { diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index b17850ccf3..86cd414520 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -1,4 +1,3 @@ -#include #include #include "modules/hyprland/workbar/backend.hpp" @@ -21,6 +20,7 @@ Backend::Backend() WorkspaceList Backend::getWorkspaces() { auto json = ipc_.getSocket1JsonReply("workspaces"); auto clients = ipc_.getSocket1JsonReply("clients"); + // Determine the currently focused window so it can be highlighted in the workbar. auto active_window = ipc_.getSocket1JsonReply("activewindow"); std::string active_address = active_window["address"].asString(); @@ -73,7 +73,7 @@ void Backend::setUpdateCallback(std::function callback) { update_callback_ = std::move(callback); } -void Backend::onEvent(const std::string& ev) { +void Backend::onEvent(const std::string&) { if (update_callback_) { update_callback_(); diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp index 80c2fc859c..ea194caf9a 100644 --- a/src/modules/hyprland/workbar/window_icon.cpp +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -1,9 +1,7 @@ -#include #include #include #include #include -#include #include @@ -27,21 +25,26 @@ WindowIcon::WindowIcon(const WindowState& window) { Gdk::POINTER_MOTION_MASK ); - // Existing signal_clicked() - // Existing signal_button_press_event() - // ... + signal_clicked().connect([this]() { + + std::string cmd = + std::string(std::getenv("HOME")) + + "/.config/hypr/scripts/smart-workspace " + + std::to_string(window_.workspace_id); + + std::system(cmd.c_str()); + + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + + cmd = "hyprctl dispatch focuswindow address:" + window_.address; + + std::system(cmd.c_str()); + }); setWindow(window); show_all(); - int min_h, nat_h; - get_preferred_height(min_h, nat_h); - - std::cout - << "WindowIcon min=" << min_h - << " nat=" << nat_h - << '\n'; } void WindowIcon::setWindow(const WindowState& window) { @@ -60,13 +63,6 @@ void WindowIcon::setWindow(const WindowState& window) { Gdk::INTERP_BILINEAR); image_.set(scaled); - - std::cout - << "Image size: " - << image_.get_pixbuf()->get_width() - << "x" - << image_.get_pixbuf()->get_height() - << '\n'; } catch (...) { } @@ -81,30 +77,6 @@ void WindowIcon::setWindow(const WindowState& window) { context->remove_class("active"); } - show_all(); - - signal_clicked().connect([this]() { - - std::string cmd = - std::string(std::getenv("HOME")) + - "/.config/hypr/scripts/smart-workspace " + - std::to_string(window_.workspace_id); - - std::system(cmd.c_str()); - - std::this_thread::sleep_for(std::chrono::milliseconds(40)); - - cmd = "hyprctl dispatch focuswindow address:" + window_.address; - - std::system(cmd.c_str()); - }); - - std::vector targets = { - Gtk::TargetEntry("WORKBAR_WINDOW") - }; - - add_events(Gdk::BUTTON_PRESS_MASK); - } diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index 6ae7267a94..7e21e0d1aa 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -1,4 +1,4 @@ -#include + #include "modules/hyprland/workbar/workspace_button.hpp" #include @@ -17,10 +17,6 @@ WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) get_style_context()->add_class("workspace"); - std::cout << "Workspace classes:\n"; - for (auto& c : get_style_context()->list_classes()) - std::cout << " " << c << '\n'; - box_.get_style_context()->add_class("workspace-content"); icons_.get_style_context()->add_class("workspace-icons"); @@ -35,23 +31,10 @@ WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) show_all(); - int min_h, nat_h; - get_preferred_height(min_h, nat_h); - - std::cout - << "WorkspaceButton min=" << min_h - << " nat=" << nat_h - << '\n'; } void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { - window_icons_.clear(); - - for (auto* child : icons_.get_children()) { - icons_.remove(*child); - } - auto context = number_.style(); std::unordered_set seen; @@ -81,6 +64,7 @@ void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { auto icon = std::make_unique(window); icons_.pack_start(*icon, Gtk::PACK_SHRINK); + icon->show(); window_icons_.emplace(window.address, std::move(icon)); } @@ -94,7 +78,7 @@ void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { } } - show_all(); + show(); } diff --git a/src/modules/hyprland/workbar/workspace_number.cpp b/src/modules/hyprland/workbar/workspace_number.cpp index 7e83876a0e..01993f17b6 100644 --- a/src/modules/hyprland/workbar/workspace_number.cpp +++ b/src/modules/hyprland/workbar/workspace_number.cpp @@ -1,4 +1,3 @@ -#include #include #include @@ -16,10 +15,6 @@ WorkspaceNumber::WorkspaceNumber(int workspace_id) { get_style_context()->add_class("workspace-number"); - std::cout << "Number classes:\n"; - for (auto& c : get_style_context()->list_classes()) - std::cout << " " << c << '\n'; - add_events( Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK From da75dcdb34aa0ddaea829ca6d72a65f1d0c8f1a7 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Mon, 6 Jul 2026 02:16:41 +0530 Subject: [PATCH 13/14] Made it independent of workspace changing script --- include/modules/hyprland/workbar/model.hpp | 1 + .../modules/hyprland/workbar/window_icon.hpp | 3 ++ src/modules/hyprland/workbar/backend.cpp | 3 +- src/modules/hyprland/workbar/widget.cpp | 12 ++--- src/modules/hyprland/workbar/window_icon.cpp | 50 ++++++++----------- .../hyprland/workbar/workspace_number.cpp | 24 +++++++-- 6 files changed, 51 insertions(+), 42 deletions(-) diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp index 73a79c5636..f52726249b 100644 --- a/include/modules/hyprland/workbar/model.hpp +++ b/include/modules/hyprland/workbar/model.hpp @@ -13,6 +13,7 @@ struct WindowState { int workspace_id; bool active = false; + bool workspace_visible = false; }; struct WorkspaceState { diff --git a/include/modules/hyprland/workbar/window_icon.hpp b/include/modules/hyprland/workbar/window_icon.hpp index 39a2648847..61e97318f9 100644 --- a/include/modules/hyprland/workbar/window_icon.hpp +++ b/include/modules/hyprland/workbar/window_icon.hpp @@ -12,6 +12,7 @@ class WindowIcon : public Gtk::Button { explicit WindowIcon(const WindowState& window); void setWindow(const WindowState& window); + protected: bool on_button_press_event(GdkEventButton* event) override; @@ -19,6 +20,8 @@ class WindowIcon : public Gtk::Button { bool on_button_release_event(GdkEventButton* event) override; private: + + void focusWindow(); Gtk::Image image_; WindowState window_; diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index 86cd414520..66166dd1d8 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -59,7 +59,8 @@ WorkspaceList Backend::getWorkspaces() { client["class"].asString(), client["title"].asString(), state.id, - client["address"].asString() == active_address + client["address"].asString() == active_address, + state.visible }); } diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp index 6a7cf8fb40..04f4d2c128 100644 --- a/src/modules/hyprland/workbar/widget.cpp +++ b/src/modules/hyprland/workbar/widget.cpp @@ -1,5 +1,6 @@ #include "modules/hyprland/workbar/widget.hpp" #include "modules/hyprland/workbar/workspace_button.hpp" +#include "modules/hyprland/backend.hpp" #include #include @@ -158,13 +159,10 @@ void Widget::endDrag() { if (hovered_workspace_) { - std::string cmd = - "hyprctl dispatch movetoworkspacesilent " - + std::to_string(hovered_workspace_->id()) - + ",address:" - + dragged_window_.address; - - std::system(cmd.c_str()); + IPC::dispatch( + "movetoworkspacesilent", + std::to_string(hovered_workspace_->id()) + + ",address:" + dragged_window_.address); } hovered_workspace_ = nullptr; diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp index ea194caf9a..6ba50ccdc6 100644 --- a/src/modules/hyprland/workbar/window_icon.cpp +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -8,11 +8,28 @@ #include "modules/hyprland/workbar/window_icon.hpp" #include "modules/hyprland/workbar/drag_state.hpp" #include "modules/hyprland/workbar/widget.hpp" +#include "modules/hyprland/backend.hpp" using WorkbarWidget = waybar::modules::hyprland::workbar::Widget; namespace waybar::modules::hyprland::workbar { + +void WindowIcon::focusWindow() { + if (window_.workspace_visible) { + IPC::dispatch("workspace", + std::to_string(window_.workspace_id)); + } else { + IPC::dispatch("focusworkspaceoncurrentmonitor", + std::to_string(window_.workspace_id)); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(40)); + + IPC::dispatch("focuswindow", + "address:" + window_.address); +} + WindowIcon::WindowIcon(const WindowState& window) { add(image_); @@ -26,19 +43,7 @@ WindowIcon::WindowIcon(const WindowState& window) { ); signal_clicked().connect([this]() { - - std::string cmd = - std::string(std::getenv("HOME")) + - "/.config/hypr/scripts/smart-workspace " + - std::to_string(window_.workspace_id); - - std::system(cmd.c_str()); - - std::this_thread::sleep_for(std::chrono::milliseconds(40)); - - cmd = "hyprctl dispatch focuswindow address:" + window_.address; - - std::system(cmd.c_str()); + focusWindow(); }); setWindow(window); @@ -131,10 +136,8 @@ bool WindowIcon::on_motion_notify_event(GdkEventMotion* event) { bool WindowIcon::on_button_release_event(GdkEventButton* event) { if (event->button == 2) { - std::string cmd = - "hyprctl dispatch closewindow address:" + window_.address; - - std::system(cmd.c_str()); + IPC::dispatch("closewindow", + "address:" + window_.address); return true; } @@ -152,18 +155,7 @@ bool WindowIcon::on_button_release_event(GdkEventButton* event) { } else if (event->button == 1) { - std::string cmd = - std::string(std::getenv("HOME")) + - "/.config/hypr/scripts/smart-workspace " + - std::to_string(window_.workspace_id); - - std::system(cmd.c_str()); - - std::this_thread::sleep_for(std::chrono::milliseconds(40)); - - cmd = "hyprctl dispatch focuswindow address:" + window_.address; - - std::system(cmd.c_str()); + focusWindow(); } diff --git a/src/modules/hyprland/workbar/workspace_number.cpp b/src/modules/hyprland/workbar/workspace_number.cpp index 01993f17b6..a25bbc16b8 100644 --- a/src/modules/hyprland/workbar/workspace_number.cpp +++ b/src/modules/hyprland/workbar/workspace_number.cpp @@ -3,6 +3,7 @@ #include "modules/hyprland/workbar/workspace_number.hpp" #include "modules/hyprland/workbar/drag_state.hpp" +#include "modules/hyprland/backend.hpp" namespace waybar::modules::hyprland::workbar { @@ -35,12 +36,25 @@ WorkspaceNumber::WorkspaceNumber(int workspace_id) { }); signal_clicked().connect([this]() { - std::string cmd = - std::string(std::getenv("HOME")) + - "/.config/hypr/scripts/smart-workspace " + - std::to_string(workspace_id_); - std::system(cmd.c_str()); + auto monitors = IPC::inst().getSocket1JsonReply("monitors"); + + bool visible = false; + + for (const auto& monitor : monitors) { + if (monitor["activeWorkspace"]["id"].asInt() == workspace_id_) { + visible = true; + break; + } + } + + if (visible) { + IPC::dispatch("workspace", + std::to_string(workspace_id_)); + } else { + IPC::dispatch("focusworkspaceoncurrentmonitor", + std::to_string(workspace_id_)); + } }); } From f319322b31e4487e3cb7841a86bfd63d641f30c4 Mon Sep 17 00:00:00 2001 From: Uts-v-Sinha Date: Tue, 7 Jul 2026 20:44:22 +0530 Subject: [PATCH 14/14] Refactor workbar to use native Hyprland IPC --- include/modules/hyprland/workbar/backend.hpp | 2 +- .../modules/hyprland/workbar/drag_state.hpp | 8 +- include/modules/hyprland/workbar/model.hpp | 22 +- include/modules/hyprland/workbar/module.hpp | 14 +- include/modules/hyprland/workbar/widget.hpp | 38 ++-- .../modules/hyprland/workbar/window_icon.hpp | 20 +- .../hyprland/workbar/workspace_button.hpp | 16 +- .../hyprland/workbar/workspace_number.hpp | 8 +- man/waybar-hyprland-workbar.5.scd | 78 +++++++ meson.build | 1 + src/factory.cpp | 4 +- src/modules/hyprland/workbar/backend.cpp | 101 ++++----- src/modules/hyprland/workbar/module.cpp | 31 ++- src/modules/hyprland/workbar/widget.cpp | 205 ++++++++---------- src/modules/hyprland/workbar/window_icon.cpp | 190 +++++++--------- .../hyprland/workbar/workspace_button.cpp | 98 ++++----- .../hyprland/workbar/workspace_number.cpp | 96 ++++---- 17 files changed, 461 insertions(+), 471 deletions(-) create mode 100644 man/waybar-hyprland-workbar.5.scd diff --git a/include/modules/hyprland/workbar/backend.hpp b/include/modules/hyprland/workbar/backend.hpp index c443158bcb..d52759796b 100644 --- a/include/modules/hyprland/workbar/backend.hpp +++ b/include/modules/hyprland/workbar/backend.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include "modules/hyprland/backend.hpp" #include "modules/hyprland/workbar/model.hpp" diff --git a/include/modules/hyprland/workbar/drag_state.hpp b/include/modules/hyprland/workbar/drag_state.hpp index a59aee00c7..6224c79b78 100644 --- a/include/modules/hyprland/workbar/drag_state.hpp +++ b/include/modules/hyprland/workbar/drag_state.hpp @@ -5,11 +5,11 @@ namespace waybar::modules::hyprland::workbar { struct DragState { - bool dragging = false; - std::string window_address; - int source_workspace = -1; + bool dragging = false; + std::string window_address; + int source_workspace = -1; }; extern DragState drag_state; -} \ No newline at end of file +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/model.hpp b/include/modules/hyprland/workbar/model.hpp index f52726249b..b88b75264a 100644 --- a/include/modules/hyprland/workbar/model.hpp +++ b/include/modules/hyprland/workbar/model.hpp @@ -6,25 +6,25 @@ namespace waybar::modules::hyprland::workbar { struct WindowState { - std::string address; - std::string class_name; - std::string title; + std::string address; + std::string class_name; + std::string title; - int workspace_id; + int workspace_id; - bool active = false; - bool workspace_visible = false; + bool active = false; + bool workspace_visible = false; }; struct WorkspaceState { - int id; + int id; - bool active = false; - bool visible = false; + bool active = false; + bool visible = false; - std::string monitor; + std::string monitor; - std::vector windows; + std::vector windows; }; using WorkspaceList = std::vector; diff --git a/include/modules/hyprland/workbar/module.hpp b/include/modules/hyprland/workbar/module.hpp index b584a01e55..db1add39c6 100644 --- a/include/modules/hyprland/workbar/module.hpp +++ b/include/modules/hyprland/workbar/module.hpp @@ -1,20 +1,20 @@ #pragma once #include "AModule.hpp" -#include "modules/hyprland/workbar/widget.hpp" #include "modules/hyprland/workbar/backend.hpp" +#include "modules/hyprland/workbar/widget.hpp" namespace waybar::modules::hyprland::workbar { class Module : public AModule { - public: - Module(const std::string& id, const Json::Value& config); + public: + Module(const std::string& id, const Json::Value& config); - void update() override; + void update() override; - private: - Backend backend_; - Widget widget_; + private: + Backend backend_; + Widget widget_; }; } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/widget.hpp b/include/modules/hyprland/workbar/widget.hpp index 6c045eb041..fff846048d 100644 --- a/include/modules/hyprland/workbar/widget.hpp +++ b/include/modules/hyprland/workbar/widget.hpp @@ -1,33 +1,33 @@ #pragma once #include + +#include #include +#include #include "modules/hyprland/workbar/model.hpp" #include "modules/hyprland/workbar/workspace_button.hpp" -#include -#include - namespace waybar::modules::hyprland::workbar { class Widget : public Gtk::Box { - public: - Widget(); - static Widget* instance(); - WorkspaceButton* workspaceAt(int x, int y); - void setWorkspaces(const WorkspaceList& workspaces); - void beginDrag(const WindowState& window); - void updateDrag(double x, double y); - void endDrag(); + public: + Widget(); + static Widget* instance(); + WorkspaceButton* workspaceAt(int x, int y); + void setWorkspaces(const WorkspaceList& workspaces); + void beginDrag(const WindowState& window); + void updateDrag(double x, double y); + void endDrag(); - private: - void clearWorkspaces(); - static Widget* instance_; - std::unordered_map> workspaces_; - bool dragging_ = false; - WindowState dragged_window_; - WorkspaceButton* hovered_workspace_ = nullptr; + private: + void clearWorkspaces(); + static Widget* instance_; + std::unordered_map> workspaces_; + bool dragging_ = false; + WindowState dragged_window_; + WorkspaceButton* hovered_workspace_ = nullptr; }; -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/window_icon.hpp b/include/modules/hyprland/workbar/window_icon.hpp index 61e97318f9..2bb7dbfaee 100644 --- a/include/modules/hyprland/workbar/window_icon.hpp +++ b/include/modules/hyprland/workbar/window_icon.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include "modules/hyprland/workbar/model.hpp" @@ -13,22 +13,20 @@ class WindowIcon : public Gtk::Button { void setWindow(const WindowState& window); - protected: bool on_button_press_event(GdkEventButton* event) override; bool on_motion_notify_event(GdkEventMotion* event) override; bool on_button_release_event(GdkEventButton* event) override; private: - - void focusWindow(); - Gtk::Image image_; - WindowState window_; - - bool left_pressed_ = false; - bool dragging_ = false; - double press_x_ = 0; - double press_y_ = 0; + void focusWindow(); + Gtk::Image image_; + WindowState window_; + + bool left_pressed_ = false; + bool dragging_ = false; + double press_x_ = 0; + double press_y_ = 0; }; } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/workspace_button.hpp b/include/modules/hyprland/workbar/workspace_button.hpp index 9cfcdd14e6..252bb04739 100644 --- a/include/modules/hyprland/workbar/workspace_button.hpp +++ b/include/modules/hyprland/workbar/workspace_button.hpp @@ -1,12 +1,13 @@ #pragma once -#include -#include -#include -#include #include -#include +#include #include +#include + +#include +#include +#include #include "modules/hyprland/workbar/model.hpp" #include "modules/hyprland/workbar/window_icon.hpp" @@ -22,7 +23,6 @@ class WorkspaceButton : public Gtk::Box { void setWorkspace(const WorkspaceState& workspace); private: - Gtk::Box box_; Gtk::Box icons_; @@ -31,6 +31,4 @@ class WorkspaceButton : public Gtk::Box { std::unordered_map> window_icons_; }; - - -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/include/modules/hyprland/workbar/workspace_number.hpp b/include/modules/hyprland/workbar/workspace_number.hpp index 0e2ae8ef54..58eab6ace0 100644 --- a/include/modules/hyprland/workbar/workspace_number.hpp +++ b/include/modules/hyprland/workbar/workspace_number.hpp @@ -12,13 +12,11 @@ class WorkspaceNumber : public Gtk::Button { explicit WorkspaceNumber(int workspace_id); int workspaceId() const; void setWorkspace(int workspace_id); - Glib::RefPtr style() { - return get_style_context(); - } + Glib::RefPtr style() { return get_style_context(); } protected: - bool on_enter_notify_event(GdkEventCrossing* event) override; - bool on_leave_notify_event(GdkEventCrossing* event) override; + bool on_enter_notify_event(GdkEventCrossing* event) override; + bool on_leave_notify_event(GdkEventCrossing* event) override; private: int workspace_id_; diff --git a/man/waybar-hyprland-workbar.5.scd b/man/waybar-hyprland-workbar.5.scd new file mode 100644 index 0000000000..8142c15ab9 --- /dev/null +++ b/man/waybar-hyprland-workbar.5.scd @@ -0,0 +1,78 @@ +waybar-hyprland-workbar(5) + +# NAME + +waybar - Hyprland workbar module + +# DESCRIPTION + +The *workbar* module combines the functionality of the traditional *workspaces* and *taskbar* modules into a single component. + +Each workspace is displayed as a single pill containing its workspace number along with icons representing the windows currently opened on that workspace. + +The module communicates directly with Hyprland through Waybar's native IPC backend and does not require any external helper scripts. + +The module is intended for users who prefer a workspace-centric workflow by grouping workspace navigation and window management into a single interface. + +# CONFIGURATION + +Addressed by *hyprland/workbar* + +*rotate*: ++ + typeof: integer ++ + default: 0 ++ + Rotates the module. + +# FEATURES + +- Unified replacement for Workspaces and Taskbar modules +- Displays application icons grouped by workspace +- Highlights the active workspace +- Highlights the active window +- Indicates workspaces visible on non-focused monitors +- Drag and drop windows between workspaces +- Middle-click window icons to close windows +- Native Hyprland IPC implementation +- Incremental widget updates for improved performance + +# INTERACTION + +Left-click workspace number:: + Switch to the selected workspace. + +Left-click window icon:: + Switch to the corresponding workspace (if necessary) and focus the selected window. + +Middle-click window icon:: + Close the selected window. + +Drag window icon:: + Move the window to another workspace. + +# EXAMPLE + +``` +"hyprland/workbar": { + "rotate": 0 +} +``` + +# STYLE + +The following CSS classes are available: + +- *#workbar* +- *.workspace* +- *.workspace-number* +- *.workspace-number.active* +- *.workspace-number.visible* +- *.window-icon* +- *.window-icon.active* + +# SEE ALSO + +*waybar*(5) + +*waybar-hyprland-workspaces*(5) + +*waybar-hyprland-window*(5) \ No newline at end of file diff --git a/meson.build b/meson.build index 8eda36a76c..0b4c38ac3a 100644 --- a/meson.build +++ b/meson.build @@ -338,6 +338,7 @@ if true 'man/waybar-hyprland-submap.5.scd', 'man/waybar-hyprland-window.5.scd', 'man/waybar-hyprland-workspaces.5.scd', + 'man/waybar-hyprland-workbar.5.scd', ) endif diff --git a/src/factory.cpp b/src/factory.cpp index 63260bb10d..655bea9856 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -35,8 +35,8 @@ #include "modules/hyprland/submap.hpp" #include "modules/hyprland/window.hpp" #include "modules/hyprland/windowcount.hpp" -#include "modules/hyprland/workspaces.hpp" #include "modules/hyprland/workbar/module.hpp" +#include "modules/hyprland/workspaces.hpp" #endif #ifdef HAVE_NIRI #include "modules/niri/language.hpp" @@ -221,7 +221,7 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name, return new waybar::modules::hyprland::Workspaces(id, bar_, config_[name]); } if (ref == "hyprland/workbar") { - return new waybar::modules::hyprland::workbar::Module(id, config_[name]); + return new waybar::modules::hyprland::workbar::Module(id, config_[name]); } #endif #ifdef HAVE_NIRI diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp index 66166dd1d8..d9317b71f6 100644 --- a/src/modules/hyprland/workbar/backend.cpp +++ b/src/modules/hyprland/workbar/backend.cpp @@ -1,73 +1,67 @@ -#include #include "modules/hyprland/workbar/backend.hpp" +#include namespace waybar::modules::hyprland::workbar { -Backend::Backend() - : ipc_(IPC::inst()) { - ipc_.registerForIPC("workspacev2", this); - ipc_.registerForIPC("focusedmonv2", this); +Backend::Backend() : ipc_(IPC::inst()) { + ipc_.registerForIPC("workspacev2", this); + ipc_.registerForIPC("focusedmonv2", this); - ipc_.registerForIPC("openwindow", this); - ipc_.registerForIPC("closewindow", this); - ipc_.registerForIPC("movewindowv2", this); + ipc_.registerForIPC("openwindow", this); + ipc_.registerForIPC("closewindow", this); + ipc_.registerForIPC("movewindowv2", this); - ipc_.registerForIPC("activewindowv2", this); - //ipc_.registerForIPC("windowtitlev2", this);//Turn this if you see bug + ipc_.registerForIPC("activewindowv2", this); + // ipc_.registerForIPC("windowtitlev2", this);//Turn this if you see bug } WorkspaceList Backend::getWorkspaces() { - auto json = ipc_.getSocket1JsonReply("workspaces"); - auto clients = ipc_.getSocket1JsonReply("clients"); - // Determine the currently focused window so it can be highlighted in the workbar. - auto active_window = ipc_.getSocket1JsonReply("activewindow"); - std::string active_address = active_window["address"].asString(); + auto json = ipc_.getSocket1JsonReply("workspaces"); + auto clients = ipc_.getSocket1JsonReply("clients"); + // Determine the currently focused window so it can be highlighted in the workbar. + auto active_window = ipc_.getSocket1JsonReply("activewindow"); + std::string active_address = active_window["address"].asString(); - WorkspaceList workspaces; + WorkspaceList workspaces; - auto monitors = ipc_.getSocket1JsonReply("monitors"); + auto monitors = ipc_.getSocket1JsonReply("monitors"); - std::unordered_set active_workspaces; - std::unordered_set visible_workspaces; + std::unordered_set active_workspaces; + std::unordered_set visible_workspaces; - for (const auto& monitor : monitors) { - int ws = monitor["activeWorkspace"]["id"].asInt(); + for (const auto& monitor : monitors) { + int ws = monitor["activeWorkspace"]["id"].asInt(); - visible_workspaces.insert(ws); + visible_workspaces.insert(ws); - if (monitor["focused"].asBool()) { - active_workspaces.insert(ws); - } + if (monitor["focused"].asBool()) { + active_workspaces.insert(ws); } + } + + for (const auto& ws : json) { + WorkspaceState state; + + state.id = ws["id"].asInt(); + state.active = active_workspaces.contains(state.id); + state.visible = visible_workspaces.contains(state.id); + state.monitor = ws["monitor"].asString(); - for (const auto& ws : json) { - WorkspaceState state; - - state.id = ws["id"].asInt(); - state.active = active_workspaces.contains(state.id); - state.visible = visible_workspaces.contains(state.id); - state.monitor = ws["monitor"].asString(); - - for (const auto& client : clients) { - if (client["workspace"]["id"].asInt() != state.id) { - continue; - } - - state.windows.push_back({ - client["address"].asString(), - client["class"].asString(), - client["title"].asString(), - state.id, - client["address"].asString() == active_address, - state.visible - }); - } - - workspaces.push_back(std::move(state)); + for (const auto& client : clients) { + if (client["workspace"]["id"].asInt() != state.id) { + continue; + } + + state.windows.push_back({client["address"].asString(), client["class"].asString(), + client["title"].asString(), state.id, + client["address"].asString() == active_address, state.visible}); } - return workspaces; + workspaces.push_back(std::move(state)); + } + + return workspaces; } void Backend::setUpdateCallback(std::function callback) { @@ -75,10 +69,9 @@ void Backend::setUpdateCallback(std::function callback) { } void Backend::onEvent(const std::string&) { - - if (update_callback_) { - update_callback_(); - } + if (update_callback_) { + update_callback_(); + } } } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/module.cpp b/src/modules/hyprland/workbar/module.cpp index f4587a1648..8467e54a5d 100644 --- a/src/modules/hyprland/workbar/module.cpp +++ b/src/modules/hyprland/workbar/module.cpp @@ -2,29 +2,26 @@ namespace waybar::modules::hyprland::workbar { - Module::Module(const std::string& id, const Json::Value& config) - : AModule(config, "workbar", id) { - widget_.set_name("workbar"); +Module::Module(const std::string& id, const Json::Value& config) : AModule(config, "workbar", id) { + widget_.set_name("workbar"); - widget_.get_style_context()->add_class(MODULE_CLASS); + widget_.get_style_context()->add_class(MODULE_CLASS); - if (!id.empty()) { - widget_.get_style_context()->add_class(id); - } + if (!id.empty()) { + widget_.get_style_context()->add_class(id); + } - event_box_.add(widget_); + event_box_.add(widget_); - backend_.setUpdateCallback([this]() { - dp.emit(); - }); + backend_.setUpdateCallback([this]() { dp.emit(); }); - dp.emit(); - } + dp.emit(); +} - void Module::update() { - widget_.setWorkspaces(backend_.getWorkspaces()); +void Module::update() { + widget_.setWorkspaces(backend_.getWorkspaces()); - AModule::update(); - } + AModule::update(); +} } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/widget.cpp b/src/modules/hyprland/workbar/widget.cpp index 04f4d2c128..06e92342a1 100644 --- a/src/modules/hyprland/workbar/widget.cpp +++ b/src/modules/hyprland/workbar/widget.cpp @@ -1,171 +1,146 @@ #include "modules/hyprland/workbar/widget.hpp" -#include "modules/hyprland/workbar/workspace_button.hpp" -#include "modules/hyprland/backend.hpp" +#include #include #include #include -#include - -namespace waybar::modules::hyprland::workbar { - - Widget* Widget::instance_ = nullptr; - - Widget::Widget() - : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { - - instance_ = this; - show_all(); - } - - void Widget::clearWorkspaces() { - for (auto& [id, button] : workspaces_) { - remove(*button); - } - workspaces_.clear(); - } - - void Widget::setWorkspaces(const WorkspaceList& workspaces) { - std::unordered_set seen; +#include "modules/hyprland/backend.hpp" +#include "modules/hyprland/workbar/workspace_button.hpp" - for (const auto& ws : workspaces) { - seen.insert(ws.id); +namespace waybar::modules::hyprland::workbar { - auto it = workspaces_.find(ws.id); +Widget* Widget::instance_ = nullptr; - if (it != workspaces_.end()) { - it->second->setWorkspace(ws); - continue; - } +Widget::Widget() : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL) { + instance_ = this; + show_all(); +} - auto button = std::make_unique(ws); +void Widget::clearWorkspaces() { + for (auto& [id, button] : workspaces_) { + remove(*button); + } - pack_start(*button, Gtk::PACK_SHRINK); + workspaces_.clear(); +} - workspaces_.emplace(ws.id, std::move(button)); - } +void Widget::setWorkspaces(const WorkspaceList& workspaces) { + std::unordered_set seen; - for (auto it = workspaces_.begin(); it != workspaces_.end();) { - if (!seen.contains(it->first)) { - remove(*it->second); - it = workspaces_.erase(it); - } else { - ++it; - } - } + for (const auto& ws : workspaces) { + seen.insert(ws.id); - std::vector ids; - ids.reserve(workspaces_.size()); + auto it = workspaces_.find(ws.id); - for (const auto& [id, _] : workspaces_) { - ids.push_back(id); - } + if (it != workspaces_.end()) { + it->second->setWorkspace(ws); + continue; + } - std::sort(ids.begin(), ids.end()); + auto button = std::make_unique(ws); - for (int id : ids) { - reorder_child(*workspaces_.at(id), id - 1); - } + pack_start(*button, Gtk::PACK_SHRINK); - show_all(); - } + workspaces_.emplace(ws.id, std::move(button)); + } - Widget* Widget::instance() { - return instance_; + for (auto it = workspaces_.begin(); it != workspaces_.end();) { + if (!seen.contains(it->first)) { + remove(*it->second); + it = workspaces_.erase(it); + } else { + ++it; } + } - WorkspaceButton* Widget::workspaceAt(int x, int y) { - - + std::vector ids; + ids.reserve(workspaces_.size()); - auto children = get_children(); + for (const auto& [id, _] : workspaces_) { + ids.push_back(id); + } - for (size_t i = 0; i < children.size(); ++i) { + std::sort(ids.begin(), ids.end()); - auto* button = dynamic_cast(children[i]); + for (int id : ids) { + reorder_child(*workspaces_.at(id), id - 1); + } - if (!button) { - - continue; - } - - int left, top; - button->translate_coordinates(*this, 0, 0, left, top); + show_all(); +} +Widget* Widget::instance() { return instance_; } - int right; +WorkspaceButton* Widget::workspaceAt(int x, int y) { + auto children = get_children(); - if (i + 1 < children.size()) { + for (size_t i = 0; i < children.size(); ++i) { + auto* button = dynamic_cast(children[i]); - auto* next = - dynamic_cast(children[i + 1]); + if (!button) { + continue; + } - int next_left, next_top; - next->translate_coordinates(*this, 0, 0, next_left, next_top); + int left, top; + button->translate_coordinates(*this, 0, 0, left, top); - right = next_left; + int right; - } else { + if (i + 1 < children.size()) { + auto* next = dynamic_cast(children[i + 1]); - right = get_allocation().get_width(); - } + int next_left, next_top; + next->translate_coordinates(*this, 0, 0, next_left, next_top); + right = next_left; - if (x >= left && - x < right) { + } else { + right = get_allocation().get_width(); + } - return button; - } + if (x >= left && x < right) { + return button; } + } - return nullptr; + return nullptr; } void Widget::beginDrag(const WindowState& window) { - - dragging_ = true; - dragged_window_ = window; - hovered_workspace_ = nullptr; + dragging_ = true; + dragged_window_ = window; + hovered_workspace_ = nullptr; } void Widget::updateDrag(double x, double y) { + static int count = 0; - static int count = 0; + if (!dragging_) { + return; + } - if (!dragging_) { + int wx, wy; + get_window()->get_origin(wx, wy); - return; - } + auto* ws = workspaceAt(x - wx, y - wy); - int wx, wy; - get_window()->get_origin(wx, wy); - - auto* ws = workspaceAt(x - wx, y - wy); - - if (ws != hovered_workspace_) { - - hovered_workspace_ = ws; - - } + if (ws != hovered_workspace_) { + hovered_workspace_ = ws; + } } void Widget::endDrag() { + if (!dragging_) return; - if (!dragging_) - return; - - dragging_ = false; + dragging_ = false; - if (hovered_workspace_) { - - IPC::dispatch( - "movetoworkspacesilent", - std::to_string(hovered_workspace_->id()) + - ",address:" + dragged_window_.address); - } + if (hovered_workspace_) { + IPC::dispatch("movetoworkspacesilent", + std::to_string(hovered_workspace_->id()) + ",address:" + dragged_window_.address); + } - hovered_workspace_ = nullptr; + hovered_workspace_ = nullptr; } -} // namespace waybar::modules::hyprland \ No newline at end of file +} // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/window_icon.cpp b/src/modules/hyprland/workbar/window_icon.cpp index 6ba50ccdc6..c8669dbb45 100644 --- a/src/modules/hyprland/workbar/window_icon.cpp +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -1,165 +1,137 @@ -#include -#include -#include -#include +#include "modules/hyprland/workbar/window_icon.hpp" +#include #include -#include "modules/hyprland/workbar/window_icon.hpp" +#include +#include +#include + +#include "modules/hyprland/backend.hpp" #include "modules/hyprland/workbar/drag_state.hpp" #include "modules/hyprland/workbar/widget.hpp" -#include "modules/hyprland/backend.hpp" using WorkbarWidget = waybar::modules::hyprland::workbar::Widget; namespace waybar::modules::hyprland::workbar { - void WindowIcon::focusWindow() { - if (window_.workspace_visible) { - IPC::dispatch("workspace", - std::to_string(window_.workspace_id)); - } else { - IPC::dispatch("focusworkspaceoncurrentmonitor", - std::to_string(window_.workspace_id)); - } + if (window_.workspace_visible) { + IPC::dispatch("workspace", std::to_string(window_.workspace_id)); + } else { + IPC::dispatch("focusworkspaceoncurrentmonitor", std::to_string(window_.workspace_id)); + } - std::this_thread::sleep_for(std::chrono::milliseconds(40)); - - IPC::dispatch("focuswindow", - "address:" + window_.address); + IPC::dispatch("focuswindow", "address:" + window_.address); } WindowIcon::WindowIcon(const WindowState& window) { + add(image_); - add(image_); - - get_style_context()->add_class("window-icon"); - - add_events( - Gdk::BUTTON_PRESS_MASK | - Gdk::BUTTON_RELEASE_MASK | - Gdk::POINTER_MOTION_MASK - ); + get_style_context()->add_class("window-icon"); - signal_clicked().connect([this]() { - focusWindow(); - }); + add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK); - setWindow(window); + signal_clicked().connect([this]() { focusWindow(); }); - show_all(); + setWindow(window); + show_all(); } void WindowIcon::setWindow(const WindowState& window) { - auto theme = Gtk::IconTheme::get_default(); - - try { - auto pixbuf = theme->load_icon( - theme->has_icon(window.class_name) - ? window.class_name - : "application-x-executable", - 64, // load a large icon - Gtk::ICON_LOOKUP_FORCE_SIZE); - - auto scaled = pixbuf->scale_simple( - 16, 16, - Gdk::INTERP_BILINEAR); - - image_.set(scaled); - - } catch (...) { - } + auto theme = Gtk::IconTheme::get_default(); - window_ = window; + try { + auto pixbuf = theme->load_icon( + theme->has_icon(window.class_name) ? window.class_name : "application-x-executable", + 64, // load a large icon + Gtk::ICON_LOOKUP_FORCE_SIZE); - auto context = get_style_context(); + auto scaled = pixbuf->scale_simple(16, 16, Gdk::INTERP_BILINEAR); - if (window.active) { - context->add_class("active"); - } else { - context->remove_class("active"); - } + image_.set(scaled); - -} + } catch (...) { + } + window_ = window; -bool WindowIcon::on_button_press_event(GdkEventButton* event) { + auto context = get_style_context(); - if (event->button == 1) { - left_pressed_ = true; + if (window.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } +} - press_x_ = event->x; - press_y_ = event->y; - dragging_ = false; - } +bool WindowIcon::on_button_press_event(GdkEventButton* event) { + if (event->button == 1) { + left_pressed_ = true; - return Gtk::Button::on_button_press_event(event); + press_x_ = event->x; + press_y_ = event->y; + dragging_ = false; + } + + return Gtk::Button::on_button_press_event(event); } bool WindowIcon::on_motion_notify_event(GdkEventMotion* event) { - if (!left_pressed_) { - return Gtk::Button::on_motion_notify_event(event); - } - - if (!dragging_) { + if (!left_pressed_) { + return Gtk::Button::on_motion_notify_event(event); + } - double dx = event->x - press_x_; - double dy = event->y - press_y_; + if (!dragging_) { + double dx = event->x - press_x_; + double dy = event->y - press_y_; - if (dx * dx + dy * dy > 36) { - dragging_ = true; + if (dx * dx + dy * dy > 36) { + dragging_ = true; - auto* widget = WorkbarWidget::instance(); + auto* widget = WorkbarWidget::instance(); - if (widget) { - widget->beginDrag(window_); - } - } + if (widget) { + widget->beginDrag(window_); + } } + } - // <-- ADD THIS NEW BLOCK - if (dragging_) { - - auto* widget = WorkbarWidget::instance(); + // <-- ADD THIS NEW BLOCK + if (dragging_) { + auto* widget = WorkbarWidget::instance(); - if (widget) { - widget->updateDrag(event->x_root, event->y_root); - } + if (widget) { + widget->updateDrag(event->x_root, event->y_root); } + } - return Gtk::Button::on_motion_notify_event(event); + return Gtk::Button::on_motion_notify_event(event); } bool WindowIcon::on_button_release_event(GdkEventButton* event) { + if (event->button == 2) { + IPC::dispatch("closewindow", "address:" + window_.address); - if (event->button == 2) { - IPC::dispatch("closewindow", - "address:" + window_.address); - - return true; - } - - left_pressed_ = false; - - if (dragging_) { - - dragging_ = false; - - auto* widget = WorkbarWidget::instance(); - if (widget) { - widget->endDrag(); - } + return true; + } - } else if (event->button == 1) { + left_pressed_ = false; - focusWindow(); + if (dragging_) { + dragging_ = false; + auto* widget = WorkbarWidget::instance(); + if (widget) { + widget->endDrag(); } - return true; + } else if (event->button == 1) { + focusWindow(); + } + + return true; } } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/workspace_button.cpp b/src/modules/hyprland/workbar/workspace_button.cpp index 7e21e0d1aa..cd7cc79eb5 100644 --- a/src/modules/hyprland/workbar/workspace_button.cpp +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -5,81 +5,75 @@ namespace waybar::modules::hyprland::workbar { -int WorkspaceButton::id() const { - return number_.workspaceId(); -} +int WorkspaceButton::id() const { return number_.workspaceId(); } WorkspaceButton::WorkspaceButton(const WorkspaceState& workspace) - : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL), - number_(workspace.id), - box_(Gtk::ORIENTATION_HORIZONTAL), - icons_(Gtk::ORIENTATION_HORIZONTAL) { - - get_style_context()->add_class("workspace"); - - box_.get_style_context()->add_class("workspace-content"); + : Gtk::Box(Gtk::ORIENTATION_HORIZONTAL), + number_(workspace.id), + box_(Gtk::ORIENTATION_HORIZONTAL), + icons_(Gtk::ORIENTATION_HORIZONTAL) { + get_style_context()->add_class("workspace"); - icons_.get_style_context()->add_class("workspace-icons"); - number_.get_style_context()->add_class("workspace-number"); + box_.get_style_context()->add_class("workspace-content"); - box_.pack_start(number_, Gtk::PACK_SHRINK); - box_.pack_start(icons_, Gtk::PACK_SHRINK); + icons_.get_style_context()->add_class("workspace-icons"); + number_.get_style_context()->add_class("workspace-number"); - pack_start(box_, Gtk::PACK_EXPAND_WIDGET); + box_.pack_start(number_, Gtk::PACK_SHRINK); + box_.pack_start(icons_, Gtk::PACK_SHRINK); - setWorkspace(workspace); + pack_start(box_, Gtk::PACK_EXPAND_WIDGET); - show_all(); + setWorkspace(workspace); + show_all(); } void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { + auto context = number_.style(); - auto context = number_.style(); + std::unordered_set seen; - std::unordered_set seen; - - if (workspace.active) { - context->add_class("active"); - } else { - context->remove_class("active"); - } + if (workspace.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } - if (workspace.visible) { - context->add_class("visible"); - } else { - context->remove_class("visible"); - } + if (workspace.visible) { + context->add_class("visible"); + } else { + context->remove_class("visible"); + } - for (const auto& window : workspace.windows) { - seen.insert(window.address); + for (const auto& window : workspace.windows) { + seen.insert(window.address); - auto it = window_icons_.find(window.address); + auto it = window_icons_.find(window.address); - if (it != window_icons_.end()) { - it->second->setWindow(window); - continue; - } + if (it != window_icons_.end()) { + it->second->setWindow(window); + continue; + } - auto icon = std::make_unique(window); + auto icon = std::make_unique(window); - icons_.pack_start(*icon, Gtk::PACK_SHRINK); - icon->show(); + icons_.pack_start(*icon, Gtk::PACK_SHRINK); + icon->show(); - window_icons_.emplace(window.address, std::move(icon)); - } + window_icons_.emplace(window.address, std::move(icon)); + } - for (auto it = window_icons_.begin(); it != window_icons_.end();) { - if (!seen.contains(it->first)) { - icons_.remove(*it->second); - it = window_icons_.erase(it); - } else { - ++it; - } + for (auto it = window_icons_.begin(); it != window_icons_.end();) { + if (!seen.contains(it->first)) { + icons_.remove(*it->second); + it = window_icons_.erase(it); + } else { + ++it; } + } - show(); + show(); } - } // namespace waybar::modules::hyprland::workbar \ No newline at end of file diff --git a/src/modules/hyprland/workbar/workspace_number.cpp b/src/modules/hyprland/workbar/workspace_number.cpp index a25bbc16b8..560e377516 100644 --- a/src/modules/hyprland/workbar/workspace_number.cpp +++ b/src/modules/hyprland/workbar/workspace_number.cpp @@ -1,76 +1,62 @@ +#include "modules/hyprland/workbar/workspace_number.hpp" + #include #include -#include "modules/hyprland/workbar/workspace_number.hpp" -#include "modules/hyprland/workbar/drag_state.hpp" #include "modules/hyprland/backend.hpp" +#include "modules/hyprland/workbar/drag_state.hpp" namespace waybar::modules::hyprland::workbar { -int WorkspaceNumber::workspaceId() const { - return workspace_id_; -} +int WorkspaceNumber::workspaceId() const { return workspace_id_; } WorkspaceNumber::WorkspaceNumber(int workspace_id) { - add(label_); - - get_style_context()->add_class("workspace-number"); - - add_events( - Gdk::ENTER_NOTIFY_MASK | - Gdk::LEAVE_NOTIFY_MASK - ); - - setWorkspace(workspace_id); - show_all(); - - drag_dest_set({ Gtk::TargetEntry("WORKBAR_WINDOW") }, Gtk::DEST_DEFAULT_ALL, Gdk::DragAction::ACTION_MOVE); - - signal_drag_data_received().connect( - [this](const Glib::RefPtr&, - int, - int, - const Gtk::SelectionData&, - guint, - guint) { - }); - - signal_clicked().connect([this]() { - - auto monitors = IPC::inst().getSocket1JsonReply("monitors"); - - bool visible = false; - - for (const auto& monitor : monitors) { - if (monitor["activeWorkspace"]["id"].asInt() == workspace_id_) { - visible = true; - break; - } - } - - if (visible) { - IPC::dispatch("workspace", - std::to_string(workspace_id_)); - } else { - IPC::dispatch("focusworkspaceoncurrentmonitor", - std::to_string(workspace_id_)); - } - }); + add(label_); + + get_style_context()->add_class("workspace-number"); + + add_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + + setWorkspace(workspace_id); + show_all(); + + drag_dest_set({Gtk::TargetEntry("WORKBAR_WINDOW")}, Gtk::DEST_DEFAULT_ALL, + Gdk::DragAction::ACTION_MOVE); + + signal_drag_data_received().connect([this](const Glib::RefPtr&, int, int, + const Gtk::SelectionData&, guint, guint) {}); + + signal_clicked().connect([this]() { + auto monitors = IPC::inst().getSocket1JsonReply("monitors"); + + bool visible = false; + + for (const auto& monitor : monitors) { + if (monitor["activeWorkspace"]["id"].asInt() == workspace_id_) { + visible = true; + break; + } + } + + if (visible) { + IPC::dispatch("workspace", std::to_string(workspace_id_)); + } else { + IPC::dispatch("focusworkspaceoncurrentmonitor", std::to_string(workspace_id_)); + } + }); } void WorkspaceNumber::setWorkspace(int workspace_id) { - workspace_id_ = workspace_id; - label_.set_text(std::to_string(workspace_id)); + workspace_id_ = workspace_id; + label_.set_text(std::to_string(workspace_id)); } bool WorkspaceNumber::on_enter_notify_event(GdkEventCrossing* event) { - - return Gtk::Button::on_enter_notify_event(event); + return Gtk::Button::on_enter_notify_event(event); } bool WorkspaceNumber::on_leave_notify_event(GdkEventCrossing* event) { - - return Gtk::Button::on_leave_notify_event(event); + return Gtk::Button::on_leave_notify_event(event); } } // namespace waybar::modules::hyprland::workbar \ No newline at end of file