diff --git a/include/modules/hyprland/workbar/backend.hpp b/include/modules/hyprland/workbar/backend.hpp new file mode 100644 index 000000000..d52759796 --- /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/drag_state.hpp b/include/modules/hyprland/workbar/drag_state.hpp new file mode 100644 index 000000000..6224c79b7 --- /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; + +} // 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 new file mode 100644 index 000000000..b88b75264 --- /dev/null +++ b/include/modules/hyprland/workbar/model.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +namespace waybar::modules::hyprland::workbar { + +struct WindowState { + std::string address; + std::string class_name; + std::string title; + + int workspace_id; + + bool active = false; + bool workspace_visible = false; +}; + +struct WorkspaceState { + int id; + + bool active = false; + bool visible = false; + + std::string monitor; + + std::vector windows; +}; + +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 000000000..db1add39c --- /dev/null +++ b/include/modules/hyprland/workbar/module.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "AModule.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); + + void update() override; + + 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 new file mode 100644 index 000000000..fff846048 --- /dev/null +++ b/include/modules/hyprland/workbar/widget.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include +#include +#include + +#include "modules/hyprland/workbar/model.hpp" +#include "modules/hyprland/workbar/workspace_button.hpp" + +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::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 new file mode 100644 index 000000000..2bb7dbfae --- /dev/null +++ b/include/modules/hyprland/workbar/window_icon.hpp @@ -0,0 +1,32 @@ +#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); + + 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; +}; + +} // 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 new file mode 100644 index 000000000..252bb0473 --- /dev/null +++ b/include/modules/hyprland/workbar/workspace_button.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +#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::Box { + public: + WorkspaceButton(const WorkspaceState& workspace); + int id() const; + + void setWorkspace(const WorkspaceState& workspace); + + private: + Gtk::Box box_; + Gtk::Box icons_; + + WorkspaceNumber number_; + + std::unordered_map> window_icons_; +}; + +} // 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 new file mode 100644 index 000000000..58eab6ace --- /dev/null +++ b/include/modules/hyprland/workbar/workspace_number.hpp @@ -0,0 +1,27 @@ +#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); + Glib::RefPtr style() { return get_style_context(); } + + 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/man/waybar-hyprland-workbar.5.scd b/man/waybar-hyprland-workbar.5.scd new file mode 100644 index 000000000..8142c15ab --- /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 0c494eb22..0b4c38ac3 100644 --- a/meson.build +++ b/meson.build @@ -323,6 +323,14 @@ if true 'src/modules/hyprland/windowcount.cpp', 'src/modules/hyprland/workspace.cpp', 'src/modules/hyprland/workspaces.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/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( @@ -330,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/client.cpp b/src/client.cpp index d14891867..1288b90b0 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/factory.cpp b/src/factory.cpp index 2fd3e3b81..655bea985 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -35,6 +35,7 @@ #include "modules/hyprland/submap.hpp" #include "modules/hyprland/window.hpp" #include "modules/hyprland/windowcount.hpp" +#include "modules/hyprland/workbar/module.hpp" #include "modules/hyprland/workspaces.hpp" #endif #ifdef HAVE_NIRI @@ -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::Module(id, config_[name]); + } #endif #ifdef HAVE_NIRI if (ref == "niri/language") { diff --git a/src/modules/hyprland/workbar/backend.cpp b/src/modules/hyprland/workbar/backend.cpp new file mode 100644 index 000000000..d9317b71f --- /dev/null +++ b/src/modules/hyprland/workbar/backend.cpp @@ -0,0 +1,77 @@ +#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); + + 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"); + // 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; + + auto monitors = ipc_.getSocket1JsonReply("monitors"); + + std::unordered_set active_workspaces; + std::unordered_set visible_workspaces; + + for (const auto& monitor : monitors) { + int ws = monitor["activeWorkspace"]["id"].asInt(); + + visible_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& 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)); + } + + 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/drag_state.cpp b/src/modules/hyprland/workbar/drag_state.cpp new file mode 100644 index 000000000..50c103949 --- /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/model.cpp b/src/modules/hyprland/workbar/model.cpp new file mode 100644 index 000000000..f6e925fe9 --- /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/module.cpp b/src/modules/hyprland/workbar/module.cpp new file mode 100644 index 000000000..8467e54a5 --- /dev/null +++ b/src/modules/hyprland/workbar/module.cpp @@ -0,0 +1,27 @@ +#include "modules/hyprland/workbar/module.hpp" + +namespace waybar::modules::hyprland::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); + + if (!id.empty()) { + widget_.get_style_context()->add_class(id); + } + + event_box_.add(widget_); + + backend_.setUpdateCallback([this]() { dp.emit(); }); + + dp.emit(); +} + +void Module::update() { + widget_.setWorkspaces(backend_.getWorkspaces()); + + 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 new file mode 100644 index 000000000..06e92342a --- /dev/null +++ b/src/modules/hyprland/workbar/widget.cpp @@ -0,0 +1,146 @@ +#include "modules/hyprland/workbar/widget.hpp" + +#include +#include +#include +#include + +#include "modules/hyprland/backend.hpp" +#include "modules/hyprland/workbar/workspace_button.hpp" + +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; + + 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_.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(); +} + +Widget* Widget::instance() { return instance_; } + +WorkspaceButton* Widget::workspaceAt(int x, int y) { + auto children = get_children(); + + for (size_t i = 0; i < children.size(); ++i) { + auto* button = dynamic_cast(children[i]); + + if (!button) { + continue; + } + + 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(); + } + + if (x >= left && x < right) { + return button; + } + } + + return nullptr; +} + +void Widget::beginDrag(const WindowState& window) { + dragging_ = true; + dragged_window_ = window; + hovered_workspace_ = nullptr; +} + +void Widget::updateDrag(double x, double y) { + static int count = 0; + + if (!dragging_) { + return; + } + + int wx, wy; + get_window()->get_origin(wx, wy); + + auto* ws = workspaceAt(x - wx, y - wy); + + if (ws != hovered_workspace_) { + hovered_workspace_ = ws; + } +} + +void Widget::endDrag() { + if (!dragging_) return; + + dragging_ = false; + + if (hovered_workspace_) { + IPC::dispatch("movetoworkspacesilent", + std::to_string(hovered_workspace_->id()) + ",address:" + dragged_window_.address); + } + + hovered_workspace_ = nullptr; +} + +} // 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 new file mode 100644 index 000000000..c8669dbb4 --- /dev/null +++ b/src/modules/hyprland/workbar/window_icon.cpp @@ -0,0 +1,137 @@ +#include "modules/hyprland/workbar/window_icon.hpp" + +#include +#include + +#include +#include +#include + +#include "modules/hyprland/backend.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 { + +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)); + } + + IPC::dispatch("focuswindow", "address:" + window_.address); +} + +WindowIcon::WindowIcon(const WindowState& window) { + add(image_); + + get_style_context()->add_class("window-icon"); + + add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK); + + signal_clicked().connect([this]() { focusWindow(); }); + + 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 (...) { + } + + window_ = window; + + auto context = get_style_context(); + + if (window.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } +} + +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) { + 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(); + } + + } 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 new file mode 100644 index 000000000..cd7cc79eb --- /dev/null +++ b/src/modules/hyprland/workbar/workspace_button.cpp @@ -0,0 +1,79 @@ + +#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) + : 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"); + + 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); + + pack_start(box_, Gtk::PACK_EXPAND_WIDGET); + + setWorkspace(workspace); + + show_all(); +} + +void WorkspaceButton::setWorkspace(const WorkspaceState& workspace) { + auto context = number_.style(); + + std::unordered_set seen; + + if (workspace.active) { + context->add_class("active"); + } else { + context->remove_class("active"); + } + + if (workspace.visible) { + context->add_class("visible"); + } else { + context->remove_class("visible"); + } + + 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); + icon->show(); + + 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(); +} + +} // 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 new file mode 100644 index 000000000..560e37751 --- /dev/null +++ b/src/modules/hyprland/workbar/workspace_number.cpp @@ -0,0 +1,62 @@ +#include "modules/hyprland/workbar/workspace_number.hpp" + +#include +#include + +#include "modules/hyprland/backend.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_); + + 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)); +} + +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