From 94a4d41a65c98b6c95e2f520a57911321ae256ec Mon Sep 17 00:00:00 2001 From: Jan Beich Date: Tue, 26 May 2020 07:29:54 +0000 Subject: [PATCH 01/61] disk: make used calculation match df(1) output Substract space only available to superuser as well. --- src/modules/disk.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/disk.cpp b/src/modules/disk.cpp index 59ffea6..658fcd9 100644 --- a/src/modules/disk.cpp +++ b/src/modules/disk.cpp @@ -45,7 +45,7 @@ auto waybar::modules::Disk::update() -> void { } auto free = pow_format(stats.f_bavail * stats.f_frsize, "B", true); - auto used = pow_format((stats.f_blocks - stats.f_bavail) * stats.f_frsize, "B", true); + auto used = pow_format((stats.f_blocks - stats.f_bfree) * stats.f_frsize, "B", true); auto total = pow_format(stats.f_blocks * stats.f_frsize, "B", true); label_.set_markup(fmt::format(format_ @@ -53,7 +53,7 @@ auto waybar::modules::Disk::update() -> void { , fmt::arg("free", free) , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) , fmt::arg("used", used) - , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bfree) * 100 / stats.f_blocks) , fmt::arg("total", total) , fmt::arg("path", path_) )); @@ -67,7 +67,7 @@ auto waybar::modules::Disk::update() -> void { , fmt::arg("free", free) , fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks) , fmt::arg("used", used) - , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bavail) * 100 / stats.f_blocks) + , fmt::arg("percentage_used", (stats.f_blocks - stats.f_bfree) * 100 / stats.f_blocks) , fmt::arg("total", total) , fmt::arg("path", path_) )); From 2b11b7ef8c9b66e9f00ec573fa3de3f14e724e0d Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 5 Aug 2020 02:17:38 +0300 Subject: [PATCH 02/61] Base wlr impl (Manager, Group) --- include/factory.hpp | 1 + include/modules/wlr/workspaces.hpp | 82 ++++++++ meson.build | 1 + protocol/meson.build | 1 + protocol/wlr-workspace-unstable-v1.xml | 270 +++++++++++++++++++++++++ src/factory.cpp | 3 + src/modules/wlr/workspaces.cpp | 152 ++++++++++++++ 7 files changed, 510 insertions(+) create mode 100644 include/modules/wlr/workspaces.hpp create mode 100644 protocol/wlr-workspace-unstable-v1.xml create mode 100644 src/modules/wlr/workspaces.cpp diff --git a/include/factory.hpp b/include/factory.hpp index fcbf3a2..db6fd87 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -9,6 +9,7 @@ #endif #ifdef HAVE_WLR #include "modules/wlr/taskbar.hpp" +#include "modules/wlr/workspaces.hpp" #endif #ifdef HAVE_RIVER #include "modules/river/tags.hpp" diff --git a/include/modules/wlr/workspaces.hpp b/include/modules/wlr/workspaces.hpp new file mode 100644 index 0000000..351ddc4 --- /dev/null +++ b/include/modules/wlr/workspaces.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include + +#include +#include + +#include "AModule.hpp" +#include "bar.hpp" +#include "wlr-workspace-unstable-v1-client-protocol.h" + +namespace waybar::modules::wlr { + +class WorkspaceManager; +class WorkspaceGroup; + +class Workspace { + public: + Workspace(const waybar::Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, + zwlr_workspace_handle_v1 &workspace); + ~Workspace() = default; + auto update() -> void; + + enum class State { ACTIVE = 1 << 1 }; + + private: + const Bar & bar_; + const Gtk::Box box_; + const Gtk::Image icon_; + const Json::Value & config_; + const WorkspaceGroup &workspace_group_; + + // wlr stuff + zwlr_workspace_handle_v1 &workspace_handle_; + uint32_t state_; +}; + +class WorkspaceGroup { + public: + WorkspaceGroup(const waybar::Bar &bar, const Json::Value &config, WorkspaceManager &manager, + zwlr_workspace_group_handle_v1 &workspace_group_handle); + auto update() -> void; + + // wlr stuff + auto handle_workspace_create(zwlr_workspace_handle_v1 &workspace_handle) -> void; + auto handle_remove() -> void; + auto handle_output_enter(wl_output &output) -> void; + auto handle_output_leave(wl_output &output) -> void; + + private: + const waybar::Bar & bar_; + const Json::Value & config_; + const WorkspaceManager & workspace_manager_; + std::vector> workspaces_; + + // wlr stuff + zwlr_workspace_group_handle_v1 &workspace_group_handle_; +}; + +class WorkspaceManager : public AModule { + public: + WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config); + auto update() -> void override; + + // wlr stuff + auto register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void; + auto handle_workspace_group_create(zwlr_workspace_group_handle_v1 *workspace_group_handle) + -> void; + auto handle_done() -> void; + auto handle_finished() -> void; + + private: + const waybar::Bar & bar_; + Gtk::Box box_; + std::vector> groups_; + + // wlr stuff + zwlr_workspace_manager_v1 *workspace_manager_ = nullptr; +}; + +} // namespace waybar::modules::wlr diff --git a/meson.build b/meson.build index dd56c29..d0ba1e8 100644 --- a/meson.build +++ b/meson.build @@ -166,6 +166,7 @@ src_files += [ if true add_project_arguments('-DHAVE_WLR', language: 'cpp') src_files += 'src/modules/wlr/taskbar.cpp' + src_files += 'src/modules/wlr/workspaces.cpp' endif if true diff --git a/protocol/meson.build b/protocol/meson.build index 07d524a..467260b 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -27,6 +27,7 @@ client_protocols = [ [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], + ['wlr-workspace-unstable-v1.xml'], ['river-status-unstable-v1.xml'], ] diff --git a/protocol/wlr-workspace-unstable-v1.xml b/protocol/wlr-workspace-unstable-v1.xml new file mode 100644 index 0000000..ae0e44d --- /dev/null +++ b/protocol/wlr-workspace-unstable-v1.xml @@ -0,0 +1,270 @@ + + + + Copyright © 2019 Christopher Billington + Copyright © 2020 Ilia Bozhinov + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + Workspaces, also called virtual desktops, are groups of surfaces. A + compositor with a concept of workspaces may only show some such groups of + surfaces (those of 'active' workspaces) at a time. 'Activating' a + workspace is a request for the compositor to display that workspace's + surfaces as normal, whereas the compositor may hide or otherwise + de-emphasise surfaces that are associated only with 'inactive' workspaces. + Workspaces are grouped by which sets of outputs they correspond to, and + may contain surfaces only from those outputs. In this way, it is possible + for each output to have its own set of workspaces, or for all outputs (or + any other arbitrary grouping) to share workspaces. Compositors may + optionally conceptually arrange each group of workspaces in an + N-dimensional grid. + + The purpose of this protocol is to enable the creation of taskbars and + docks by providing them with a list of workspaces and their properties, + and allowing them to activate and deactivate workspaces. + + After a client binds the zwlr_workspace_manager_v1, each workspace will be + sent via the workspace event. + + + + + This event is emitted whenever a new workspace group has been created. + + All initial details of the workspace group (workspaces, outputs) will be + sent immediately after this event via the corresponding events in + zwlr_workspace_group_handle_v1. + + + + + + + The client must send this request after it has finished sending other + requests. The compositor must process a series of requests preceding a + commit request atomically. + + This allows changes to the workspace properties to be seen as atomic, + even if they happen via multiple events, and even if they involve + multiple zwlr_workspace_handle_v1 objects, for example, deactivating one + workspace and activating another. + + + + + + This event is sent after all changes in all workspace groups have been + sent. + + This allows changes to one or more zwlr_workspace_group_handle_v1 + properties to be seen as atomic, even if they happen via multiple + events. In particular, an output moving from one workspace group to + another sends an output_enter event and an output_leave event to the two + zwlr_workspace_group_handle_v1 objects in question. The compositor sends + the done event only after updating the output information in both + workspace groups. + + + + + + This event indicates that the compositor is done sending events to the + zwlr_workspace_manager_v1. The server will destroy the object + immediately after sending this request, so it will become invalid and + the client should free any resources associated with it. + + + + + + Indicates the client no longer wishes to receive events for new + workspace groups. However the compositor may emit further workspace + events, until the finished event is emitted. + + The client must not send any more requests after this one. + + + + + + + A zwlr_workspace_group_handle_v1 object represents a a workspace group + that is assigned a set of outputs and contains a number of workspaces. + + The set of outputs assigned to the workspace group is conveyed to the client via + output_enter and output_leave events, and its workspaces are conveyed with + workspace events. + + + + + This event is emitted whenever an output is assigned to the workspace + group. + + + + + + + This event is emitted whenever an output is removed from the workspace + group. + + + + + + + This event is emitted whenever a new workspace has been created. + + All initial details of the workspace (name, coordinates, state) will + be sent immediately after this event via the corresponding events in + zwlr_workspace_handle_v1. + + + + + + + This event means the zwlr_workspace_group_handle_v1 has been destroyed. + It is guaranteed there won't be any more events for this + zwlr_workspace_group_handle_v1. The zwlr_workspace_group_handle_v1 becomes + inert so any requests will be ignored except the destroy request. + + The compositor must remove all workspaces belonging to a workspace group + before removing the workspace group. + + + + + + Destroys the zwlr_workspace_handle_v1 object. + + This request should be called either when the client does not want to + use the workspace object any more or after the remove event to finalize + the destruction of the object. + + + + + + + A zwlr_workspace_handle_v1 object represents a a workspace that handles a + group of surfaces. + + Each workspace has a name, conveyed to the client with the name event; a + list of states, conveyed to the client with the state event; and + optionally a set of coordinates, conveyed to the client with the + coordinates event. The client may request that the compositor activate or + deactivate the workspace. + + + + + This event is emitted immediately after the zwlr_workspace_handle_v1 is + created and whenever the name of the workspace changes. + + + + + + + This event is used to organize workspaces into an N-dimensional grid + within a workspace group, and if supported, is emitted immediately after + the zwlr_workspace_handle_v1 is created and whenever the coordinates of + the workspace change. Compositors may not send this event if they do not + conceptually arrange workspaces in this way. If compositors simply + number workspaces, without any geometric interpretation, they may send + 1D coordinates, which clients should not interpret as implying any + geometry. Sending an empty array means that the compositor no longer + orders the workspace geometrically. + + Coordinates have an arbitrary number of dimensions N with an uint32 + position along each dimension. By convention if N > 1, the first + dimension is X, the second Y, the third Z, and so on. The compositor may + chose to utilize these events for a more novel workspace layout + convention, however. No guarantee is made about the grid being filled or + bounded; there may be a workspace at coordinate 1 and another at + coordinate 1000 and none in between. Within a workspace group, however, + workspaces must have unique coordinates of equal dimensionality. + + + + + + + This event is emitted immediately after the zwlr_workspace_handle_v1 is + created and each time the workspace state changes, either because of a + compositor action or because of a request in this protocol. + + + + + + + The different states that a workspace can have. + + + + + + + + This event means the zwlr_workspace_handle_v1 has been destroyed. It is + guaranteed there won't be any more events for this + zwlr_workspace_handle_v1. The zwlr_workspace_handle_v1 becomes inert so + any requests will be ignored except the destroy request. + + + + + + Destroys the zwlr_workspace_handle_v1 object. + + This request should be called either when the client does not want to + use the workspace object any more or after the remove event to finalize + the destruction of the object. + + + + + + Request that this workspace be activated. + + There is no guarantee the workspace will be actually activated, and + behaviour may be compositor-dependent. For example, activating a + workspace may or may not deactivate all other workspaces in the same + group. + + + + + + Request that this workspace be deactivated. + + There is no guarantee the workspace will be actually deactivated. + + + + diff --git a/src/factory.cpp b/src/factory.cpp index 5a01d52..804378e 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -27,6 +27,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "wlr/taskbar") { return new waybar::modules::wlr::Taskbar(id, bar_, config_[name]); } + if (ref == "wlr/workspaces") { + return new waybar::modules::wlr::WorkspaceManager(id, bar_, config_[name]); + } #endif #ifdef HAVE_RIVER if (ref == "river/tags") { diff --git a/src/modules/wlr/workspaces.cpp b/src/modules/wlr/workspaces.cpp new file mode 100644 index 0000000..0d9ae0b --- /dev/null +++ b/src/modules/wlr/workspaces.cpp @@ -0,0 +1,152 @@ +#include "modules/wlr/workspaces.hpp" + +#include +#include + +#include + +namespace waybar::modules::wlr { + +static void handle_global(void *data, wl_registry *registry, uint32_t name, + const char *interface, uint32_t version) { + if (std::strcmp(interface, zwlr_workspace_manager_v1_interface.name) == 0) { + static_cast(data)->register_manager(registry, name, version); + } +} + +static void handle_global_remove(void *data, wl_registry *registry, uint32_t name) { + /* Nothing to do here */ +} + +static const wl_registry_listener registry_listener_impl = {.global = handle_global, + .global_remove = handle_global_remove}; + +WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar, + const Json::Value &config) + : waybar::AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()), + bar_(bar), + box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { + box_.set_name("workspaces"); + if (!id.empty()) { + box_.get_style_context()->add_class(id); + } + event_box_.add(box_); + + // wlr stuff + wl_display * display = Client::inst()->wl_display; + wl_registry *registry = wl_display_get_registry(display); + + wl_registry_add_listener(registry, ®istry_listener_impl, this); + wl_display_roundtrip(display); + + if (!workspace_manager_) { + return; + } +} + +static void workspace_manager_handle_workspace_group( + void *data, zwlr_workspace_manager_v1 *_, + zwlr_workspace_group_handle_v1 *workspace_group) { + static_cast(data)->handle_workspace_group_create(workspace_group); +} + +static void workspace_manager_handle_done(void *data, zwlr_workspace_manager_v1 *_) { + static_cast(data)->handle_done(); +} + +static void workspace_manager_handle_finished(void *data, zwlr_workspace_manager_v1 *_) { + static_cast(data)->handle_finished(); +} + +static const zwlr_workspace_manager_v1_listener workspace_manager_impl = { + .workspace_group = workspace_manager_handle_workspace_group, + .done = workspace_manager_handle_done, + .finished = workspace_manager_handle_finished, +}; + +auto WorkspaceManager::register_manager(wl_registry *registry, uint32_t name, uint32_t version) + -> void { + if (workspace_manager_) { + spdlog::warn("Register workspace manager again although already registered!"); + return; + } + if (version != 1) { + spdlog::warn("Using different workspace manager protocol version: {}", version); + } + + workspace_manager_ = static_cast( + wl_registry_bind(registry, name, &zwlr_workspace_manager_v1_interface, version)); + + if (workspace_manager_) + zwlr_workspace_manager_v1_add_listener(workspace_manager_, &workspace_manager_impl, this); + else + spdlog::debug("Failed to register manager"); +} +auto WorkspaceManager::handle_workspace_group_create( + zwlr_workspace_group_handle_v1 *workspace_group_handle) -> void { + groups_.push_back(std::make_unique(bar_, config_, *this, *workspace_group_handle)); +} + +auto WorkspaceManager::handle_finished() -> void { + zwlr_workspace_manager_v1_destroy(workspace_manager_); + workspace_manager_ = nullptr; +} +auto WorkspaceManager::handle_done() -> void {} +auto WorkspaceManager::update() -> void { + for (auto &group : groups_) { + group->update(); + } + AModule::update(); +} + +static void workspace_group_handle_output_enter(void *data, + zwlr_workspace_group_handle_v1 *_, + wl_output *output) { + static_cast(data)->handle_output_enter(*output); +} + +static void workspace_group_handle_output_leave(void *data, + zwlr_workspace_group_handle_v1 *_, + wl_output *output) { + static_cast(data)->handle_output_leave(*output); +} + +static void workspace_group_handle_workspace(void *data, + zwlr_workspace_group_handle_v1 *_, + zwlr_workspace_handle_v1 *workspace) { + static_cast(data)->handle_workspace_create(*workspace); +} + +static void workspace_group_handle_remove(void *data, + zwlr_workspace_group_handle_v1 *_) { + static_cast(data)->handle_remove(); +} + +static const zwlr_workspace_group_handle_v1_listener workspace_group_impl = { + .output_enter = workspace_group_handle_output_enter, + .output_leave = workspace_group_handle_output_leave, + .workspace = workspace_group_handle_workspace, + .remove = workspace_group_handle_remove +}; + +WorkspaceGroup::WorkspaceGroup(const Bar & bar, const Json::Value &config, WorkspaceManager &manager, + zwlr_workspace_group_handle_v1 &workspace_group_handle) + : bar_(bar), config_(config), workspace_manager_(manager), workspace_group_handle_(workspace_group_handle) +{ + zwlr_workspace_group_handle_v1_add_listener(&workspace_group_handle, &workspace_group_impl, this); +} +auto WorkspaceGroup::handle_workspace_create(zwlr_workspace_handle_v1 &workspace) -> void { + workspaces_.push_back(std::make_unique(bar_, config_, *this, workspace)); +} +auto WorkspaceGroup::handle_remove() -> void {} +auto WorkspaceGroup::handle_output_enter(wl_output &output) -> void {} +auto WorkspaceGroup::handle_output_leave(wl_output &output) -> void {} +auto WorkspaceGroup::update() -> void { + +} +Workspace::Workspace(const Bar &bar, const Json::Value &config, + WorkspaceGroup &workspace_group, zwlr_workspace_handle_v1 &workspace) + : bar_(bar), config_(config), workspace_group_(workspace_group), workspace_handle_(workspace) +{ +} +} // namespace waybar::modules::wlr \ No newline at end of file From edd4d8ee119f1ebeb51ecbac814784e8980e08ca Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 5 Aug 2020 23:10:08 +0300 Subject: [PATCH 03/61] Finish implement wlr --- include/factory.hpp | 2 +- include/modules/wlr/workspace_manager.hpp | 109 +++++++++++ .../modules/wlr/workspace_manager_binding.hpp | 8 + include/modules/wlr/workspaces.hpp | 82 -------- meson.build | 3 +- src/modules/wlr/workspace_manager.cpp | 182 ++++++++++++++++++ src/modules/wlr/workspace_manager_binding.cpp | 134 +++++++++++++ src/modules/wlr/workspaces.cpp | 152 --------------- 8 files changed, 436 insertions(+), 236 deletions(-) create mode 100644 include/modules/wlr/workspace_manager.hpp create mode 100644 include/modules/wlr/workspace_manager_binding.hpp delete mode 100644 include/modules/wlr/workspaces.hpp create mode 100644 src/modules/wlr/workspace_manager.cpp create mode 100644 src/modules/wlr/workspace_manager_binding.cpp delete mode 100644 src/modules/wlr/workspaces.cpp diff --git a/include/factory.hpp b/include/factory.hpp index db6fd87..a34e361 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -9,7 +9,7 @@ #endif #ifdef HAVE_WLR #include "modules/wlr/taskbar.hpp" -#include "modules/wlr/workspaces.hpp" +#include "modules/wlr/workspace_manager.hpp" #endif #ifdef HAVE_RIVER #include "modules/river/tags.hpp" diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp new file mode 100644 index 0000000..3c8fe99 --- /dev/null +++ b/include/modules/wlr/workspace_manager.hpp @@ -0,0 +1,109 @@ +#pragma once + +#include +#include + +#include +#include + +#include "AModule.hpp" +#include "bar.hpp" +#include "wlr-workspace-unstable-v1-client-protocol.h" + +namespace waybar::modules::wlr { + +class WorkspaceManager; +class WorkspaceGroup; + +class Workspace { + public: + Workspace(const waybar::Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, + zwlr_workspace_handle_v1 *workspace); + ~Workspace(); + auto update() -> void; + + auto id() const -> uint32_t { return id_; } + auto handle_name(const std::string &name) -> void { name_ = name; } + auto handle_coordinates(const std::vector &coordinates) -> void { + coordinates_ = coordinates; + } + auto handle_state(const std::vector &state) -> void; + auto handle_remove() -> void; + + enum class State { ACTIVE = 1 << 0 }; + + private: + static uint32_t workspace_global_id; + const Bar & bar_; + const Json::Value &config_; + WorkspaceGroup & workspace_group_; + + // wlr stuff + zwlr_workspace_handle_v1 *workspace_handle_; + uint32_t state_ = 0; + + uint32_t id_; + std::string name_; + std::vector coordinates_; + + const Gtk::Box box_; + const Gtk::Image icon_; +}; + +class WorkspaceGroup { + public: + WorkspaceGroup(const waybar::Bar &bar, const Json::Value &config, WorkspaceManager &manager, + zwlr_workspace_group_handle_v1 *workspace_group_handle); + ~WorkspaceGroup(); + auto update() -> void; + + auto id() const -> uint32_t { return id_; } + auto remove_workspace(uint32_t id_) -> void; + + // wlr stuff + auto handle_workspace_create(zwlr_workspace_handle_v1 *workspace_handle) -> void; + + auto handle_remove() -> void; + auto handle_output_enter(wl_output *output) -> void; + auto handle_output_leave() -> void; + + private: + static uint32_t group_global_id; + const waybar::Bar &bar_; + const Json::Value &config_; + WorkspaceManager & workspace_manager_; + + // wlr stuff + zwlr_workspace_group_handle_v1 *workspace_group_handle_; + wl_output * output_ = nullptr; + + uint32_t id_; + std::vector> workspaces_; +}; + +class WorkspaceManager : public AModule { + public: + WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config); + ~WorkspaceManager() override; + auto update() -> void override; + + auto remove_workspace_group(uint32_t id_) -> void; + + // wlr stuff + auto register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void; + auto handle_workspace_group_create(zwlr_workspace_group_handle_v1 *workspace_group_handle) + -> void; + + auto handle_done() -> void; + auto handle_finished() -> void; + + private: + const waybar::Bar & bar_; + Gtk::Box box_; + std::vector> groups_; + + // wlr stuff + zwlr_workspace_manager_v1 *workspace_manager_ = nullptr; +}; + +} // namespace waybar::modules::wlr diff --git a/include/modules/wlr/workspace_manager_binding.hpp b/include/modules/wlr/workspace_manager_binding.hpp new file mode 100644 index 0000000..1cef652 --- /dev/null +++ b/include/modules/wlr/workspace_manager_binding.hpp @@ -0,0 +1,8 @@ +#include "wlr-workspace-unstable-v1-client-protocol.h" + +namespace waybar::modules::wlr { + void add_registry_listener(void *data); + void add_workspace_listener(zwlr_workspace_handle_v1 *workspace_handle, void *data); + void add_workspace_group_listener(zwlr_workspace_group_handle_v1 *workspace_group_handle, void *data); + zwlr_workspace_manager_v1* workspace_manager_bind(wl_registry *registry, uint32_t name, uint32_t version, void *data); +} \ No newline at end of file diff --git a/include/modules/wlr/workspaces.hpp b/include/modules/wlr/workspaces.hpp deleted file mode 100644 index 351ddc4..0000000 --- a/include/modules/wlr/workspaces.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -#include "AModule.hpp" -#include "bar.hpp" -#include "wlr-workspace-unstable-v1-client-protocol.h" - -namespace waybar::modules::wlr { - -class WorkspaceManager; -class WorkspaceGroup; - -class Workspace { - public: - Workspace(const waybar::Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, - zwlr_workspace_handle_v1 &workspace); - ~Workspace() = default; - auto update() -> void; - - enum class State { ACTIVE = 1 << 1 }; - - private: - const Bar & bar_; - const Gtk::Box box_; - const Gtk::Image icon_; - const Json::Value & config_; - const WorkspaceGroup &workspace_group_; - - // wlr stuff - zwlr_workspace_handle_v1 &workspace_handle_; - uint32_t state_; -}; - -class WorkspaceGroup { - public: - WorkspaceGroup(const waybar::Bar &bar, const Json::Value &config, WorkspaceManager &manager, - zwlr_workspace_group_handle_v1 &workspace_group_handle); - auto update() -> void; - - // wlr stuff - auto handle_workspace_create(zwlr_workspace_handle_v1 &workspace_handle) -> void; - auto handle_remove() -> void; - auto handle_output_enter(wl_output &output) -> void; - auto handle_output_leave(wl_output &output) -> void; - - private: - const waybar::Bar & bar_; - const Json::Value & config_; - const WorkspaceManager & workspace_manager_; - std::vector> workspaces_; - - // wlr stuff - zwlr_workspace_group_handle_v1 &workspace_group_handle_; -}; - -class WorkspaceManager : public AModule { - public: - WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config); - auto update() -> void override; - - // wlr stuff - auto register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void; - auto handle_workspace_group_create(zwlr_workspace_group_handle_v1 *workspace_group_handle) - -> void; - auto handle_done() -> void; - auto handle_finished() -> void; - - private: - const waybar::Bar & bar_; - Gtk::Box box_; - std::vector> groups_; - - // wlr stuff - zwlr_workspace_manager_v1 *workspace_manager_ = nullptr; -}; - -} // namespace waybar::modules::wlr diff --git a/meson.build b/meson.build index d0ba1e8..638a766 100644 --- a/meson.build +++ b/meson.build @@ -166,7 +166,8 @@ src_files += [ if true add_project_arguments('-DHAVE_WLR', language: 'cpp') src_files += 'src/modules/wlr/taskbar.cpp' - src_files += 'src/modules/wlr/workspaces.cpp' + src_files += 'src/modules/wlr/workspace_manager.cpp' + src_files += 'src/modules/wlr/workspace_manager_binding.cpp' endif if true diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp new file mode 100644 index 0000000..04a3188 --- /dev/null +++ b/src/modules/wlr/workspace_manager.cpp @@ -0,0 +1,182 @@ +#include "modules/wlr/workspace_manager.hpp" + +#include +#include + +#include + +#include "modules/wlr/workspace_manager_binding.hpp" + +namespace waybar::modules::wlr { + +uint32_t Workspace::workspace_global_id = 0; +uint32_t WorkspaceGroup::group_global_id = 0; + +WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar, + const Json::Value &config) + : waybar::AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()), + bar_(bar), + box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { + box_.set_name("workspaces"); + if (!id.empty()) { + box_.get_style_context()->add_class(id); + } + event_box_.add(box_); + + add_registry_listener(this); + if (!workspace_manager_) { + return; + } +} + +auto WorkspaceManager::register_manager(wl_registry *registry, uint32_t name, uint32_t version) + -> void { + if (workspace_manager_) { + spdlog::warn("Register workspace manager again although already registered!"); + return; + } + if (version != 1) { + spdlog::warn("Using different workspace manager protocol version: {}", version); + } + workspace_manager_ = workspace_manager_bind(registry, name, version, this); +} + +auto WorkspaceManager::handle_workspace_group_create( + zwlr_workspace_group_handle_v1 *workspace_group_handle) -> void { + groups_.push_back(std::make_unique(bar_, config_, *this, workspace_group_handle)); + spdlog::debug("Workspace group {} created", groups_.back()->id()); +} + +auto WorkspaceManager::handle_finished() -> void { + zwlr_workspace_manager_v1_destroy(workspace_manager_); + workspace_manager_ = nullptr; +} + +auto WorkspaceManager::handle_done() -> void { +} + +auto WorkspaceManager::update() -> void { + for (auto &group : groups_) { + group->update(); + } + AModule::update(); +} + +WorkspaceManager::~WorkspaceManager() { + if (!workspace_manager_) { + return; + } + + zwlr_workspace_manager_v1_destroy(workspace_manager_); + workspace_manager_ = nullptr; +} +auto WorkspaceManager::remove_workspace_group(uint32_t id) -> void { + auto it = std::find_if(groups_.begin(), + groups_.end(), + [id](const std::unique_ptr &g) { return g->id() == id; }); + + if (it == groups_.end()) { + spdlog::warn("Can't find group with id {}", id); + return; + } + + groups_.erase(it); +} + +WorkspaceGroup::WorkspaceGroup(const Bar &bar, const Json::Value &config, WorkspaceManager &manager, + zwlr_workspace_group_handle_v1 *workspace_group_handle) + : bar_(bar), + config_(config), + workspace_manager_(manager), + workspace_group_handle_(workspace_group_handle), + id_(++group_global_id) { + add_workspace_group_listener(workspace_group_handle, this); +} + +WorkspaceGroup::~WorkspaceGroup()->void { + if (!workspace_group_handle_) { + return; + } + + zwlr_workspace_group_handle_v1_destroy(workspace_group_handle_); + workspace_group_handle_ = nullptr; +} + +auto WorkspaceGroup::handle_workspace_create(zwlr_workspace_handle_v1 *workspace) -> void { + workspaces_.push_back(std::make_unique(bar_, config_, *this, workspace)); + spdlog::debug("Workspace {} created", workspaces_.back()->id()); +} + +auto WorkspaceGroup::handle_remove() -> void { + zwlr_workspace_group_handle_v1_destroy(workspace_group_handle_); + workspace_group_handle_ = nullptr; + workspace_manager_.remove_workspace_group(id_); +} + +auto WorkspaceGroup::handle_output_enter(wl_output *output) -> void { + spdlog::debug("Output {} assigned to {} group", (void *)output, id_); + output_ = output; +} + +auto WorkspaceGroup::handle_output_leave() -> void { + spdlog::debug("Output {} remove from {} group", (void *)output_, id_); + output_ = nullptr; +} + +auto WorkspaceGroup::update() -> void { + for (auto &workspace : workspaces_) { + workspace->update(); + } +} + +auto WorkspaceGroup::remove_workspace(uint32_t id) -> void { + auto it = std::find_if(workspaces_.begin(), + workspaces_.end(), + [id](const std::unique_ptr &w) { return w->id() == id; }); + + if (it == workspaces_.end()) { + spdlog::warn("Can't find group with id {}", id); + return; + } + + workspaces_.erase(it); +} + +Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, + zwlr_workspace_handle_v1 *workspace) + : bar_(bar), + config_(config), + workspace_group_(workspace_group), + workspace_handle_(workspace), + id_(++workspace_global_id) { + add_workspace_listener(workspace, this); +} + +Workspace::~Workspace() { + if (!workspace_handle_) { + return; + } + + zwlr_workspace_handle_v1_destroy(workspace_handle_); + workspace_handle_ = nullptr; +} + +auto Workspace::update() -> void {} + +auto Workspace::handle_state(const std::vector &state) -> void { + state_ = 0; + for (auto state_entry : state) { + switch (state_entry) { + case ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE: + state_ |= (uint32_t)State::ACTIVE; + break; + } + } +} + +auto Workspace::handle_remove() -> void { + zwlr_workspace_handle_v1_destroy(workspace_handle_); + workspace_handle_ = nullptr; + workspace_group_.remove_workspace(id_); +} +} // namespace waybar::modules::wlr \ No newline at end of file diff --git a/src/modules/wlr/workspace_manager_binding.cpp b/src/modules/wlr/workspace_manager_binding.cpp new file mode 100644 index 0000000..f6db711 --- /dev/null +++ b/src/modules/wlr/workspace_manager_binding.cpp @@ -0,0 +1,134 @@ +#include "modules/wlr/workspace_manager_binding.hpp" + +#include + +#include "client.hpp" +#include "modules/wlr/workspace_manager.hpp" + +namespace waybar::modules::wlr { + +static void handle_global(void *data, wl_registry *registry, uint32_t name, const char *interface, + uint32_t version) { + if (std::strcmp(interface, zwlr_workspace_manager_v1_interface.name) == 0) { + static_cast(data)->register_manager(registry, name, version); + } +} + +static void handle_global_remove(void *data, wl_registry *registry, uint32_t name) { + /* Nothing to do here */ +} + +static const wl_registry_listener registry_listener_impl = {.global = handle_global, + .global_remove = handle_global_remove}; + +void add_registry_listener(void *data) { + wl_display * display = Client::inst()->wl_display; + wl_registry *registry = wl_display_get_registry(display); + + wl_registry_add_listener(registry, ®istry_listener_impl, data); + wl_display_roundtrip(display); + wl_display_roundtrip(display); +} + +static void workspace_manager_handle_workspace_group( + void *data, zwlr_workspace_manager_v1 *_, zwlr_workspace_group_handle_v1 *workspace_group) { + static_cast(data)->handle_workspace_group_create(workspace_group); +} + +static void workspace_manager_handle_done(void *data, zwlr_workspace_manager_v1 *_) { + static_cast(data)->handle_done(); +} + +static void workspace_manager_handle_finished(void *data, zwlr_workspace_manager_v1 *_) { + static_cast(data)->handle_finished(); +} + +static const zwlr_workspace_manager_v1_listener workspace_manager_impl = { + .workspace_group = workspace_manager_handle_workspace_group, + .done = workspace_manager_handle_done, + .finished = workspace_manager_handle_finished, +}; + +zwlr_workspace_manager_v1 *workspace_manager_bind(wl_registry *registry, uint32_t name, + uint32_t version, void *data) { + auto *workspace_manager = static_cast( + wl_registry_bind(registry, name, &zwlr_workspace_manager_v1_interface, version)); + + if (workspace_manager) + zwlr_workspace_manager_v1_add_listener(workspace_manager, &workspace_manager_impl, data); + else + spdlog::error("Failed to register manager"); + + return workspace_manager; +} + +static void workspace_group_handle_output_enter(void *data, zwlr_workspace_group_handle_v1 *_, + wl_output *output) { + static_cast(data)->handle_output_enter(output); +} + +static void workspace_group_handle_output_leave(void *data, zwlr_workspace_group_handle_v1 *_, + wl_output *output) { + static_cast(data)->handle_output_leave(); +} + +static void workspace_group_handle_workspace(void *data, zwlr_workspace_group_handle_v1 *_, + zwlr_workspace_handle_v1 *workspace) { + static_cast(data)->handle_workspace_create(workspace); +} + +static void workspace_group_handle_remove(void *data, zwlr_workspace_group_handle_v1 *_) { + static_cast(data)->handle_remove(); +} + +static const zwlr_workspace_group_handle_v1_listener workspace_group_impl = { + .output_enter = workspace_group_handle_output_enter, + .output_leave = workspace_group_handle_output_leave, + .workspace = workspace_group_handle_workspace, + .remove = workspace_group_handle_remove}; + +void add_workspace_group_listener(zwlr_workspace_group_handle_v1 *workspace_group_handle, + void * data) { + zwlr_workspace_group_handle_v1_add_listener(workspace_group_handle, &workspace_group_impl, data); +} + +void workspace_handle_name(void *data, struct zwlr_workspace_handle_v1 *_, const char *name) { + static_cast(data)->handle_name(name); +} + +void workspace_handle_coordinates(void *data, struct zwlr_workspace_handle_v1 *_, + struct wl_array *coordinates) { + std::vector coords_vec; + auto coords = static_cast(coordinates->data); + for (size_t i = 0; i < coordinates->size; ++i) { + coords_vec.push_back(coords[i]); + } + + static_cast(data)->handle_coordinates(coords_vec); +} + +void workspace_handle_state(void *data, struct zwlr_workspace_handle_v1 *_, + struct wl_array *state) { + std::vector state_vec; + auto coords = static_cast(state->data); + for (size_t i = 0; i < state->size; ++i) { + state_vec.push_back(coords[i]); + } + + static_cast(data)->handle_state(state_vec); +} + +void workspace_handle_remove(void *data, struct zwlr_workspace_handle_v1 *_) { + static_cast(data)->handle_remove(); +} + +static const zwlr_workspace_handle_v1_listener workspace_impl = { + .name = workspace_handle_name, + .coordinates = workspace_handle_coordinates, + .state = workspace_handle_state, + .remove = workspace_handle_remove}; + +void add_workspace_listener(zwlr_workspace_handle_v1 *workspace_handle, void *data) { + zwlr_workspace_handle_v1_add_listener(workspace_handle, &workspace_impl, data); +} +} // namespace waybar::modules::wlr diff --git a/src/modules/wlr/workspaces.cpp b/src/modules/wlr/workspaces.cpp deleted file mode 100644 index 0d9ae0b..0000000 --- a/src/modules/wlr/workspaces.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "modules/wlr/workspaces.hpp" - -#include -#include - -#include - -namespace waybar::modules::wlr { - -static void handle_global(void *data, wl_registry *registry, uint32_t name, - const char *interface, uint32_t version) { - if (std::strcmp(interface, zwlr_workspace_manager_v1_interface.name) == 0) { - static_cast(data)->register_manager(registry, name, version); - } -} - -static void handle_global_remove(void *data, wl_registry *registry, uint32_t name) { - /* Nothing to do here */ -} - -static const wl_registry_listener registry_listener_impl = {.global = handle_global, - .global_remove = handle_global_remove}; - -WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar, - const Json::Value &config) - : waybar::AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()), - bar_(bar), - box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { - box_.set_name("workspaces"); - if (!id.empty()) { - box_.get_style_context()->add_class(id); - } - event_box_.add(box_); - - // wlr stuff - wl_display * display = Client::inst()->wl_display; - wl_registry *registry = wl_display_get_registry(display); - - wl_registry_add_listener(registry, ®istry_listener_impl, this); - wl_display_roundtrip(display); - - if (!workspace_manager_) { - return; - } -} - -static void workspace_manager_handle_workspace_group( - void *data, zwlr_workspace_manager_v1 *_, - zwlr_workspace_group_handle_v1 *workspace_group) { - static_cast(data)->handle_workspace_group_create(workspace_group); -} - -static void workspace_manager_handle_done(void *data, zwlr_workspace_manager_v1 *_) { - static_cast(data)->handle_done(); -} - -static void workspace_manager_handle_finished(void *data, zwlr_workspace_manager_v1 *_) { - static_cast(data)->handle_finished(); -} - -static const zwlr_workspace_manager_v1_listener workspace_manager_impl = { - .workspace_group = workspace_manager_handle_workspace_group, - .done = workspace_manager_handle_done, - .finished = workspace_manager_handle_finished, -}; - -auto WorkspaceManager::register_manager(wl_registry *registry, uint32_t name, uint32_t version) - -> void { - if (workspace_manager_) { - spdlog::warn("Register workspace manager again although already registered!"); - return; - } - if (version != 1) { - spdlog::warn("Using different workspace manager protocol version: {}", version); - } - - workspace_manager_ = static_cast( - wl_registry_bind(registry, name, &zwlr_workspace_manager_v1_interface, version)); - - if (workspace_manager_) - zwlr_workspace_manager_v1_add_listener(workspace_manager_, &workspace_manager_impl, this); - else - spdlog::debug("Failed to register manager"); -} -auto WorkspaceManager::handle_workspace_group_create( - zwlr_workspace_group_handle_v1 *workspace_group_handle) -> void { - groups_.push_back(std::make_unique(bar_, config_, *this, *workspace_group_handle)); -} - -auto WorkspaceManager::handle_finished() -> void { - zwlr_workspace_manager_v1_destroy(workspace_manager_); - workspace_manager_ = nullptr; -} -auto WorkspaceManager::handle_done() -> void {} -auto WorkspaceManager::update() -> void { - for (auto &group : groups_) { - group->update(); - } - AModule::update(); -} - -static void workspace_group_handle_output_enter(void *data, - zwlr_workspace_group_handle_v1 *_, - wl_output *output) { - static_cast(data)->handle_output_enter(*output); -} - -static void workspace_group_handle_output_leave(void *data, - zwlr_workspace_group_handle_v1 *_, - wl_output *output) { - static_cast(data)->handle_output_leave(*output); -} - -static void workspace_group_handle_workspace(void *data, - zwlr_workspace_group_handle_v1 *_, - zwlr_workspace_handle_v1 *workspace) { - static_cast(data)->handle_workspace_create(*workspace); -} - -static void workspace_group_handle_remove(void *data, - zwlr_workspace_group_handle_v1 *_) { - static_cast(data)->handle_remove(); -} - -static const zwlr_workspace_group_handle_v1_listener workspace_group_impl = { - .output_enter = workspace_group_handle_output_enter, - .output_leave = workspace_group_handle_output_leave, - .workspace = workspace_group_handle_workspace, - .remove = workspace_group_handle_remove -}; - -WorkspaceGroup::WorkspaceGroup(const Bar & bar, const Json::Value &config, WorkspaceManager &manager, - zwlr_workspace_group_handle_v1 &workspace_group_handle) - : bar_(bar), config_(config), workspace_manager_(manager), workspace_group_handle_(workspace_group_handle) -{ - zwlr_workspace_group_handle_v1_add_listener(&workspace_group_handle, &workspace_group_impl, this); -} -auto WorkspaceGroup::handle_workspace_create(zwlr_workspace_handle_v1 &workspace) -> void { - workspaces_.push_back(std::make_unique(bar_, config_, *this, workspace)); -} -auto WorkspaceGroup::handle_remove() -> void {} -auto WorkspaceGroup::handle_output_enter(wl_output &output) -> void {} -auto WorkspaceGroup::handle_output_leave(wl_output &output) -> void {} -auto WorkspaceGroup::update() -> void { - -} -Workspace::Workspace(const Bar &bar, const Json::Value &config, - WorkspaceGroup &workspace_group, zwlr_workspace_handle_v1 &workspace) - : bar_(bar), config_(config), workspace_group_(workspace_group), workspace_handle_(workspace) -{ -} -} // namespace waybar::modules::wlr \ No newline at end of file From 7638f5c5958d0f9243c8b71569b9cb048f439a7a Mon Sep 17 00:00:00 2001 From: dmitry Date: Thu, 6 Aug 2020 01:42:57 +0300 Subject: [PATCH 04/61] Add base name representation --- include/modules/wlr/workspace_manager.hpp | 14 ++++++++---- src/modules/wlr/workspace_manager.cpp | 26 ++++++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index 3c8fe99..f606331 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include @@ -23,6 +25,7 @@ class Workspace { auto update() -> void; auto id() const -> uint32_t { return id_; } + // wlr stuff auto handle_name(const std::string &name) -> void { name_ = name; } auto handle_coordinates(const std::vector &coordinates) -> void { coordinates_ = coordinates; @@ -46,8 +49,9 @@ class Workspace { std::string name_; std::vector coordinates_; - const Gtk::Box box_; - const Gtk::Image icon_; + Gtk::Button button_; + Gtk::Box content_; + Gtk::Label label_; }; class WorkspaceGroup { @@ -62,11 +66,12 @@ class WorkspaceGroup { // wlr stuff auto handle_workspace_create(zwlr_workspace_handle_v1 *workspace_handle) -> void; - auto handle_remove() -> void; auto handle_output_enter(wl_output *output) -> void; auto handle_output_leave() -> void; + auto add_button(Gtk::Button &button) -> void; + private: static uint32_t group_global_id; const waybar::Bar &bar_; @@ -93,10 +98,11 @@ class WorkspaceManager : public AModule { auto register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void; auto handle_workspace_group_create(zwlr_workspace_group_handle_v1 *workspace_group_handle) -> void; - auto handle_done() -> void; auto handle_finished() -> void; + auto add_button(Gtk::Button &button) -> void { box_.pack_start(button, false, false); } + private: const waybar::Bar & bar_; Gtk::Box box_; diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 04a3188..25ce525 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -14,7 +14,7 @@ uint32_t WorkspaceGroup::group_global_id = 0; WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config) - : waybar::AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()), + : waybar::AModule(config, "workspaces", id, false, false), bar_(bar), box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { box_.set_name("workspaces"); @@ -53,6 +53,7 @@ auto WorkspaceManager::handle_finished() -> void { } auto WorkspaceManager::handle_done() -> void { + dp.emit(); } auto WorkspaceManager::update() -> void { @@ -92,8 +93,11 @@ WorkspaceGroup::WorkspaceGroup(const Bar &bar, const Json::Value &config, Worksp id_(++group_global_id) { add_workspace_group_listener(workspace_group_handle, this); } +auto WorkspaceGroup::add_button(Gtk::Button &button) -> void { + workspace_manager_.add_button(button); +} -WorkspaceGroup::~WorkspaceGroup()->void { +WorkspaceGroup::~WorkspaceGroup() { if (!workspace_group_handle_) { return; } @@ -135,7 +139,7 @@ auto WorkspaceGroup::remove_workspace(uint32_t id) -> void { [id](const std::unique_ptr &w) { return w->id() == id; }); if (it == workspaces_.end()) { - spdlog::warn("Can't find group with id {}", id); + spdlog::warn("Can't find workspace with id {}", id); return; } @@ -148,8 +152,17 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & config_(config), workspace_group_(workspace_group), workspace_handle_(workspace), - id_(++workspace_global_id) { + id_(++workspace_global_id), + content_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} { add_workspace_listener(workspace, this); + workspace_group.add_button(button_); + button_.set_relief(Gtk::RELIEF_NONE); + label_.set_label(fmt::format("{name}", fmt::arg("name", "1"))); + label_.show(); + content_.add(label_); + content_.show(); + button_.add(content_); + button_.show(); } Workspace::~Workspace() { @@ -161,7 +174,10 @@ Workspace::~Workspace() { workspace_handle_ = nullptr; } -auto Workspace::update() -> void {} +auto Workspace::update() -> void { + label_.set_label(fmt::format("{name}", fmt::arg("name", name_))); + label_.show(); +} auto Workspace::handle_state(const std::vector &state) -> void { state_ = 0; From 4c251578e923760372bf51f2d9540d7abd9b204b Mon Sep 17 00:00:00 2001 From: dmitry Date: Fri, 7 Aug 2020 02:45:08 +0300 Subject: [PATCH 05/61] Add formatting and states handling --- include/modules/wlr/workspace_manager.hpp | 20 +++++- src/modules/wlr/workspace_manager.cpp | 80 ++++++++++++++++++++--- 2 files changed, 87 insertions(+), 13 deletions(-) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index f606331..8cd065f 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -25,6 +26,7 @@ class Workspace { auto update() -> void; auto id() const -> uint32_t { return id_; } + auto is_active() const -> bool { return state_ & static_cast(State::ACTIVE); } // wlr stuff auto handle_name(const std::string &name) -> void { name_ = name; } auto handle_coordinates(const std::vector &coordinates) -> void { @@ -33,9 +35,14 @@ class Workspace { auto handle_state(const std::vector &state) -> void; auto handle_remove() -> void; + auto handle_done() -> void; + auto handle_clicked() -> void; + enum class State { ACTIVE = 1 << 0 }; private: + auto get_icon() -> std::string; + static uint32_t workspace_global_id; const Bar & bar_; const Json::Value &config_; @@ -45,9 +52,12 @@ class Workspace { zwlr_workspace_handle_v1 *workspace_handle_; uint32_t state_ = 0; - uint32_t id_; - std::string name_; - std::vector coordinates_; + uint32_t id_; + std::string name_; + std::vector coordinates_; + static std::map icons_map_; + std::string format_; + bool with_icon_ = false; Gtk::Button button_; Gtk::Box content_; @@ -62,6 +72,7 @@ class WorkspaceGroup { auto update() -> void; auto id() const -> uint32_t { return id_; } + auto is_visible() const -> bool { return output_ != nullptr; } auto remove_workspace(uint32_t id_) -> void; // wlr stuff @@ -71,6 +82,8 @@ class WorkspaceGroup { auto handle_output_leave() -> void; auto add_button(Gtk::Button &button) -> void; + auto handle_done() -> void; + auto commit() -> void; private: static uint32_t group_global_id; @@ -102,6 +115,7 @@ class WorkspaceManager : public AModule { auto handle_finished() -> void; auto add_button(Gtk::Button &button) -> void { box_.pack_start(button, false, false); } + auto commit() -> void; private: const waybar::Bar & bar_; diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 25ce525..cf0510d 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -9,8 +9,9 @@ namespace waybar::modules::wlr { -uint32_t Workspace::workspace_global_id = 0; -uint32_t WorkspaceGroup::group_global_id = 0; +uint32_t Workspace::workspace_global_id = 0; +uint32_t WorkspaceGroup::group_global_id = 0; +std::map Workspace::icons_map_; WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar, const Json::Value &config) @@ -53,6 +54,9 @@ auto WorkspaceManager::handle_finished() -> void { } auto WorkspaceManager::handle_done() -> void { + for (auto &group : groups_) { + group->handle_done(); + } dp.emit(); } @@ -83,6 +87,7 @@ auto WorkspaceManager::remove_workspace_group(uint32_t id) -> void { groups_.erase(it); } +auto WorkspaceManager::commit() -> void { zwlr_workspace_manager_v1_commit(workspace_manager_); } WorkspaceGroup::WorkspaceGroup(const Bar &bar, const Json::Value &config, WorkspaceManager &manager, zwlr_workspace_group_handle_v1 *workspace_group_handle) @@ -145,6 +150,14 @@ auto WorkspaceGroup::remove_workspace(uint32_t id) -> void { workspaces_.erase(it); } +auto WorkspaceGroup::handle_done() -> void { + if (is_visible()) { + for (auto &workspace : workspaces_) { + workspace->handle_done(); + } + } +} +auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, zwlr_workspace_handle_v1 *workspace) @@ -152,17 +165,30 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & config_(config), workspace_group_(workspace_group), workspace_handle_(workspace), - id_(++workspace_global_id), - content_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} { + id_(++workspace_global_id) { add_workspace_listener(workspace, this); + + auto config_format = config["format"]; + + format_ = config_format.isString() ? config_format.asString() : "{name}"; + with_icon_ = format_.find("{icon}") != std::string::npos; + + if (with_icon_ && icons_map_.empty()) { + auto format_icons = config["format-icons"]; + for (auto &name : format_icons.getMemberNames()) { + icons_map_.emplace(name, format_icons[name].asString()); + } + } + + button_.signal_clicked().connect(sigc::mem_fun(this, &Workspace::handle_clicked)); + workspace_group.add_button(button_); button_.set_relief(Gtk::RELIEF_NONE); - label_.set_label(fmt::format("{name}", fmt::arg("name", "1"))); - label_.show(); - content_.add(label_); - content_.show(); + content_.set_center_widget(label_); button_.add(content_); button_.show(); + label_.show(); + content_.show(); } Workspace::~Workspace() { @@ -175,8 +201,8 @@ Workspace::~Workspace() { } auto Workspace::update() -> void { - label_.set_label(fmt::format("{name}", fmt::arg("name", name_))); - label_.show(); + label_.set_markup(fmt::format( + format_, fmt::arg("name", name_), fmt::arg("icon", with_icon_ ? get_icon() : ""))); } auto Workspace::handle_state(const std::vector &state) -> void { @@ -195,4 +221,38 @@ auto Workspace::handle_remove() -> void { workspace_handle_ = nullptr; workspace_group_.remove_workspace(id_); } +auto Workspace::handle_done() -> void { + spdlog::debug("Workspace {} changed to state {}", id_, state_); + auto style_context = button_.get_style_context(); + if (is_active()) { + style_context->add_class("focused"); + } else { + style_context->remove_class("focused"); + } +} +auto Workspace::get_icon() -> std::string { + if (is_active()) { + auto focused_icon_it = icons_map_.find("focused"); + if (focused_icon_it != icons_map_.end()) { + return focused_icon_it->second; + } + } + + auto named_icon_it = icons_map_.find(name_); + if (named_icon_it != icons_map_.end()) { + return named_icon_it->second; + } + + auto default_icon_it = icons_map_.find("default"); + if (default_icon_it != icons_map_.end()) { + return default_icon_it->second; + } + + return name_; +} +auto Workspace::handle_clicked() -> void { + spdlog::debug("Workspace {} clicked", (void*)workspace_handle_); + zwlr_workspace_handle_v1_activate(workspace_handle_); + workspace_group_.commit(); +} } // namespace waybar::modules::wlr \ No newline at end of file From 0ad29a5960c945fed328d300fce3d897d2a68994 Mon Sep 17 00:00:00 2001 From: dmitry Date: Fri, 7 Aug 2020 23:46:47 +0300 Subject: [PATCH 06/61] Finish base implementation --- include/modules/wlr/workspace_manager.hpp | 28 +++--- src/modules/wlr/workspace_manager.cpp | 86 +++++++++++++++---- src/modules/wlr/workspace_manager_binding.cpp | 12 ++- 3 files changed, 96 insertions(+), 30 deletions(-) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index 8cd065f..abec5d6 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -21,29 +21,31 @@ class WorkspaceGroup; class Workspace { public: Workspace(const waybar::Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, - zwlr_workspace_handle_v1 *workspace); + zwlr_workspace_handle_v1 *workspace, uint32_t id); ~Workspace(); auto update() -> void; auto id() const -> uint32_t { return id_; } auto is_active() const -> bool { return state_ & static_cast(State::ACTIVE); } // wlr stuff - auto handle_name(const std::string &name) -> void { name_ = name; } - auto handle_coordinates(const std::vector &coordinates) -> void { - coordinates_ = coordinates; - } + auto handle_name(const std::string &name) -> void; + auto handle_coordinates(const std::vector &coordinates) -> void; auto handle_state(const std::vector &state) -> void; auto handle_remove() -> void; auto handle_done() -> void; auto handle_clicked() -> void; + auto show() -> void { button_.show(); } + auto hide() -> void { button_.hide(); } + auto get_button_ref() -> Gtk::Button & { return button_; } + auto get_name() -> std::string & { return name_; } + auto get_coords() -> std::vector & { return coordinates_; } enum class State { ACTIVE = 1 << 0 }; private: auto get_icon() -> std::string; - static uint32_t workspace_global_id; const Bar & bar_; const Json::Value &config_; WorkspaceGroup & workspace_group_; @@ -66,8 +68,9 @@ class Workspace { class WorkspaceGroup { public: - WorkspaceGroup(const waybar::Bar &bar, const Json::Value &config, WorkspaceManager &manager, - zwlr_workspace_group_handle_v1 *workspace_group_handle); + WorkspaceGroup(const waybar::Bar &bar, Gtk::Box &box, const Json::Value &config, + WorkspaceManager &manager, zwlr_workspace_group_handle_v1 *workspace_group_handle, + uint32_t id); ~WorkspaceGroup(); auto update() -> void; @@ -84,10 +87,12 @@ class WorkspaceGroup { auto add_button(Gtk::Button &button) -> void; auto handle_done() -> void; auto commit() -> void; + auto sort_workspaces() -> void; private: - static uint32_t group_global_id; + static uint32_t workspace_global_id; const waybar::Bar &bar_; + Gtk::Box & box_; const Json::Value &config_; WorkspaceManager & workspace_manager_; @@ -97,6 +102,8 @@ class WorkspaceGroup { uint32_t id_; std::vector> workspaces_; + bool sort_by_name = true; + bool sort_by_coordinates = true; }; class WorkspaceManager : public AModule { @@ -114,7 +121,6 @@ class WorkspaceManager : public AModule { auto handle_done() -> void; auto handle_finished() -> void; - auto add_button(Gtk::Button &button) -> void { box_.pack_start(button, false, false); } auto commit() -> void; private: @@ -124,6 +130,8 @@ class WorkspaceManager : public AModule { // wlr stuff zwlr_workspace_manager_v1 *workspace_manager_ = nullptr; + + static uint32_t group_global_id; }; } // namespace waybar::modules::wlr diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index cf0510d..2892d55 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -9,8 +9,8 @@ namespace waybar::modules::wlr { -uint32_t Workspace::workspace_global_id = 0; -uint32_t WorkspaceGroup::group_global_id = 0; +uint32_t WorkspaceGroup::workspace_global_id = 0; +uint32_t WorkspaceManager::group_global_id = 0; std::map Workspace::icons_map_; WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar, @@ -44,8 +44,10 @@ auto WorkspaceManager::register_manager(wl_registry *registry, uint32_t name, ui auto WorkspaceManager::handle_workspace_group_create( zwlr_workspace_group_handle_v1 *workspace_group_handle) -> void { - groups_.push_back(std::make_unique(bar_, config_, *this, workspace_group_handle)); - spdlog::debug("Workspace group {} created", groups_.back()->id()); + auto new_id = ++group_global_id; + groups_.push_back( + std::make_unique(bar_, box_, config_, *this, workspace_group_handle, new_id)); + spdlog::debug("Workspace group {} created", new_id); } auto WorkspaceManager::handle_finished() -> void { @@ -89,17 +91,28 @@ auto WorkspaceManager::remove_workspace_group(uint32_t id) -> void { } auto WorkspaceManager::commit() -> void { zwlr_workspace_manager_v1_commit(workspace_manager_); } -WorkspaceGroup::WorkspaceGroup(const Bar &bar, const Json::Value &config, WorkspaceManager &manager, - zwlr_workspace_group_handle_v1 *workspace_group_handle) +WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value &config, + WorkspaceManager & manager, + zwlr_workspace_group_handle_v1 *workspace_group_handle, uint32_t id) : bar_(bar), + box_(box), config_(config), workspace_manager_(manager), workspace_group_handle_(workspace_group_handle), - id_(++group_global_id) { + id_(id) { add_workspace_group_listener(workspace_group_handle, this); + auto config_sort_by_name = config_["sort_by_name"]; + if (config_sort_by_name.isBool()) { + sort_by_name = config_sort_by_name.asBool(); + } + + auto config_sort_by_coordinates = config_["sort_by_coordinates"]; + if (config_sort_by_coordinates.isBool()) { + sort_by_coordinates = config_sort_by_coordinates.asBool(); + } } auto WorkspaceGroup::add_button(Gtk::Button &button) -> void { - workspace_manager_.add_button(button); + box_.pack_start(button, false, false); } WorkspaceGroup::~WorkspaceGroup() { @@ -112,8 +125,9 @@ WorkspaceGroup::~WorkspaceGroup() { } auto WorkspaceGroup::handle_workspace_create(zwlr_workspace_handle_v1 *workspace) -> void { - workspaces_.push_back(std::make_unique(bar_, config_, *this, workspace)); - spdlog::debug("Workspace {} created", workspaces_.back()->id()); + auto new_id = ++workspace_global_id; + workspaces_.push_back(std::make_unique(bar_, config_, *this, workspace, new_id)); + spdlog::debug("Workspace {} created", new_id); } auto WorkspaceGroup::handle_remove() -> void { @@ -124,12 +138,18 @@ auto WorkspaceGroup::handle_remove() -> void { auto WorkspaceGroup::handle_output_enter(wl_output *output) -> void { spdlog::debug("Output {} assigned to {} group", (void *)output, id_); + for (auto &workspace : workspaces_) { + workspace->show(); + } output_ = output; } auto WorkspaceGroup::handle_output_leave() -> void { spdlog::debug("Output {} remove from {} group", (void *)output_, id_); output_ = nullptr; + for (auto &workspace : workspaces_) { + workspace->hide(); + } } auto WorkspaceGroup::update() -> void { @@ -150,22 +170,37 @@ auto WorkspaceGroup::remove_workspace(uint32_t id) -> void { workspaces_.erase(it); } + auto WorkspaceGroup::handle_done() -> void { - if (is_visible()) { - for (auto &workspace : workspaces_) { - workspace->handle_done(); - } + for (auto &workspace : workspaces_) { + workspace->handle_done(); } } auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } +auto WorkspaceGroup::sort_workspaces() -> void { + auto cmp = [=](std::unique_ptr &lhs, std::unique_ptr &rhs) { + if (sort_by_name && lhs->get_name() != rhs->get_name()) { + return lhs->get_name() < rhs->get_name(); + } + + return lhs->get_coords() < rhs->get_coords(); + }; + std::sort(workspaces_.begin(), workspaces_.end(), cmp); + for (size_t i = 0; i < workspaces_.size(); ++i) { + for (auto &workspace : workspaces_) { + box_.reorder_child(workspace->get_button_ref(), i); + } + } +} + Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, - zwlr_workspace_handle_v1 *workspace) + zwlr_workspace_handle_v1 *workspace, uint32_t id) : bar_(bar), config_(config), workspace_group_(workspace_group), workspace_handle_(workspace), - id_(++workspace_global_id) { + id_(id) { add_workspace_listener(workspace, this); auto config_format = config["format"]; @@ -186,6 +221,10 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & button_.set_relief(Gtk::RELIEF_NONE); content_.set_center_widget(label_); button_.add(content_); + if (!workspace_group.is_visible()) { + return; + } + button_.show(); label_.show(); content_.show(); @@ -221,6 +260,7 @@ auto Workspace::handle_remove() -> void { workspace_handle_ = nullptr; workspace_group_.remove_workspace(id_); } + auto Workspace::handle_done() -> void { spdlog::debug("Workspace {} changed to state {}", id_, state_); auto style_context = button_.get_style_context(); @@ -230,6 +270,7 @@ auto Workspace::handle_done() -> void { style_context->remove_class("focused"); } } + auto Workspace::get_icon() -> std::string { if (is_active()) { auto focused_icon_it = icons_map_.find("focused"); @@ -250,9 +291,20 @@ auto Workspace::get_icon() -> std::string { return name_; } + auto Workspace::handle_clicked() -> void { - spdlog::debug("Workspace {} clicked", (void*)workspace_handle_); + spdlog::debug("Workspace {} clicked", (void *)workspace_handle_); zwlr_workspace_handle_v1_activate(workspace_handle_); workspace_group_.commit(); } + +auto Workspace::handle_name(const std::string &name) -> void { + name_ = name; + workspace_group_.sort_workspaces(); +} + +auto Workspace::handle_coordinates(const std::vector &coordinates) -> void { + coordinates_ = coordinates; + workspace_group_.sort_workspaces(); +} } // namespace waybar::modules::wlr \ No newline at end of file diff --git a/src/modules/wlr/workspace_manager_binding.cpp b/src/modules/wlr/workspace_manager_binding.cpp index f6db711..c7d84bb 100644 --- a/src/modules/wlr/workspace_manager_binding.cpp +++ b/src/modules/wlr/workspace_manager_binding.cpp @@ -107,12 +107,18 @@ void workspace_handle_coordinates(void *data, struct zwlr_workspace_handle_v1 *_ static_cast(data)->handle_coordinates(coords_vec); } -void workspace_handle_state(void *data, struct zwlr_workspace_handle_v1 *_, +void workspace_handle_state(void *data, struct zwlr_workspace_handle_v1 *workspace_handle, struct wl_array *state) { std::vector state_vec; - auto coords = static_cast(state->data); + auto states = static_cast(state->data); for (size_t i = 0; i < state->size; ++i) { - state_vec.push_back(coords[i]); + // To sync server and pending states + if (states[i] == ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { + zwlr_workspace_handle_v1_activate(workspace_handle); + } else { + zwlr_workspace_handle_v1_deactivate(workspace_handle); + } + state_vec.push_back(states[i]); } static_cast(data)->handle_state(state_vec); From 42b6c089f34b24cb46a7add4892112a4b15799ca Mon Sep 17 00:00:00 2001 From: dmitry Date: Sat, 8 Aug 2020 00:09:35 +0300 Subject: [PATCH 07/61] Add docs and adjust sorting --- man/waybar-wlr-workspaces.5.scd | 69 +++++++++++++++++++++++++++ man/waybar.5.scd | 1 + meson.build | 1 + src/modules/wlr/workspace_manager.cpp | 23 +++++++-- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 man/waybar-wlr-workspaces.5.scd diff --git a/man/waybar-wlr-workspaces.5.scd b/man/waybar-wlr-workspaces.5.scd new file mode 100644 index 0000000..732c01b --- /dev/null +++ b/man/waybar-wlr-workspaces.5.scd @@ -0,0 +1,69 @@ +waybar-wlr-workspaces(5) + +# NAME + +waybar - wlr workspaces module + +# DESCRIPTION + +The *workspaces* module displays the currently used workspaces in waynland compositor. + +# CONFIGURATION + +Addressed by *wlr/workspaces* + +*format*: ++ + typeof: string ++ + default: {name} ++ + The format, how information should be displayed. + +*format-icons*: ++ + typeof: array ++ + Based on the workspace name and state, the corresponding icon gets selected. See *icons*. + +*sort-by-name*: ++ + typeof: bool ++ + default: true ++ + Should workspaces be sorted by name. + +*sort-by-coordinates*: ++ + typeof: bool ++ + default: false ++ + Should workspaces be sorted by coordinates. + Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first. + If both are false - sort by id will be performed. + +# FORMAT REPLACEMENTS + +*{name}*: Number stripped from workspace value. + +*{icon}*: Icon, as defined in *format-icons*. + +# ICONS + +Additional to workspace name matching, the following *format-icons* can be set. + +- *default*: Will be shown, when no string matches is found. +- *focused*: Will be shown, when workspace is focused + +# EXAMPLES + +``` +"wlr/workspaces": { + "format": "{name}: {icon}", + "format-icons": { + "1": "", + "2": "", + "3": "", + "4": "", + "5": "", + "focused": "", + "default": "" + } +} +``` + +# Style + +- *#workspaces button* +- *#workspaces button.focused* diff --git a/man/waybar.5.scd b/man/waybar.5.scd index 5267110..a758821 100644 --- a/man/waybar.5.scd +++ b/man/waybar.5.scd @@ -197,5 +197,6 @@ Valid options for the "rotate" property are: 0, 90, 180 and 270. - *waybar-sway-window(5)* - *waybar-sway-workspaces(5)* - *waybar-wlr-taskbar(5)* +- *waybar-wlr-workspaces(5)* - *waybar-temperature(5)* - *waybar-tray(5)* diff --git a/meson.build b/meson.build index 638a766..19c6b4a 100644 --- a/meson.build +++ b/meson.build @@ -272,6 +272,7 @@ if scdoc.found() 'waybar-tray.5.scd', 'waybar-states.5.scd', 'waybar-wlr-taskbar.5.scd', + 'waybar-wlr-workspaces.5.scd', 'waybar-bluetooth.5.scd', ] diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 2892d55..d86dc62 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -101,12 +101,12 @@ WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value workspace_group_handle_(workspace_group_handle), id_(id) { add_workspace_group_listener(workspace_group_handle, this); - auto config_sort_by_name = config_["sort_by_name"]; + auto config_sort_by_name = config_["sort-by-name"]; if (config_sort_by_name.isBool()) { sort_by_name = config_sort_by_name.asBool(); } - auto config_sort_by_coordinates = config_["sort_by_coordinates"]; + auto config_sort_by_coordinates = config_["sort-by-coordinates"]; if (config_sort_by_coordinates.isBool()) { sort_by_coordinates = config_sort_by_coordinates.asBool(); } @@ -180,12 +180,25 @@ auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } auto WorkspaceGroup::sort_workspaces() -> void { auto cmp = [=](std::unique_ptr &lhs, std::unique_ptr &rhs) { - if (sort_by_name && lhs->get_name() != rhs->get_name()) { - return lhs->get_name() < rhs->get_name(); + auto is_name_less = lhs->get_name() < rhs->get_name(); + auto is_name_eq = lhs->get_name() == rhs->get_name(); + auto is_coords_less = lhs->get_coords() < rhs->get_coords(); + if (sort_by_name) { + if (sort_by_coordinates) { + return is_name_eq ? is_coords_less : is_name_less; + } + else { + return is_name_less; + } } - return lhs->get_coords() < rhs->get_coords(); + if (sort_by_coordinates) { + return is_coords_less; + } + + return lhs->id() < rhs->id(); }; + std::sort(workspaces_.begin(), workspaces_.end(), cmp); for (size_t i = 0; i < workspaces_.size(); ++i) { for (auto &workspace : workspaces_) { From 22409d27c5a6307880828841a8b7c4a113b3dc1b Mon Sep 17 00:00:00 2001 From: dmitry Date: Tue, 11 Aug 2020 00:28:56 +0300 Subject: [PATCH 08/61] Fix docs typos Add removing buttons Adjust handling multiple outputs. --- include/modules/wlr/workspace_manager.hpp | 1 + man/waybar-wlr-workspaces.5.scd | 7 ++++--- src/modules/wlr/workspace_manager.cpp | 21 ++++++++++++++++++++- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index abec5d6..73c5893 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -85,6 +85,7 @@ class WorkspaceGroup { auto handle_output_leave() -> void; auto add_button(Gtk::Button &button) -> void; + auto remove_button(Gtk::Button &button) -> void; auto handle_done() -> void; auto commit() -> void; auto sort_workspaces() -> void; diff --git a/man/waybar-wlr-workspaces.5.scd b/man/waybar-wlr-workspaces.5.scd index 732c01b..c1e827f 100644 --- a/man/waybar-wlr-workspaces.5.scd +++ b/man/waybar-wlr-workspaces.5.scd @@ -6,7 +6,7 @@ waybar - wlr workspaces module # DESCRIPTION -The *workspaces* module displays the currently used workspaces in waynland compositor. +The *workspaces* module displays the currently used workspaces in wayland compositor. # CONFIGURATION @@ -35,7 +35,7 @@ Addressed by *wlr/workspaces* # FORMAT REPLACEMENTS -*{name}*: Number stripped from workspace value. +*{name}*: Name of workspace assigned by compositor *{icon}*: Icon, as defined in *format-icons*. @@ -43,7 +43,7 @@ Addressed by *wlr/workspaces* Additional to workspace name matching, the following *format-icons* can be set. -- *default*: Will be shown, when no string matches is found. +- *default*: Will be shown, when no string match is found. - *focused*: Will be shown, when workspace is focused # EXAMPLES @@ -65,5 +65,6 @@ Additional to workspace name matching, the following *format-icons* can be set. # Style +- *#workspaces* - *#workspaces button* - *#workspaces button.focused* diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index d86dc62..20294f4 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -1,5 +1,6 @@ #include "modules/wlr/workspace_manager.hpp" +#include #include #include @@ -77,6 +78,7 @@ WorkspaceManager::~WorkspaceManager() { zwlr_workspace_manager_v1_destroy(workspace_manager_); workspace_manager_ = nullptr; } + auto WorkspaceManager::remove_workspace_group(uint32_t id) -> void { auto it = std::find_if(groups_.begin(), groups_.end(), @@ -111,6 +113,7 @@ WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value sort_by_coordinates = config_sort_by_coordinates.asBool(); } } + auto WorkspaceGroup::add_button(Gtk::Button &button) -> void { box_.pack_start(button, false, false); } @@ -138,15 +141,25 @@ auto WorkspaceGroup::handle_remove() -> void { auto WorkspaceGroup::handle_output_enter(wl_output *output) -> void { spdlog::debug("Output {} assigned to {} group", (void *)output, id_); + output_ = output; + + if (output != gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj())) { + return; + } + for (auto &workspace : workspaces_) { workspace->show(); } - output_ = output; } auto WorkspaceGroup::handle_output_leave() -> void { spdlog::debug("Output {} remove from {} group", (void *)output_, id_); output_ = nullptr; + + if (output_ != gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj())) { + return; + } + for (auto &workspace : workspaces_) { workspace->hide(); } @@ -176,6 +189,7 @@ auto WorkspaceGroup::handle_done() -> void { workspace->handle_done(); } } + auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } auto WorkspaceGroup::sort_workspaces() -> void { @@ -207,6 +221,10 @@ auto WorkspaceGroup::sort_workspaces() -> void { } } +auto WorkspaceGroup::remove_button(Gtk::Button &button) -> void { + box_.remove(button); +} + Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, zwlr_workspace_handle_v1 *workspace, uint32_t id) : bar_(bar), @@ -244,6 +262,7 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & } Workspace::~Workspace() { + workspace_group_.remove_button(button_); if (!workspace_handle_) { return; } From cb49650ea48b457e0b5a4572d794bbc1a73bc33a Mon Sep 17 00:00:00 2001 From: Michael Swiger Date: Sun, 22 Aug 2021 14:46:40 -0700 Subject: [PATCH 09/61] Use g_memdup2 instead of g_memdup This fixes a compile warning. See: https://discourse.gnome.org/t/port-your-module-from-g-memdup-to-g-memdup2-now/5538 --- src/modules/sni/item.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/sni/item.cpp b/src/modules/sni/item.cpp index 991ccc4..917a92a 100644 --- a/src/modules/sni/item.cpp +++ b/src/modules/sni/item.cpp @@ -287,7 +287,7 @@ Glib::RefPtr Item::extractPixBuf(GVariant* variant) { if (array != nullptr) { g_free(array); } - array = static_cast(g_memdup(data, size)); + array = static_cast(g_memdup2(data, size)); lwidth = width; lheight = height; } From 9d9f95976926d5817837d03344b9506d700cee16 Mon Sep 17 00:00:00 2001 From: Ciaran Downey Date: Wed, 25 Aug 2021 14:47:51 -0700 Subject: [PATCH 10/61] Switch network module to read /proc/net/dev This fixes issue #610 by reading bandwidth usage per-interface from /proc/net/dev instead of globally via /proc/net/netstat. It supports the same matching logic as elsewhere, so setting interface to '*' should display the same sum-total bandwidth usage as the previous implementation. --- include/modules/network.hpp | 1 + src/modules/network.cpp | 168 +++++++++++++++++------------------- 2 files changed, 79 insertions(+), 90 deletions(-) diff --git a/include/modules/network.hpp b/include/modules/network.hpp index 009ae5a..183c9e2 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -43,6 +43,7 @@ class Network : public ALabel { const std::string getNetworkState() const; void clearIface(); bool wildcardMatch(const std::string& pattern, const std::string& text) const; + std::optional> readBandwidthUsage(); int ifid_; sa_family_t family_; diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 7d0f638..22b9f71 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -1,87 +1,79 @@ -#include "modules/network.hpp" +#include #include #include -#include -#include + #include +#include +#include #include + +#include "modules/network.hpp" #include "util/format.hpp" #ifdef WANT_RFKILL #include "util/rfkill.hpp" #endif namespace { - using namespace waybar::util; - -constexpr const char *NETSTAT_FILE = - "/proc/net/netstat"; // std::ifstream does not take std::string_view as param -constexpr std::string_view BANDWIDTH_CATEGORY = "IpExt"; -constexpr std::string_view BANDWIDTH_DOWN_TOTAL_KEY = "InOctets"; -constexpr std::string_view BANDWIDTH_UP_TOTAL_KEY = "OutOctets"; constexpr const char *DEFAULT_FORMAT = "{ifname}"; - -std::ifstream netstat(NETSTAT_FILE); -std::optional read_netstat(std::string_view category, std::string_view key) { - if (!netstat) { - spdlog::warn("Failed to open netstat file {}", NETSTAT_FILE); - return {}; - } - netstat.seekg(std::ios_base::beg); - - // finding corresponding line (category) - // looks into the file for the first line starting by the 'category' string - auto starts_with = [](const std::string &str, std::string_view start) { - return start == std::string_view{str.data(), std::min(str.size(), start.size())}; - }; - - std::string read; - while (std::getline(netstat, read) && !starts_with(read, category)) - ; - if (!starts_with(read, category)) { - spdlog::warn("Category '{}' not found in netstat file {}", category, NETSTAT_FILE); - return {}; - } - - // finding corresponding column (key) - // looks into the fetched line for the first word (space separated) equal to 'key' - int index = 0; - auto r_it = read.begin(); - auto k_it = key.begin(); - while (k_it != key.end() && r_it != read.end()) { - if (*r_it != *k_it) { - r_it = std::find(r_it, read.end(), ' '); - if (r_it != read.end()) { - ++r_it; - } - k_it = key.begin(); - ++index; - } else { - ++r_it; - ++k_it; - } - } - - if (r_it == read.end() && k_it != key.end()) { - spdlog::warn( - "Key '{}' not found in category '{}' of netstat file {}", key, category, NETSTAT_FILE); - return {}; - } - - // finally accessing value - // accesses the line right under the fetched one - std::getline(netstat, read); - assert(starts_with(read, category)); - std::istringstream iss(read); - while (index--) { - std::getline(iss, read, ' '); - } - unsigned long long value; - iss >> value; - return value; -} } // namespace +constexpr const char *NETDEV_FILE = + "/proc/net/dev"; // std::ifstream does not take std::string_view as param +std::optional> +waybar::modules::Network::readBandwidthUsage() { + std::ifstream netdev(NETDEV_FILE); + if (!netdev) { + spdlog::warn("Failed to open netdev file {}", NETDEV_FILE); + return {}; + } + + // skip the headers + std::string line; + std::getline(netdev, line); + std::getline(netdev, line); + if (!netdev) { + spdlog::warn("Unexpectedly short netdev file {}", NETDEV_FILE); + return {}; + } + + unsigned long long receivedBytes = 0ull; + unsigned long long transmittedBytes = 0ull; + for (std::getline(netdev, line); netdev; std::getline(netdev, line)) { + std::istringstream iss(line); + + std::string ifacename; + iss >> ifacename; // ifacename contains "eth0:" + ifacename.pop_back(); // remove trailing ':' + if (!checkInterface(ifacename)) { + continue; + } + + // The rest of the line consists of whitespace separated counts divided + // into two groups (receive and transmit). The first column in each group + // is bytes, which is the only one we care about. + unsigned long long r = 0ull; + unsigned long long t = 0ull; + // Read received bytes + iss >> r; + // Skip all the other columns in the received group + for (int colsToSkip = 7; colsToSkip > 0; colsToSkip--) { + // skip whitespace between columns + while (iss.peek() == ' ') { iss.ignore(); } + // skip the irrelevant column + while (iss.peek() != ' ') { iss.ignore(); } + } + // Read transmit bytes + iss >> t; + spdlog::trace("read r={}, t={}, iface={}", r, t, ifacename); + + receivedBytes += r; + transmittedBytes += t; + } + + return {{receivedBytes, transmittedBytes}}; +} + waybar::modules::Network::Network(const std::string &id, const Json::Value &config) : ALabel(config, "network", id, DEFAULT_FORMAT, 60), ifid_(-1), @@ -106,17 +98,12 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf // the module start with no text, but the the event_box_ is shown. label_.set_markup(""); - auto down_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_DOWN_TOTAL_KEY); - auto up_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_UP_TOTAL_KEY); - if (down_octets) { - bandwidth_down_total_ = *down_octets; + auto bandwidth = readBandwidthUsage(); + if (bandwidth.has_value()) { + bandwidth_down_total_ = (*bandwidth).first; + bandwidth_up_total_ = (*bandwidth).second; } else { bandwidth_down_total_ = 0; - } - - if (up_octets) { - bandwidth_up_total_ = *up_octets; - } else { bandwidth_up_total_ = 0; } @@ -303,20 +290,21 @@ const std::string waybar::modules::Network::getNetworkState() const { auto waybar::modules::Network::update() -> void { std::lock_guard lock(mutex_); std::string tooltip_format; - auto down_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_DOWN_TOTAL_KEY); - auto up_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_UP_TOTAL_KEY); - unsigned long long bandwidth_down = 0; - if (down_octets) { - bandwidth_down = *down_octets - bandwidth_down_total_; - bandwidth_down_total_ = *down_octets; + auto bandwidth = readBandwidthUsage(); + auto bandwidth_down = 0ull; + auto bandwidth_up = 0ull; + if (bandwidth.has_value()) { + auto down_octets = (*bandwidth).first; + auto up_octets = (*bandwidth).second; + + bandwidth_down = down_octets - bandwidth_down_total_; + bandwidth_down_total_ = down_octets; + + bandwidth_up = up_octets - bandwidth_up_total_; + bandwidth_up_total_ = up_octets; } - unsigned long long bandwidth_up = 0; - if (up_octets) { - bandwidth_up = *up_octets - bandwidth_up_total_; - bandwidth_up_total_ = *up_octets; - } if (!alt_) { auto state = getNetworkState(); if (!state_.empty() && label_.get_style_context()->has_class(state_)) { From 5186dd27e64b00b19736a2fa3bd6b325c4fcd555 Mon Sep 17 00:00:00 2001 From: Ciaran Downey Date: Thu, 26 Aug 2021 11:30:06 -0700 Subject: [PATCH 11/61] Use while (getline) instead of a for loop Also make the comments surrounding the /proc/net/dev parsing clearer and remove the apparently redundant "is the netdev file still good?" check. --- src/modules/network.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 22b9f71..5818f02 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -28,18 +28,14 @@ waybar::modules::Network::readBandwidthUsage() { return {}; } - // skip the headers std::string line; + // skip the headers (first two lines) std::getline(netdev, line); std::getline(netdev, line); - if (!netdev) { - spdlog::warn("Unexpectedly short netdev file {}", NETDEV_FILE); - return {}; - } unsigned long long receivedBytes = 0ull; unsigned long long transmittedBytes = 0ull; - for (std::getline(netdev, line); netdev; std::getline(netdev, line)) { + while (std::getline(netdev, line)) { std::istringstream iss(line); std::string ifacename; @@ -50,8 +46,11 @@ waybar::modules::Network::readBandwidthUsage() { } // The rest of the line consists of whitespace separated counts divided - // into two groups (receive and transmit). The first column in each group - // is bytes, which is the only one we care about. + // into two groups (receive and transmit). Each group has the following + // columns: bytes, packets, errs, drop, fifo, frame, compressed, multicast + // + // We only care about the bytes count, so we'll just ignore the 7 other + // columns. unsigned long long r = 0ull; unsigned long long t = 0ull; // Read received bytes @@ -65,7 +64,6 @@ waybar::modules::Network::readBandwidthUsage() { } // Read transmit bytes iss >> t; - spdlog::trace("read r={}, t={}, iface={}", r, t, ifacename); receivedBytes += r; transmittedBytes += t; From 4f76c9bd43dd7ff8108ffe81c690fe3e6232ee6a Mon Sep 17 00:00:00 2001 From: Michael Swiger Date: Sun, 29 Aug 2021 13:11:04 -0700 Subject: [PATCH 12/61] Only use g_memdup2 for glib >= 2.68 --- src/modules/sni/item.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/sni/item.cpp b/src/modules/sni/item.cpp index 917a92a..d9748ed 100644 --- a/src/modules/sni/item.cpp +++ b/src/modules/sni/item.cpp @@ -287,7 +287,11 @@ Glib::RefPtr Item::extractPixBuf(GVariant* variant) { if (array != nullptr) { g_free(array); } +#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 68 array = static_cast(g_memdup2(data, size)); +#else + array = static_cast(g_memdup(data, size)); +#endif lwidth = width; lheight = height; } From aacd0fcc652f36901632a252bd91e7f0c5f73cf1 Mon Sep 17 00:00:00 2001 From: Matan1x Date: Wed, 8 Sep 2021 17:12:30 +0300 Subject: [PATCH 13/61] round brightness --- src/modules/backlight.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/backlight.cpp b/src/modules/backlight.cpp index 3ebc6e7..fcd668c 100644 --- a/src/modules/backlight.cpp +++ b/src/modules/backlight.cpp @@ -173,7 +173,7 @@ auto waybar::modules::Backlight::update() -> void { return; } - const auto percent = best->get_max() == 0 ? 100 : best->get_actual() * 100 / best->get_max(); + const uint8_t percent = best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max()); label_.set_markup(fmt::format( format_, fmt::arg("percent", std::to_string(percent)), fmt::arg("icon", getIcon(percent)))); getState(percent); From 2c380a53caabfc831d832985becb95b69d202eed Mon Sep 17 00:00:00 2001 From: Rolf Vidar Mazunki Hoksaas Date: Thu, 9 Sep 2021 20:05:18 +0200 Subject: [PATCH 14/61] added support for the {gwaddr} variable --- Makefile | 3 +++ include/modules/network.hpp | 1 + man/waybar-network.5.scd | 2 ++ src/modules/network.cpp | 10 +++++++++- 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d7182c1..ccf0507 100644 --- a/Makefile +++ b/Makefile @@ -16,5 +16,8 @@ install: build run: build ./build/waybar +debug-run: build + ./build/waybar --log-level debug + clean: rm -rf build diff --git a/include/modules/network.hpp b/include/modules/network.hpp index 009ae5a..ad28520 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -67,6 +67,7 @@ class Network : public ALabel { bool carrier_; std::string ifname_; std::string ipaddr_; + std::string gwaddr_; std::string netmask_; int cidr_; int32_t signal_strength_dbm_; diff --git a/man/waybar-network.5.scd b/man/waybar-network.5.scd index f274881..f8bdd65 100644 --- a/man/waybar-network.5.scd +++ b/man/waybar-network.5.scd @@ -131,6 +131,8 @@ Addressed by *network* *{ipaddr}*: The first IP of the interface. +*{gwaddr}*: The default gateway for the interface + *{netmask}*: The subnetmask corresponding to the IP. *{cidr}*: The subnetmask corresponding to the IP in CIDR notation. diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 7d0f638..a45f2b8 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -348,6 +348,7 @@ auto waybar::modules::Network::update() -> void { fmt::arg("ifname", ifname_), fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), + fmt::arg("gwaddr", gwaddr_), fmt::arg("cidr", cidr_), fmt::arg("frequency", frequency_), fmt::arg("icon", getIcon(signal_strength_, state_)), @@ -376,6 +377,7 @@ auto waybar::modules::Network::update() -> void { fmt::arg("ifname", ifname_), fmt::arg("netmask", netmask_), fmt::arg("ipaddr", ipaddr_), + fmt::arg("gwaddr", gwaddr_), fmt::arg("cidr", cidr_), fmt::arg("frequency", frequency_), fmt::arg("icon", getIcon(signal_strength_, state_)), @@ -409,6 +411,7 @@ void waybar::modules::Network::clearIface() { ifname_.clear(); essid_.clear(); ipaddr_.clear(); + gwaddr_.clear(); netmask_.clear(); carrier_ = false; cidr_ = 0; @@ -581,6 +584,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { break; } + char temp_gw_addr[INET6_ADDRSTRLEN]; case RTM_DELROUTE: is_del_event = true; case RTM_NEWROUTE: { @@ -595,6 +599,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { int temp_idx = -1; uint32_t priority = 0; + /* Find the message(s) concerting the main routing table, each message * corresponds to a single routing table entry. */ @@ -612,9 +617,10 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { case RTA_GATEWAY: /* The gateway of the route. * - * If someone every needs to figure out the gateway address as well, + * If someone ever needs to figure out the gateway address as well, * it's here as the attribute payload. */ + inet_ntop(net->family_, RTA_DATA(attr), temp_gw_addr, sizeof(temp_gw_addr)); has_gateway = true; break; case RTA_DST: { @@ -655,6 +661,8 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { net->clearIface(); net->ifid_ = temp_idx; net->route_priority = priority; + net->gwaddr_ = temp_gw_addr; + spdlog::debug("netwok: gateway {}", net->gwaddr_); spdlog::debug("network: new default route via if{} metric {}", temp_idx, priority); From 95ecff05511f71fc542429059b843ecd369854ef Mon Sep 17 00:00:00 2001 From: Rolf Vidar Mazunki Hoksaas Date: Thu, 9 Sep 2021 20:12:20 +0200 Subject: [PATCH 15/61] added example tooltip usage --- resources/config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/resources/config b/resources/config index 87f24c0..b315721 100644 --- a/resources/config +++ b/resources/config @@ -117,7 +117,8 @@ "network": { // "interface": "wlp2*", // (Optional) To force the use of this interface "format-wifi": "{essid} ({signalStrength}%) ", - "format-ethernet": "{ifname}: {ipaddr}/{cidr} ", + "format-ethernet": "{ipaddr}/{cidr} ", + "tooltip-format": "{ifname} via {gwaddr} ", "format-linked": "{ifname} (No IP) ", "format-disconnected": "Disconnected ⚠", "format-alt": "{ifname}: {ipaddr}/{cidr}" From b377520a38dd0a2aa68301039e9f649d98a94f5f Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 13 Aug 2021 06:08:27 -0700 Subject: [PATCH 16/61] refactor(client): extract config handling into a new class --- include/client.hpp | 14 +--- include/config.hpp | 31 +++++++++ meson.build | 1 + src/client.cpp | 148 +--------------------------------------- src/config.cpp | 166 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 204 insertions(+), 156 deletions(-) create mode 100644 include/config.hpp create mode 100644 src/config.cpp diff --git a/include/client.hpp b/include/client.hpp index e7fa1db..e68e4ad 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -3,11 +3,10 @@ #include #include #include -#include #include -#include #include "bar.hpp" +#include "config.hpp" struct zwlr_layer_shell_v1; struct zwp_idle_inhibitor_v1; @@ -32,15 +31,8 @@ class Client { private: Client() = default; - std::tuple getConfigs(const std::string &config, - const std::string &style) const; - void bindInterfaces(); - const std::string getValidPath(const std::vector &paths) const; + void bindInterfaces(); void handleOutput(struct waybar_output &output); - bool isValidOutput(const Json::Value &config, struct waybar_output &output); - auto setupConfig(const std::string &config_file, int depth) -> void; - auto resolveConfigIncludes(Json::Value &config, int depth) -> void; - auto mergeConfig(Json::Value &a_config_, Json::Value &b_config_) -> void; auto setupCss(const std::string &css_file) -> void; struct waybar_output & getOutput(void *); std::vector getOutputConfigs(struct waybar_output &output); @@ -55,7 +47,7 @@ class Client { void handleMonitorRemoved(Glib::RefPtr monitor); void handleDeferredMonitorRemoval(Glib::RefPtr monitor); - Json::Value config_; + Config config_; Glib::RefPtr style_context_; Glib::RefPtr css_provider_; std::list outputs_; diff --git a/include/config.hpp b/include/config.hpp new file mode 100644 index 0000000..bb7b906 --- /dev/null +++ b/include/config.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include + +namespace waybar { + +class Config { + public: + Config() = default; + + void load(const std::string &config, const std::string &style); + + const std::string &getStyle() { return css_file_; } + + Json::Value &getConfig() { return config_; } + + std::vector getOutputConfigs(const std::string &name, const std::string &identifier); + + private: + void setupConfig(const std::string &config_file, int depth); + void resolveConfigIncludes(Json::Value &config, int depth); + void mergeConfig(Json::Value &a_config_, Json::Value &b_config_); + + std::string config_file_; + std::string css_file_; + + Json::Value config_; +}; +} // namespace waybar diff --git a/meson.build b/meson.build index 835b70e..641607d 100644 --- a/meson.build +++ b/meson.build @@ -149,6 +149,7 @@ src_files = files( 'src/main.cpp', 'src/bar.cpp', 'src/client.cpp', + 'src/config.cpp', 'src/util/ustring_clen.cpp' ) diff --git a/src/client.cpp b/src/client.cpp index ff6e7bf..b50faff 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -3,12 +3,10 @@ #include #include -#include #include #include "idle-inhibit-unstable-v1-client-protocol.h" #include "util/clara.hpp" -#include "util/json.hpp" #include "wlr-layer-shell-unstable-v1-client-protocol.h" waybar::Client *waybar::Client::inst() { @@ -16,23 +14,6 @@ waybar::Client *waybar::Client::inst() { return c; } -const std::string waybar::Client::getValidPath(const std::vector &paths) const { - wordexp_t p; - - for (const std::string &path : paths) { - if (wordexp(path.c_str(), &p, 0) == 0) { - if (access(*p.we_wordv, F_OK) == 0) { - std::string result = *p.we_wordv; - wordfree(&p); - return result; - } - wordfree(&p); - } - } - - return std::string(); -} - void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { auto client = static_cast(data); @@ -70,29 +51,6 @@ void waybar::Client::handleOutput(struct waybar_output &output) { zxdg_output_v1_add_listener(output.xdg_output.get(), &xdgOutputListener, &output); } -bool waybar::Client::isValidOutput(const Json::Value &config, struct waybar_output &output) { - if (config["output"].isArray()) { - for (auto const &output_conf : config["output"]) { - if (output_conf.isString() && - (output_conf.asString() == output.name || output_conf.asString() == output.identifier)) { - return true; - } - } - return false; - } else if (config["output"].isString()) { - auto config_output = config["output"].asString(); - if (!config_output.empty()) { - if (config_output.substr(0, 1) == "!") { - return config_output.substr(1) != output.name && - config_output.substr(1) != output.identifier; - } - return config_output == output.name || config_output == output.identifier; - } - } - - return true; -} - struct waybar::waybar_output &waybar::Client::getOutput(void *addr) { auto it = std::find_if( outputs_.begin(), outputs_.end(), [&addr](const auto &output) { return &output == addr; }); @@ -103,17 +61,7 @@ struct waybar::waybar_output &waybar::Client::getOutput(void *addr) { } std::vector waybar::Client::getOutputConfigs(struct waybar_output &output) { - std::vector configs; - if (config_.isArray()) { - for (auto const &config : config_) { - if (config.isObject() && isValidOutput(config, output)) { - configs.push_back(config); - } - } - } else if (isValidOutput(config_, output)) { - configs.push_back(config_); - } - return configs; + return config_.getOutputConfigs(output.name, output.identifier); } void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_output*/) { @@ -203,95 +151,6 @@ void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr mon outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; }); } -std::tuple waybar::Client::getConfigs( - const std::string &config, const std::string &style) const { - auto config_file = config.empty() ? getValidPath({ - "$XDG_CONFIG_HOME/waybar/config", - "$XDG_CONFIG_HOME/waybar/config.jsonc", - "$HOME/.config/waybar/config", - "$HOME/.config/waybar/config.jsonc", - "$HOME/waybar/config", - "$HOME/waybar/config.jsonc", - "/etc/xdg/waybar/config", - "/etc/xdg/waybar/config.jsonc", - SYSCONFDIR "/xdg/waybar/config", - "./resources/config", - }) - : config; - auto css_file = style.empty() ? getValidPath({ - "$XDG_CONFIG_HOME/waybar/style.css", - "$HOME/.config/waybar/style.css", - "$HOME/waybar/style.css", - "/etc/xdg/waybar/style.css", - SYSCONFDIR "/xdg/waybar/style.css", - "./resources/style.css", - }) - : style; - if (css_file.empty() || config_file.empty()) { - throw std::runtime_error("Missing required resources files"); - } - spdlog::info("Resources files: {}, {}", config_file, css_file); - return {config_file, css_file}; -} - -auto waybar::Client::setupConfig(const std::string &config_file, int depth) -> void { - if (depth > 100) { - throw std::runtime_error("Aborting due to likely recursive include in config files"); - } - std::ifstream file(config_file); - if (!file.is_open()) { - throw std::runtime_error("Can't open config file"); - } - std::string str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - util::JsonParser parser; - Json::Value tmp_config_ = parser.parse(str); - if (tmp_config_.isArray()) { - for (auto &config_part : tmp_config_) { - resolveConfigIncludes(config_part, depth); - } - } else { - resolveConfigIncludes(tmp_config_, depth); - } - mergeConfig(config_, tmp_config_); -} - -auto waybar::Client::resolveConfigIncludes(Json::Value &config, int depth) -> void { - Json::Value includes = config["include"]; - if (includes.isArray()) { - for (const auto &include : includes) { - spdlog::info("Including resource file: {}", include.asString()); - setupConfig(getValidPath({include.asString()}), ++depth); - } - } else if (includes.isString()) { - spdlog::info("Including resource file: {}", includes.asString()); - setupConfig(getValidPath({includes.asString()}), ++depth); - } -} - -auto waybar::Client::mergeConfig(Json::Value &a_config_, Json::Value &b_config_) -> void { - if (!a_config_) { - // For the first config - a_config_ = b_config_; - } else if (a_config_.isObject() && b_config_.isObject()) { - for (const auto &key : b_config_.getMemberNames()) { - if (a_config_[key].isObject() && b_config_[key].isObject()) { - mergeConfig(a_config_[key], b_config_[key]); - } else { - a_config_[key] = b_config_[key]; - } - } - } else if (a_config_.isArray() && b_config_.isArray()) { - // This can happen only on the top-level array of a multi-bar config - for (Json::Value::ArrayIndex i = 0; i < b_config_.size(); i++) { - if (a_config_[i].isObject() && b_config_[i].isObject()) { - mergeConfig(a_config_[i], b_config_[i]); - } - } - } else { - spdlog::error("Cannot merge config, conflicting or invalid JSON types"); - } -} - auto waybar::Client::setupCss(const std::string &css_file) -> void { css_provider_ = Gtk::CssProvider::create(); style_context_ = Gtk::StyleContext::create(); @@ -367,9 +226,8 @@ int waybar::Client::main(int argc, char *argv[]) { throw std::runtime_error("Bar need to run under Wayland"); } wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj()); - auto [config_file, css_file] = getConfigs(config, style); - setupConfig(config_file, 0); - setupCss(css_file); + config_.load(config, style); + setupCss(config_.getStyle()); bindInterfaces(); gtk_app->hold(); gtk_app->run(); diff --git a/src/config.cpp b/src/config.cpp new file mode 100644 index 0000000..6c7fa17 --- /dev/null +++ b/src/config.cpp @@ -0,0 +1,166 @@ +#include "config.hpp" + +#include +#include +#include + +#include +#include + +#include "util/json.hpp" + +#ifndef SYSCONFDIR +#define SYSCONFDIR "/etc" +#endif + +namespace waybar { + +const std::string getValidPath(const std::vector &paths) { + wordexp_t p; + + for (const std::string &path : paths) { + if (wordexp(path.c_str(), &p, 0) == 0) { + if (access(*p.we_wordv, F_OK) == 0) { + std::string result = *p.we_wordv; + wordfree(&p); + return result; + } + wordfree(&p); + } + } + + return std::string(); +} + +std::tuple getConfigs(const std::string &config, + const std::string &style) { + auto config_file = config.empty() ? getValidPath({ + "$XDG_CONFIG_HOME/waybar/config", + "$XDG_CONFIG_HOME/waybar/config.jsonc", + "$HOME/.config/waybar/config", + "$HOME/.config/waybar/config.jsonc", + "$HOME/waybar/config", + "$HOME/waybar/config.jsonc", + "/etc/xdg/waybar/config", + "/etc/xdg/waybar/config.jsonc", + SYSCONFDIR "/xdg/waybar/config", + "./resources/config", + }) + : config; + auto css_file = style.empty() ? getValidPath({ + "$XDG_CONFIG_HOME/waybar/style.css", + "$HOME/.config/waybar/style.css", + "$HOME/waybar/style.css", + "/etc/xdg/waybar/style.css", + SYSCONFDIR "/xdg/waybar/style.css", + "./resources/style.css", + }) + : style; + if (css_file.empty() || config_file.empty()) { + throw std::runtime_error("Missing required resources files"); + } + spdlog::info("Resources files: {}, {}", config_file, css_file); + return {config_file, css_file}; +} + +void Config::setupConfig(const std::string &config_file, int depth) { + if (depth > 100) { + throw std::runtime_error("Aborting due to likely recursive include in config files"); + } + std::ifstream file(config_file); + if (!file.is_open()) { + throw std::runtime_error("Can't open config file"); + } + std::string str((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + util::JsonParser parser; + Json::Value tmp_config = parser.parse(str); + if (tmp_config.isArray()) { + for (auto &config_part : tmp_config) { + resolveConfigIncludes(config_part, depth); + } + } else { + resolveConfigIncludes(tmp_config, depth); + } + mergeConfig(config_, tmp_config); +} + +void Config::resolveConfigIncludes(Json::Value &config, int depth) { + Json::Value includes = config["include"]; + if (includes.isArray()) { + for (const auto &include : includes) { + spdlog::info("Including resource file: {}", include.asString()); + setupConfig(getValidPath({include.asString()}), ++depth); + } + } else if (includes.isString()) { + spdlog::info("Including resource file: {}", includes.asString()); + setupConfig(getValidPath({includes.asString()}), ++depth); + } +} + +void Config::mergeConfig(Json::Value &a_config_, Json::Value &b_config_) { + if (!a_config_) { + // For the first config + a_config_ = b_config_; + } else if (a_config_.isObject() && b_config_.isObject()) { + for (const auto &key : b_config_.getMemberNames()) { + if (a_config_[key].isObject() && b_config_[key].isObject()) { + mergeConfig(a_config_[key], b_config_[key]); + } else { + a_config_[key] = b_config_[key]; + } + } + } else if (a_config_.isArray() && b_config_.isArray()) { + // This can happen only on the top-level array of a multi-bar config + for (Json::Value::ArrayIndex i = 0; i < b_config_.size(); i++) { + if (a_config_[i].isObject() && b_config_[i].isObject()) { + mergeConfig(a_config_[i], b_config_[i]); + } + } + } else { + spdlog::error("Cannot merge config, conflicting or invalid JSON types"); + } +} +bool isValidOutput(const Json::Value &config, const std::string &name, + const std::string &identifier) { + if (config["output"].isArray()) { + for (auto const &output_conf : config["output"]) { + if (output_conf.isString() && + (output_conf.asString() == name || output_conf.asString() == identifier)) { + return true; + } + } + return false; + } else if (config["output"].isString()) { + auto config_output = config["output"].asString(); + if (!config_output.empty()) { + if (config_output.substr(0, 1) == "!") { + return config_output.substr(1) != name && config_output.substr(1) != identifier; + } + return config_output == name || config_output == identifier; + } + } + + return true; +} + +void Config::load(const std::string &config, const std::string &style) { + std::tie(config_file_, css_file_) = getConfigs(config, style); + setupConfig(config_file_, 0); +} + +std::vector Config::getOutputConfigs(const std::string &name, + const std::string &identifier) { + std::vector configs; + if (config_.isArray()) { + for (auto const &config : config_) { + if (config.isObject() && isValidOutput(config, name, identifier)) { + configs.push_back(config); + } + } + } else if (isValidOutput(config_, name, identifier)) { + configs.push_back(config_); + } + return configs; +} + +} // namespace waybar From 4fff2eaaa0851c559fabd5b04ef08de8b9604fe1 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 15 Sep 2021 21:24:45 +0700 Subject: [PATCH 17/61] refactor(client): change config visibility to public --- include/client.hpp | 2 +- src/client.cpp | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/client.hpp b/include/client.hpp index e68e4ad..1124cbb 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -28,6 +28,7 @@ class Client { struct zxdg_output_manager_v1 * xdg_output_manager = nullptr; struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr; std::vector> bars; + Config config; private: Client() = default; @@ -47,7 +48,6 @@ class Client { void handleMonitorRemoved(Glib::RefPtr monitor); void handleDeferredMonitorRemoval(Glib::RefPtr monitor); - Config config_; Glib::RefPtr style_context_; Glib::RefPtr css_provider_; std::list outputs_; diff --git a/src/client.cpp b/src/client.cpp index b50faff..0764883 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -61,7 +61,7 @@ struct waybar::waybar_output &waybar::Client::getOutput(void *addr) { } std::vector waybar::Client::getOutputConfigs(struct waybar_output &output) { - return config_.getOutputConfigs(output.name, output.identifier); + return config.getOutputConfigs(output.name, output.identifier); } void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_output*/) { @@ -188,14 +188,14 @@ void waybar::Client::bindInterfaces() { int waybar::Client::main(int argc, char *argv[]) { bool show_help = false; bool show_version = false; - std::string config; - std::string style; + std::string config_opt; + std::string style_opt; std::string bar_id; std::string log_level; auto cli = clara::detail::Help(show_help) | clara::detail::Opt(show_version)["-v"]["--version"]("Show version") | - clara::detail::Opt(config, "config")["-c"]["--config"]("Config path") | - clara::detail::Opt(style, "style")["-s"]["--style"]("Style path") | + clara::detail::Opt(config_opt, "config")["-c"]["--config"]("Config path") | + clara::detail::Opt(style_opt, "style")["-s"]["--style"]("Style path") | clara::detail::Opt( log_level, "trace|debug|info|warning|error|critical|off")["-l"]["--log-level"]("Log level") | @@ -226,8 +226,8 @@ int waybar::Client::main(int argc, char *argv[]) { throw std::runtime_error("Bar need to run under Wayland"); } wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj()); - config_.load(config, style); - setupCss(config_.getStyle()); + config.load(config_opt, style_opt); + setupCss(config.getStyle()); bindInterfaces(); gtk_app->hold(); gtk_app->run(); From 1f7d399b8edd3ea76612e674ee1b3fb1a365e483 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 13 Aug 2021 07:19:47 -0700 Subject: [PATCH 18/61] refactor(config): remove style handling from Config --- include/client.hpp | 1 + include/config.hpp | 16 ++++++--- src/client.cpp | 14 ++++++-- src/config.cpp | 84 ++++++++++++++++++++++------------------------ 4 files changed, 66 insertions(+), 49 deletions(-) diff --git a/include/client.hpp b/include/client.hpp index 1124cbb..bd80d0b 100644 --- a/include/client.hpp +++ b/include/client.hpp @@ -32,6 +32,7 @@ class Client { private: Client() = default; + const std::string getStyle(const std::string &style); void bindInterfaces(); void handleOutput(struct waybar_output &output); auto setupCss(const std::string &css_file) -> void; diff --git a/include/config.hpp b/include/config.hpp index bb7b906..25b78ab 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -2,17 +2,26 @@ #include +#include #include +#ifndef SYSCONFDIR +#define SYSCONFDIR "/etc" +#endif + namespace waybar { class Config { public: + static const std::vector CONFIG_DIRS; + + /* Try to find any of provided names in the supported set of config directories */ + static std::optional findConfigPath( + const std::vector &names, const std::vector &dirs = CONFIG_DIRS); + Config() = default; - void load(const std::string &config, const std::string &style); - - const std::string &getStyle() { return css_file_; } + void load(const std::string &config); Json::Value &getConfig() { return config_; } @@ -24,7 +33,6 @@ class Config { void mergeConfig(Json::Value &a_config_, Json::Value &b_config_); std::string config_file_; - std::string css_file_; Json::Value config_; }; diff --git a/src/client.cpp b/src/client.cpp index 0764883..95f5a29 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -151,6 +151,15 @@ void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr mon outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; }); } +const std::string waybar::Client::getStyle(const std::string &style) { + auto css_file = style.empty() ? Config::findConfigPath({"style.css"}) : style; + if (!css_file) { + throw std::runtime_error("Missing required resource files"); + } + spdlog::info("Using CSS file {}", css_file.value()); + return css_file.value(); +}; + auto waybar::Client::setupCss(const std::string &css_file) -> void { css_provider_ = Gtk::CssProvider::create(); style_context_ = Gtk::StyleContext::create(); @@ -226,8 +235,9 @@ int waybar::Client::main(int argc, char *argv[]) { throw std::runtime_error("Bar need to run under Wayland"); } wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj()); - config.load(config_opt, style_opt); - setupCss(config.getStyle()); + config.load(config_opt); + auto css_file = getStyle(style_opt); + setupCss(css_file); bindInterfaces(); gtk_app->hold(); gtk_app->run(); diff --git a/src/config.cpp b/src/config.cpp index 6c7fa17..ed7168d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -9,58 +9,51 @@ #include "util/json.hpp" -#ifndef SYSCONFDIR -#define SYSCONFDIR "/etc" -#endif - namespace waybar { -const std::string getValidPath(const std::vector &paths) { - wordexp_t p; +const std::vector Config::CONFIG_DIRS = { + "$XDG_CONFIG_HOME/waybar/", + "$HOME/.config/waybar/", + "$HOME/waybar/", + "/etc/xdg/waybar/", + SYSCONFDIR "/xdg/waybar/", + "./resources/", +}; - for (const std::string &path : paths) { - if (wordexp(path.c_str(), &p, 0) == 0) { - if (access(*p.we_wordv, F_OK) == 0) { - std::string result = *p.we_wordv; - wordfree(&p); - return result; - } +std::optional tryExpandPath(const std::string &path) { + wordexp_t p; + if (wordexp(path.c_str(), &p, 0) == 0) { + if (access(*p.we_wordv, F_OK) == 0) { + std::string result = *p.we_wordv; wordfree(&p); + return result; + } + wordfree(&p); + } + return std::nullopt; +} + +const std::string getValidPath(const std::vector &paths) { + for (const std::string &path : paths) { + if (auto res = tryExpandPath(path); res) { + return res.value(); } } return std::string(); } -std::tuple getConfigs(const std::string &config, - const std::string &style) { - auto config_file = config.empty() ? getValidPath({ - "$XDG_CONFIG_HOME/waybar/config", - "$XDG_CONFIG_HOME/waybar/config.jsonc", - "$HOME/.config/waybar/config", - "$HOME/.config/waybar/config.jsonc", - "$HOME/waybar/config", - "$HOME/waybar/config.jsonc", - "/etc/xdg/waybar/config", - "/etc/xdg/waybar/config.jsonc", - SYSCONFDIR "/xdg/waybar/config", - "./resources/config", - }) - : config; - auto css_file = style.empty() ? getValidPath({ - "$XDG_CONFIG_HOME/waybar/style.css", - "$HOME/.config/waybar/style.css", - "$HOME/waybar/style.css", - "/etc/xdg/waybar/style.css", - SYSCONFDIR "/xdg/waybar/style.css", - "./resources/style.css", - }) - : style; - if (css_file.empty() || config_file.empty()) { - throw std::runtime_error("Missing required resources files"); +std::optional Config::findConfigPath(const std::vector &names, + const std::vector &dirs) { + std::vector paths; + for (const auto &dir : dirs) { + for (const auto &name : names) { + if (auto res = tryExpandPath(dir + name); res) { + return res; + } + } } - spdlog::info("Resources files: {}, {}", config_file, css_file); - return {config_file, css_file}; + return std::nullopt; } void Config::setupConfig(const std::string &config_file, int depth) { @@ -143,8 +136,13 @@ bool isValidOutput(const Json::Value &config, const std::string &name, return true; } -void Config::load(const std::string &config, const std::string &style) { - std::tie(config_file_, css_file_) = getConfigs(config, style); +void Config::load(const std::string &config) { + auto file = config.empty() ? findConfigPath({"config", "config.jsonc"}) : config; + if (!file) { + throw std::runtime_error("Missing required resource files"); + } + config_file_ = file.value(); + spdlog::info("Using configuration file {}", config_file_); setupConfig(config_file_, 0); } From 1f16d7955d7832e2fcdc3317d42034ac0c772dac Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 13 Aug 2021 08:19:12 -0700 Subject: [PATCH 19/61] refactor(config): drop getValidPath --- src/config.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index ed7168d..207e1bd 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -33,16 +33,6 @@ std::optional tryExpandPath(const std::string &path) { return std::nullopt; } -const std::string getValidPath(const std::vector &paths) { - for (const std::string &path : paths) { - if (auto res = tryExpandPath(path); res) { - return res.value(); - } - } - - return std::string(); -} - std::optional Config::findConfigPath(const std::vector &names, const std::vector &dirs) { std::vector paths; @@ -82,11 +72,11 @@ void Config::resolveConfigIncludes(Json::Value &config, int depth) { if (includes.isArray()) { for (const auto &include : includes) { spdlog::info("Including resource file: {}", include.asString()); - setupConfig(getValidPath({include.asString()}), ++depth); + setupConfig(tryExpandPath(include.asString()).value_or(""), ++depth); } } else if (includes.isString()) { spdlog::info("Including resource file: {}", includes.asString()); - setupConfig(getValidPath({includes.asString()}), ++depth); + setupConfig(tryExpandPath(includes.asString()).value_or(""), ++depth); } } From 6eba62f0600379f9d594dea1fa5c41024f55fe8e Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 13 Aug 2021 18:33:24 -0700 Subject: [PATCH 20/61] test: add build configs for catch2 --- meson.build | 9 +++++++++ meson_options.txt | 1 + subprojects/catch2.wrap | 12 ++++++++++++ test/config.cpp | 4 ++++ test/meson.build | 21 +++++++++++++++++++++ 5 files changed, 47 insertions(+) create mode 100644 subprojects/catch2.wrap create mode 100644 test/config.cpp create mode 100644 test/meson.build diff --git a/meson.build b/meson.build index 641607d..c09fbb6 100644 --- a/meson.build +++ b/meson.build @@ -360,6 +360,15 @@ if scdoc.found() endforeach endif +catch2 = dependency( + 'catch2', + fallback: ['catch2', 'catch2_dep'], + required: get_option('tests'), +) +if catch2.found() + subdir('test') +endif + clangtidy = find_program('clang-tidy', required: false) if clangtidy.found() diff --git a/meson_options.txt b/meson_options.txt index fefb3dc..81e4468 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,3 +10,4 @@ option('mpd', type: 'feature', value: 'auto', description: 'Enable support for t option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use gtk-layer-shell library for popups support') option('rfkill', type: 'feature', value: 'auto', description: 'Enable support for RFKILL') option('sndio', type: 'feature', value: 'auto', description: 'Enable support for sndio') +option('tests', type: 'feature', value: 'auto', description: 'Enable tests') diff --git a/subprojects/catch2.wrap b/subprojects/catch2.wrap new file mode 100644 index 0000000..356c406 --- /dev/null +++ b/subprojects/catch2.wrap @@ -0,0 +1,12 @@ +[wrap-file] +directory = Catch2-2.13.3 +source_url = https://github.com/catchorg/Catch2/archive/v2.13.3.zip +source_filename = Catch2-2.13.3.zip +source_hash = 1804feb72bc15c0856b4a43aa586c661af9c3685a75973b6a8fc0b950c7cfd13 +patch_url = https://github.com/mesonbuild/catch2/releases/download/2.13.3-2/catch2.zip +patch_filename = catch2-2.13.3-2-wrap.zip +patch_hash = 21b590ab8c65b593ad5ee8f8e5b822bf9877b2c2672f97fbb52459751053eadf + +[provide] +catch2 = catch2_dep + diff --git a/test/config.cpp b/test/config.cpp new file mode 100644 index 0000000..41180bb --- /dev/null +++ b/test/config.cpp @@ -0,0 +1,4 @@ +#define CATCH_CONFIG_MAIN +#include "config.hpp" + +#include diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000..85b9771 --- /dev/null +++ b/test/meson.build @@ -0,0 +1,21 @@ +test_inc = include_directories('../include') +test_dep = [ + catch2, + fmt, + jsoncpp, + spdlog, +] + +config_test = executable( + 'config_test', + 'config.cpp', + '../src/config.cpp', + dependencies: test_dep, + include_directories: test_inc, +) + +test( + 'Configuration test', + config_test, + workdir: meson.source_root(), +) From 9f3b34e4d9c47eae5c3a7179e70952d5c6ba3f61 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 13 Aug 2021 18:50:36 -0700 Subject: [PATCH 21/61] test: validate configuration load --- test/config.cpp | 74 ++++++++++++++++++++++++++++++++++++++ test/config/include-1.json | 6 ++++ test/config/include-2.json | 3 ++ test/config/include.json | 4 +++ test/config/multi.json | 25 +++++++++++++ test/config/simple.json | 5 +++ 6 files changed, 117 insertions(+) create mode 100644 test/config/include-1.json create mode 100644 test/config/include-2.json create mode 100644 test/config/include.json create mode 100644 test/config/multi.json create mode 100644 test/config/simple.json diff --git a/test/config.cpp b/test/config.cpp index 41180bb..78ea0e1 100644 --- a/test/config.cpp +++ b/test/config.cpp @@ -2,3 +2,77 @@ #include "config.hpp" #include + +TEST_CASE("Load simple config", "[config]") { + waybar::Config conf; + conf.load("test/config/simple.json"); + + SECTION("validate the config data") { + auto& data = conf.getConfig(); + REQUIRE(data["layer"].asString() == "top"); + REQUIRE(data["height"].asInt() == 30); + } + SECTION("select configs for configured output") { + auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0"); + REQUIRE(configs.size() == 1); + } + SECTION("select configs for missing output") { + auto configs = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1"); + REQUIRE(configs.empty()); + } +} + +TEST_CASE("Load config with multiple bars", "[config]") { + waybar::Config conf; + conf.load("test/config/multi.json"); + + SECTION("select multiple configs #1") { + auto data = conf.getOutputConfigs("DP-0", "Fake DisplayPort output #0"); + REQUIRE(data.size() == 3); + REQUIRE(data[0]["layer"].asString() == "bottom"); + REQUIRE(data[0]["height"].asInt() == 20); + REQUIRE(data[1]["layer"].asString() == "top"); + REQUIRE(data[1]["position"].asString() == "bottom"); + REQUIRE(data[1]["height"].asInt() == 21); + REQUIRE(data[2]["layer"].asString() == "overlay"); + REQUIRE(data[2]["position"].asString() == "right"); + REQUIRE(data[2]["height"].asInt() == 23); + } + SECTION("select multiple configs #2") { + auto data = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0"); + REQUIRE(data.size() == 2); + REQUIRE(data[0]["layer"].asString() == "bottom"); + REQUIRE(data[0]["height"].asInt() == 20); + REQUIRE(data[1]["layer"].asString() == "overlay"); + REQUIRE(data[1]["position"].asString() == "right"); + REQUIRE(data[1]["height"].asInt() == 23); + } + SECTION("select single config by output description") { + auto data = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1"); + REQUIRE(data.size() == 1); + REQUIRE(data[0]["layer"].asString() == "overlay"); + REQUIRE(data[0]["position"].asString() == "left"); + REQUIRE(data[0]["height"].asInt() == 22); + } +} + +TEST_CASE("Load simple config with include", "[config]") { + waybar::Config conf; + conf.load("test/config/include.json"); + + SECTION("validate the config data") { + auto& data = conf.getConfig(); + REQUIRE(data["layer"].asString() == "bottom"); + REQUIRE(data["height"].asInt() == 30); + // config override behavior: preserve value from the top config + REQUIRE(data["position"].asString() == "top"); + } + SECTION("select configs for configured output") { + auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0"); + REQUIRE(configs.size() == 1); + } + SECTION("select configs for missing output") { + auto configs = conf.getOutputConfigs("HDMI-1", "Fake HDMI output #1"); + REQUIRE(configs.empty()); + } +} diff --git a/test/config/include-1.json b/test/config/include-1.json new file mode 100644 index 0000000..853111c --- /dev/null +++ b/test/config/include-1.json @@ -0,0 +1,6 @@ +{ + "layer": "top", + "position": "bottom", + "height": 30, + "output": ["HDMI-0", "DP-0"] +} diff --git a/test/config/include-2.json b/test/config/include-2.json new file mode 100644 index 0000000..741194f --- /dev/null +++ b/test/config/include-2.json @@ -0,0 +1,3 @@ +{ + "layer": "bottom" +} diff --git a/test/config/include.json b/test/config/include.json new file mode 100644 index 0000000..098cae0 --- /dev/null +++ b/test/config/include.json @@ -0,0 +1,4 @@ +{ + "include": ["test/config/include-1.json", "test/config/include-2.json"], + "position": "top" +} diff --git a/test/config/multi.json b/test/config/multi.json new file mode 100644 index 0000000..ed43a39 --- /dev/null +++ b/test/config/multi.json @@ -0,0 +1,25 @@ +[ + { + "layer": "bottom", + "height": 20, + "output": ["HDMI-0", "DP-0"] + }, + { + "position": "bottom", + "layer": "top", + "height": 21, + "output": ["DP-0"] + }, + { + "position": "left", + "layer": "overlay", + "height": 22, + "output": "Fake HDMI output #1" + }, + { + "position": "right", + "layer": "overlay", + "height": 23, + "output": "!HDMI-1" + } +] diff --git a/test/config/simple.json b/test/config/simple.json new file mode 100644 index 0000000..1cb1e3a --- /dev/null +++ b/test/config/simple.json @@ -0,0 +1,5 @@ +{ + "layer": "top", + "height": 30, + "output": ["HDMI-0", "DP-0"] +} From 8912bd3ed0734aeaf4db961e1cfab28a42ac4cb2 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Mon, 16 Aug 2021 21:11:46 +0700 Subject: [PATCH 22/61] test: multi-bar config with includes --- test/config.cpp | 34 ++++++++++++++++++++++++++++++ test/config/include-multi-0.json | 9 ++++++++ test/config/include-multi-1.json | 8 +++++++ test/config/include-multi-2.json | 9 ++++++++ test/config/include-multi-3-0.json | 8 +++++++ test/config/include-multi-3.json | 9 ++++++++ test/config/include-multi.json | 16 ++++++++++++++ 7 files changed, 93 insertions(+) create mode 100644 test/config/include-multi-0.json create mode 100644 test/config/include-multi-1.json create mode 100644 test/config/include-multi-2.json create mode 100644 test/config/include-multi-3-0.json create mode 100644 test/config/include-multi-3.json create mode 100644 test/config/include-multi.json diff --git a/test/config.cpp b/test/config.cpp index 78ea0e1..0dc0b42 100644 --- a/test/config.cpp +++ b/test/config.cpp @@ -76,3 +76,37 @@ TEST_CASE("Load simple config with include", "[config]") { REQUIRE(configs.empty()); } } + +TEST_CASE("Load multiple bar config with include", "[config]") { + waybar::Config conf; + conf.load("test/config/include-multi.json"); + + SECTION("bar config with sole include") { + auto data = conf.getOutputConfigs("OUT-0", "Fake ouptut #0"); + REQUIRE(data.size() == 1); + REQUIRE(data[0]["height"].asInt() == 20); + } + + SECTION("bar config with output and include") { + auto data = conf.getOutputConfigs("OUT-1", "Fake output #1"); + REQUIRE(data.size() == 1); + REQUIRE(data[0]["height"].asInt() == 21); + } + + SECTION("bar config with output override") { + auto data = conf.getOutputConfigs("OUT-2", "Fake output #2"); + REQUIRE(data.size() == 1); + REQUIRE(data[0]["height"].asInt() == 22); + } + + SECTION("multiple levels of include") { + auto data = conf.getOutputConfigs("OUT-3", "Fake output #3"); + REQUIRE(data.size() == 1); + REQUIRE(data[0]["height"].asInt() == 23); + } + + auto& data = conf.getConfig(); + REQUIRE(data.isArray()); + REQUIRE(data.size() == 4); + REQUIRE(data[0]["output"].asString() == "OUT-0"); +} diff --git a/test/config/include-multi-0.json b/test/config/include-multi-0.json new file mode 100644 index 0000000..87b6cab --- /dev/null +++ b/test/config/include-multi-0.json @@ -0,0 +1,9 @@ +[ + { + "output": "OUT-0", + "height": 20 + }, + {}, + {}, + {} +] diff --git a/test/config/include-multi-1.json b/test/config/include-multi-1.json new file mode 100644 index 0000000..d816a0f --- /dev/null +++ b/test/config/include-multi-1.json @@ -0,0 +1,8 @@ +[ + {}, + { + "height": 21 + }, + {}, + {} +] diff --git a/test/config/include-multi-2.json b/test/config/include-multi-2.json new file mode 100644 index 0000000..47616ef --- /dev/null +++ b/test/config/include-multi-2.json @@ -0,0 +1,9 @@ +[ + {}, + {}, + { + "output": "OUT-1", + "height": 22 + }, + {} +] diff --git a/test/config/include-multi-3-0.json b/test/config/include-multi-3-0.json new file mode 100644 index 0000000..3f4da0c --- /dev/null +++ b/test/config/include-multi-3-0.json @@ -0,0 +1,8 @@ +[ + {}, + {}, + {}, + { + "height": 23 + } +] diff --git a/test/config/include-multi-3.json b/test/config/include-multi-3.json new file mode 100644 index 0000000..d095189 --- /dev/null +++ b/test/config/include-multi-3.json @@ -0,0 +1,9 @@ +[ + {}, + {}, + {}, + { + "output": "OUT-3", + "include": "test/config/include-multi-3-0.json" + } +] diff --git a/test/config/include-multi.json b/test/config/include-multi.json new file mode 100644 index 0000000..e128aba --- /dev/null +++ b/test/config/include-multi.json @@ -0,0 +1,16 @@ +[ + { + "include": "test/config/include-multi-0.json" + }, + { + "output": "OUT-1", + "include": "test/config/include-multi-1.json" + }, + { + "output": "OUT-2", + "include": "test/config/include-multi-2.json" + }, + { + "include": "test/config/include-multi-3.json" + } +] From ccc60b42459b29fed266759bd668b697636d5253 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Tue, 14 Sep 2021 12:16:37 +0700 Subject: [PATCH 23/61] refactor(config): more sensible multi-bar include behavior --- include/config.hpp | 2 +- src/config.cpp | 20 +++++++------------- test/config.cpp | 3 ++- test/config/include-multi-0.json | 13 ++++--------- test/config/include-multi-1.json | 11 +++-------- test/config/include-multi-2.json | 13 ++++--------- test/config/include-multi-3-0.json | 11 +++-------- test/config/include-multi-3.json | 13 ++++--------- 8 files changed, 28 insertions(+), 58 deletions(-) diff --git a/include/config.hpp b/include/config.hpp index 25b78ab..82d5599 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -28,7 +28,7 @@ class Config { std::vector getOutputConfigs(const std::string &name, const std::string &identifier); private: - void setupConfig(const std::string &config_file, int depth); + void setupConfig(Json::Value &dst, const std::string &config_file, int depth); void resolveConfigIncludes(Json::Value &config, int depth); void mergeConfig(Json::Value &a_config_, Json::Value &b_config_); diff --git a/src/config.cpp b/src/config.cpp index 207e1bd..63f18c2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -46,7 +46,7 @@ std::optional Config::findConfigPath(const std::vector return std::nullopt; } -void Config::setupConfig(const std::string &config_file, int depth) { +void Config::setupConfig(Json::Value &dst, const std::string &config_file, int depth) { if (depth > 100) { throw std::runtime_error("Aborting due to likely recursive include in config files"); } @@ -64,7 +64,7 @@ void Config::setupConfig(const std::string &config_file, int depth) { } else { resolveConfigIncludes(tmp_config, depth); } - mergeConfig(config_, tmp_config); + mergeConfig(dst, tmp_config); } void Config::resolveConfigIncludes(Json::Value &config, int depth) { @@ -72,11 +72,11 @@ void Config::resolveConfigIncludes(Json::Value &config, int depth) { if (includes.isArray()) { for (const auto &include : includes) { spdlog::info("Including resource file: {}", include.asString()); - setupConfig(tryExpandPath(include.asString()).value_or(""), ++depth); + setupConfig(config, tryExpandPath(include.asString()).value_or(""), ++depth); } } else if (includes.isString()) { spdlog::info("Including resource file: {}", includes.asString()); - setupConfig(tryExpandPath(includes.asString()).value_or(""), ++depth); + setupConfig(config, tryExpandPath(includes.asString()).value_or(""), ++depth); } } @@ -88,17 +88,11 @@ void Config::mergeConfig(Json::Value &a_config_, Json::Value &b_config_) { for (const auto &key : b_config_.getMemberNames()) { if (a_config_[key].isObject() && b_config_[key].isObject()) { mergeConfig(a_config_[key], b_config_[key]); - } else { + } else if (a_config_[key].isNull()) { + // do not allow overriding value set by top or previously included config a_config_[key] = b_config_[key]; } } - } else if (a_config_.isArray() && b_config_.isArray()) { - // This can happen only on the top-level array of a multi-bar config - for (Json::Value::ArrayIndex i = 0; i < b_config_.size(); i++) { - if (a_config_[i].isObject() && b_config_[i].isObject()) { - mergeConfig(a_config_[i], b_config_[i]); - } - } } else { spdlog::error("Cannot merge config, conflicting or invalid JSON types"); } @@ -133,7 +127,7 @@ void Config::load(const std::string &config) { } config_file_ = file.value(); spdlog::info("Using configuration file {}", config_file_); - setupConfig(config_file_, 0); + setupConfig(config_, config_file_, 0); } std::vector Config::getOutputConfigs(const std::string &name, diff --git a/test/config.cpp b/test/config.cpp index 0dc0b42..343a1c1 100644 --- a/test/config.cpp +++ b/test/config.cpp @@ -62,7 +62,8 @@ TEST_CASE("Load simple config with include", "[config]") { SECTION("validate the config data") { auto& data = conf.getConfig(); - REQUIRE(data["layer"].asString() == "bottom"); + // config override behavior: preserve first included value + REQUIRE(data["layer"].asString() == "top"); REQUIRE(data["height"].asInt() == 30); // config override behavior: preserve value from the top config REQUIRE(data["position"].asString() == "top"); diff --git a/test/config/include-multi-0.json b/test/config/include-multi-0.json index 87b6cab..a4c3fc1 100644 --- a/test/config/include-multi-0.json +++ b/test/config/include-multi-0.json @@ -1,9 +1,4 @@ -[ - { - "output": "OUT-0", - "height": 20 - }, - {}, - {}, - {} -] +{ + "output": "OUT-0", + "height": 20 +} diff --git a/test/config/include-multi-1.json b/test/config/include-multi-1.json index d816a0f..2b28d6c 100644 --- a/test/config/include-multi-1.json +++ b/test/config/include-multi-1.json @@ -1,8 +1,3 @@ -[ - {}, - { - "height": 21 - }, - {}, - {} -] +{ + "height": 21 +} diff --git a/test/config/include-multi-2.json b/test/config/include-multi-2.json index 47616ef..f74c2b4 100644 --- a/test/config/include-multi-2.json +++ b/test/config/include-multi-2.json @@ -1,9 +1,4 @@ -[ - {}, - {}, - { - "output": "OUT-1", - "height": 22 - }, - {} -] +{ + "output": "OUT-1", + "height": 22 +} diff --git a/test/config/include-multi-3-0.json b/test/config/include-multi-3-0.json index 3f4da0c..11cdd3f 100644 --- a/test/config/include-multi-3-0.json +++ b/test/config/include-multi-3-0.json @@ -1,8 +1,3 @@ -[ - {}, - {}, - {}, - { - "height": 23 - } -] +{ + "height": 23 +} diff --git a/test/config/include-multi-3.json b/test/config/include-multi-3.json index d095189..309fe15 100644 --- a/test/config/include-multi-3.json +++ b/test/config/include-multi-3.json @@ -1,9 +1,4 @@ -[ - {}, - {}, - {}, - { - "output": "OUT-3", - "include": "test/config/include-multi-3-0.json" - } -] +{ + "output": "OUT-3", + "include": "test/config/include-multi-3-0.json" +} From 0c1d3e30b62dc7c94b7ae32b97089309de7ff956 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 15 Sep 2021 22:14:12 +0700 Subject: [PATCH 24/61] fix(config): preserve explicit null when merging objects --- src/config.cpp | 9 +++++++-- test/config.cpp | 2 ++ test/config/include-1.json | 3 ++- test/config/include.json | 3 ++- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 63f18c2..63149cb 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,5 +1,6 @@ #include "config.hpp" +#include #include #include #include @@ -86,11 +87,15 @@ void Config::mergeConfig(Json::Value &a_config_, Json::Value &b_config_) { a_config_ = b_config_; } else if (a_config_.isObject() && b_config_.isObject()) { for (const auto &key : b_config_.getMemberNames()) { - if (a_config_[key].isObject() && b_config_[key].isObject()) { + // [] creates key with default value. Use `get` to avoid that. + if (a_config_.get(key, Json::Value::nullSingleton()).isObject() && + b_config_[key].isObject()) { mergeConfig(a_config_[key], b_config_[key]); - } else if (a_config_[key].isNull()) { + } else if (!a_config_.isMember(key)) { // do not allow overriding value set by top or previously included config a_config_[key] = b_config_[key]; + } else { + spdlog::trace("Option {} is already set; ignoring value {}", key, b_config_[key]); } } } else { diff --git a/test/config.cpp b/test/config.cpp index 343a1c1..f09f5da 100644 --- a/test/config.cpp +++ b/test/config.cpp @@ -67,6 +67,8 @@ TEST_CASE("Load simple config with include", "[config]") { REQUIRE(data["height"].asInt() == 30); // config override behavior: preserve value from the top config REQUIRE(data["position"].asString() == "top"); + // config override behavior: explicit null is still a value and should be preserved + REQUIRE((data.isMember("nullOption") && data["nullOption"].isNull())); } SECTION("select configs for configured output") { auto configs = conf.getOutputConfigs("HDMI-0", "Fake HDMI output #0"); diff --git a/test/config/include-1.json b/test/config/include-1.json index 853111c..7c47a88 100644 --- a/test/config/include-1.json +++ b/test/config/include-1.json @@ -2,5 +2,6 @@ "layer": "top", "position": "bottom", "height": 30, - "output": ["HDMI-0", "DP-0"] + "output": ["HDMI-0", "DP-0"], + "nullOption": "not null" } diff --git a/test/config/include.json b/test/config/include.json index 098cae0..c46aaf2 100644 --- a/test/config/include.json +++ b/test/config/include.json @@ -1,4 +1,5 @@ { "include": ["test/config/include-1.json", "test/config/include-2.json"], - "position": "top" + "position": "top", + "nullOption": null } From d7d606b72152da08c4a68dcbb36b92f070419159 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 15 Sep 2021 22:00:23 +0700 Subject: [PATCH 25/61] doc: update documentation for 'include' --- man/waybar.5.scd.in | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 9dc6925..997a48d 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -87,8 +87,9 @@ Also a minimal example configuration can be found on the at the bottom of this m *include* ++ typeof: string|array ++ - Paths to additional configuration files. In case of duplicate options, the including file's value takes precedence. Make sure to avoid circular imports. - For a multi-bar config, specify at least an empty object for each bar also in every file being included. + Paths to additional configuration files. + Each file can contain a single object with any of the bar configuration options. In case of duplicate options, the first defined value takes precedence, i.e. including file -> first included file -> etc. Nested includes are permitted, but make sure to avoid circular imports. + For a multi-bar config, the include directive affects only current bar configuration object. # MODULE FORMAT From 5991bbb741fed4756e6efdec473b56a5c9767840 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Tue, 14 Sep 2021 14:02:38 +0700 Subject: [PATCH 26/61] ci: run unit-tests --- .github/workflows/freebsd.yml | 7 ++++--- .github/workflows/linux.yml | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index f02c9b5..8af7a04 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -15,9 +15,10 @@ jobs: export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf pkg install -y git # subprojects/date - pkg install -y evdev-proto gtk-layer-shell gtkmm30 jsoncpp libdbusmenu \ - libevdev libfmt libmpdclient libudev-devd meson pkgconf pulseaudio \ - scdoc sndio spdlog + pkg install -y catch evdev-proto gtk-layer-shell gtkmm30 jsoncpp \ + libdbusmenu libevdev libfmt libmpdclient libudev-devd meson \ + pkgconf pulseaudio scdoc sndio spdlog run: | meson build -Dman-pages=enabled ninja -C build + meson test -C build --no-rebuild --print-errorlogs --suite waybar diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index e550e20..d4efbf8 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -23,3 +23,5 @@ jobs: run: meson -Dman-pages=enabled build - name: build run: ninja -C build + - name: test + run: meson test -C build --no-rebuild --print-errorlogs --suite waybar From 4bf577e89bfc2c7c816cda99e1b5a68e63ae9d5a Mon Sep 17 00:00:00 2001 From: Darkclainer Date: Fri, 17 Sep 2021 21:18:21 +0300 Subject: [PATCH 27/61] Add CPU usage for every core --- include/modules/cpu.hpp | 11 ++++++----- src/modules/cpu/common.cpp | 32 +++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/include/modules/cpu.hpp b/include/modules/cpu.hpp index 866b5af..1fe1199 100644 --- a/include/modules/cpu.hpp +++ b/include/modules/cpu.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -19,11 +20,11 @@ class Cpu : public ALabel { auto update() -> void; private: - double getCpuLoad(); - std::tuple getCpuUsage(); - std::tuple getCpuFrequency(); - std::vector> parseCpuinfo(); - std::vector parseCpuFrequencies(); + double getCpuLoad(); + std::tuple, std::string> getCpuUsage(); + std::tuple getCpuFrequency(); + std::vector> parseCpuinfo(); + std::vector parseCpuFrequencies(); std::vector> prev_times_; diff --git a/src/modules/cpu/common.cpp b/src/modules/cpu/common.cpp index 767cde9..5869e13 100644 --- a/src/modules/cpu/common.cpp +++ b/src/modules/cpu/common.cpp @@ -17,7 +17,8 @@ auto waybar::modules::Cpu::update() -> void { label_.set_tooltip_text(tooltip); } auto format = format_; - auto state = getState(cpu_usage); + auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0]; + auto state = getState(total_usage); if (!state.empty() && config_["format-" + state].isString()) { format = config_["format-" + state].asString(); } @@ -27,13 +28,22 @@ auto waybar::modules::Cpu::update() -> void { } else { event_box_.show(); auto icons = std::vector{state}; - label_.set_markup(fmt::format(format, - fmt::arg("load", cpu_load), - fmt::arg("usage", cpu_usage), - fmt::arg("icon", getIcon(cpu_usage, icons)), - fmt::arg("max_frequency", max_frequency), - fmt::arg("min_frequency", min_frequency), - fmt::arg("avg_frequency", avg_frequency))); + fmt::dynamic_format_arg_store store; + store.push_back(fmt::arg("load", cpu_load)); + store.push_back(fmt::arg("load", cpu_load)); + store.push_back(fmt::arg("usage", total_usage)); + store.push_back(fmt::arg("icon", getIcon(total_usage, icons))); + store.push_back(fmt::arg("max_frequency", max_frequency)); + store.push_back(fmt::arg("min_frequency", min_frequency)); + store.push_back(fmt::arg("avg_frequency", avg_frequency)); + for (size_t i = 1; i < cpu_usage.size(); ++i) { + auto core_i = i - 1; + auto core_format = fmt::format("usage{}", core_i); + store.push_back(fmt::arg(core_format.c_str(), cpu_usage[i])); + auto icon_format = fmt::format("icon{}", core_i); + store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons))); + } + label_.set_markup(fmt::vformat(format, store)); } // Call parent update @@ -48,14 +58,14 @@ double waybar::modules::Cpu::getCpuLoad() { throw std::runtime_error("Can't get Cpu load"); } -std::tuple waybar::modules::Cpu::getCpuUsage() { +std::tuple, std::string> waybar::modules::Cpu::getCpuUsage() { if (prev_times_.empty()) { prev_times_ = parseCpuinfo(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::vector> curr_times = parseCpuinfo(); std::string tooltip; - uint16_t usage = 0; + std::vector usage; for (size_t i = 0; i < curr_times.size(); ++i) { auto [curr_idle, curr_total] = curr_times[i]; auto [prev_idle, prev_total] = prev_times_[i]; @@ -63,11 +73,11 @@ std::tuple waybar::modules::Cpu::getCpuUsage() { const float delta_total = curr_total - prev_total; uint16_t tmp = 100 * (1 - delta_idle / delta_total); if (i == 0) { - usage = tmp; tooltip = fmt::format("Total: {}%", tmp); } else { tooltip = tooltip + fmt::format("\nCore{}: {}%", i - 1, tmp); } + usage.push_back(tmp); } prev_times_ = curr_times; return {usage, tooltip}; From 8da940f929bd8c06a30fd3d02de53e6fac2ac5f8 Mon Sep 17 00:00:00 2001 From: Darkclainer Date: Fri, 17 Sep 2021 22:22:14 +0300 Subject: [PATCH 28/61] Update man pages for cpu usage --- man/waybar-cpu.5.scd | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/man/waybar-cpu.5.scd b/man/waybar-cpu.5.scd index 679ca2c..2e0d6c7 100644 --- a/man/waybar-cpu.5.scd +++ b/man/waybar-cpu.5.scd @@ -82,7 +82,9 @@ The *cpu* module displays the current cpu utilization. *{load}*: Current cpu load. -*{usage}*: Current cpu usage. +*{usage}*: Current overall cpu usage. + +*{usage*{n}*}*: Current cpu core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}. *{avg_frequency}*: Current cpu average frequency (based on all cores) in GHz. @@ -90,7 +92,13 @@ The *cpu* module displays the current cpu utilization. *{min_frequency}*: Current cpu min frequency (based on the core with the lowest frequency) in GHz. -# EXAMPLE +*{icon}*: Icon for overall cpu usage. + +*{icon*{n}*}*: Icon for cpu core n usage. Use like {icon0}. + +# EXAMPLES + +Basic configuration: ``` "cpu": { @@ -100,6 +108,16 @@ The *cpu* module displays the current cpu utilization. } ``` +Cpu usage per core rendered as icons: + +``` +"cpu": { + "interval": 1, + "format": "{icon0}{icon1}{icon2}{icon3} {usage:>2}% ", + "format-icons": ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"], +}, +``` + # STYLE - *#cpu* From 5f083193e4202e616d587b53050111fef1fa031f Mon Sep 17 00:00:00 2001 From: mazunki Date: Sat, 18 Sep 2021 01:12:58 +0200 Subject: [PATCH 29/61] fixed tab indentation to spaces, removed debug --- src/modules/network.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index a45f2b8..0fccf09 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -661,9 +661,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { net->clearIface(); net->ifid_ = temp_idx; net->route_priority = priority; - net->gwaddr_ = temp_gw_addr; - spdlog::debug("netwok: gateway {}", net->gwaddr_); - + net->gwaddr_ = temp_gw_addr; spdlog::debug("network: new default route via if{} metric {}", temp_idx, priority); /* Ask ifname associated with temp_idx as well as carrier status */ From 13239417d817460eee8dd46bd09ddae0fc8dcf5a Mon Sep 17 00:00:00 2001 From: mazunki Date: Sat, 18 Sep 2021 01:20:16 +0200 Subject: [PATCH 30/61] fixed wrong dependency for make target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ccf0507..94f8ee6 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ install: build run: build ./build/waybar -debug-run: build +debug-run: build-debug ./build/waybar --log-level debug clean: From 6142dfba6a1ffc5e08ac68df172291d926fa8b03 Mon Sep 17 00:00:00 2001 From: mazunki Date: Sat, 18 Sep 2021 01:51:16 +0200 Subject: [PATCH 31/61] updated original debug message with gateway ip, similar, yet not identical to default via 10.13.37.100 dev enp7s0 metric 2 10.13.37.0/24 dev enp7s0 proto kernel scope link src 10.13.37.97 's output --- src/modules/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 0fccf09..3b9fb18 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -662,7 +662,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { net->ifid_ = temp_idx; net->route_priority = priority; net->gwaddr_ = temp_gw_addr; - spdlog::debug("network: new default route via if{} metric {}", temp_idx, priority); + spdlog::debug("network: new default route via {} on if{} metric {}", temp_gw_addr, temp_idx, priority); /* Ask ifname associated with temp_idx as well as carrier status */ struct ifinfomsg ifinfo_hdr = { From 1c91c71dcde2d77506989b407eefcd18b20f34a3 Mon Sep 17 00:00:00 2001 From: mazunki Date: Sat, 18 Sep 2021 01:51:16 +0200 Subject: [PATCH 32/61] updated original debug message with gateway ip, similar, yet not identical to `ip route` --- src/modules/network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 0fccf09..3b9fb18 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -662,7 +662,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { net->ifid_ = temp_idx; net->route_priority = priority; net->gwaddr_ = temp_gw_addr; - spdlog::debug("network: new default route via if{} metric {}", temp_idx, priority); + spdlog::debug("network: new default route via {} on if{} metric {}", temp_gw_addr, temp_idx, priority); /* Ask ifname associated with temp_idx as well as carrier status */ struct ifinfomsg ifinfo_hdr = { From 67c730293885684a954632a70fe041abd2288685 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 18 Sep 2021 13:50:16 +0200 Subject: [PATCH 33/61] Revert "Add CPU usage for every core" --- include/modules/cpu.hpp | 11 +++++------ man/waybar-cpu.5.scd | 22 ++-------------------- src/modules/cpu/common.cpp | 32 +++++++++++--------------------- 3 files changed, 18 insertions(+), 47 deletions(-) diff --git a/include/modules/cpu.hpp b/include/modules/cpu.hpp index 1fe1199..866b5af 100644 --- a/include/modules/cpu.hpp +++ b/include/modules/cpu.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include @@ -20,11 +19,11 @@ class Cpu : public ALabel { auto update() -> void; private: - double getCpuLoad(); - std::tuple, std::string> getCpuUsage(); - std::tuple getCpuFrequency(); - std::vector> parseCpuinfo(); - std::vector parseCpuFrequencies(); + double getCpuLoad(); + std::tuple getCpuUsage(); + std::tuple getCpuFrequency(); + std::vector> parseCpuinfo(); + std::vector parseCpuFrequencies(); std::vector> prev_times_; diff --git a/man/waybar-cpu.5.scd b/man/waybar-cpu.5.scd index 2e0d6c7..679ca2c 100644 --- a/man/waybar-cpu.5.scd +++ b/man/waybar-cpu.5.scd @@ -82,9 +82,7 @@ The *cpu* module displays the current cpu utilization. *{load}*: Current cpu load. -*{usage}*: Current overall cpu usage. - -*{usage*{n}*}*: Current cpu core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}. +*{usage}*: Current cpu usage. *{avg_frequency}*: Current cpu average frequency (based on all cores) in GHz. @@ -92,13 +90,7 @@ The *cpu* module displays the current cpu utilization. *{min_frequency}*: Current cpu min frequency (based on the core with the lowest frequency) in GHz. -*{icon}*: Icon for overall cpu usage. - -*{icon*{n}*}*: Icon for cpu core n usage. Use like {icon0}. - -# EXAMPLES - -Basic configuration: +# EXAMPLE ``` "cpu": { @@ -108,16 +100,6 @@ Basic configuration: } ``` -Cpu usage per core rendered as icons: - -``` -"cpu": { - "interval": 1, - "format": "{icon0}{icon1}{icon2}{icon3} {usage:>2}% ", - "format-icons": ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"], -}, -``` - # STYLE - *#cpu* diff --git a/src/modules/cpu/common.cpp b/src/modules/cpu/common.cpp index 5869e13..767cde9 100644 --- a/src/modules/cpu/common.cpp +++ b/src/modules/cpu/common.cpp @@ -17,8 +17,7 @@ auto waybar::modules::Cpu::update() -> void { label_.set_tooltip_text(tooltip); } auto format = format_; - auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0]; - auto state = getState(total_usage); + auto state = getState(cpu_usage); if (!state.empty() && config_["format-" + state].isString()) { format = config_["format-" + state].asString(); } @@ -28,22 +27,13 @@ auto waybar::modules::Cpu::update() -> void { } else { event_box_.show(); auto icons = std::vector{state}; - fmt::dynamic_format_arg_store store; - store.push_back(fmt::arg("load", cpu_load)); - store.push_back(fmt::arg("load", cpu_load)); - store.push_back(fmt::arg("usage", total_usage)); - store.push_back(fmt::arg("icon", getIcon(total_usage, icons))); - store.push_back(fmt::arg("max_frequency", max_frequency)); - store.push_back(fmt::arg("min_frequency", min_frequency)); - store.push_back(fmt::arg("avg_frequency", avg_frequency)); - for (size_t i = 1; i < cpu_usage.size(); ++i) { - auto core_i = i - 1; - auto core_format = fmt::format("usage{}", core_i); - store.push_back(fmt::arg(core_format.c_str(), cpu_usage[i])); - auto icon_format = fmt::format("icon{}", core_i); - store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons))); - } - label_.set_markup(fmt::vformat(format, store)); + label_.set_markup(fmt::format(format, + fmt::arg("load", cpu_load), + fmt::arg("usage", cpu_usage), + fmt::arg("icon", getIcon(cpu_usage, icons)), + fmt::arg("max_frequency", max_frequency), + fmt::arg("min_frequency", min_frequency), + fmt::arg("avg_frequency", avg_frequency))); } // Call parent update @@ -58,14 +48,14 @@ double waybar::modules::Cpu::getCpuLoad() { throw std::runtime_error("Can't get Cpu load"); } -std::tuple, std::string> waybar::modules::Cpu::getCpuUsage() { +std::tuple waybar::modules::Cpu::getCpuUsage() { if (prev_times_.empty()) { prev_times_ = parseCpuinfo(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::vector> curr_times = parseCpuinfo(); std::string tooltip; - std::vector usage; + uint16_t usage = 0; for (size_t i = 0; i < curr_times.size(); ++i) { auto [curr_idle, curr_total] = curr_times[i]; auto [prev_idle, prev_total] = prev_times_[i]; @@ -73,11 +63,11 @@ std::tuple, std::string> waybar::modules::Cpu::getCpuUsage const float delta_total = curr_total - prev_total; uint16_t tmp = 100 * (1 - delta_idle / delta_total); if (i == 0) { + usage = tmp; tooltip = fmt::format("Total: {}%", tmp); } else { tooltip = tooltip + fmt::format("\nCore{}: {}%", i - 1, tmp); } - usage.push_back(tmp); } prev_times_ = curr_times; return {usage, tooltip}; From fe547901fae1f536d047b468d8c35d3afb70a6e2 Mon Sep 17 00:00:00 2001 From: Gavin Beatty Date: Sat, 18 Sep 2021 15:28:27 -0500 Subject: [PATCH 34/61] sway/language: remove tabs, indent with 2 spaces --- src/modules/sway/language.cpp | 74 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/modules/sway/language.cpp b/src/modules/sway/language.cpp index 85dc769..186fa4b 100644 --- a/src/modules/sway/language.cpp +++ b/src/modules/sway/language.cpp @@ -20,15 +20,15 @@ const std::string Language::XKB_ACTIVE_LAYOUT_NAME_KEY = "xkb_active_layout_name Language::Language(const std::string& id, const Json::Value& config) : ALabel(config, "language", id, "{}", 0, true) { is_variant_displayed = format_.find("{variant}") != std::string::npos; - if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) { - displayed_short_flag |= static_cast(DispayedShortFlag::ShortName); - } - if (format_.find("{shortDescription}") != std::string::npos) { - displayed_short_flag |= static_cast(DispayedShortFlag::ShortDescription); - } - if (config.isMember("tooltip-format")) { - tooltip_format_ = config["tooltip-format"].asString(); - } + if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) { + displayed_short_flag |= static_cast(DispayedShortFlag::ShortName); + } + if (format_.find("{shortDescription}") != std::string::npos) { + displayed_short_flag |= static_cast(DispayedShortFlag::ShortDescription); + } + if (config.isMember("tooltip-format")) { + tooltip_format_ = config["tooltip-format"].asString(); + } ipc_.subscribe(R"(["input"])"); ipc_.signal_event.connect(sigc::mem_fun(*this, &Language::onEvent)); ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Language::onCmd)); @@ -102,16 +102,16 @@ auto Language::update() -> void { fmt::arg("variant", layout_.variant))); label_.set_markup(display_layout); if (tooltipEnabled()) { - if (tooltip_format_ != "") { - auto tooltip_display_layout = trim(fmt::format(tooltip_format_, - fmt::arg("short", layout_.short_name), - fmt::arg("shortDescription", layout_.short_description), - fmt::arg("long", layout_.full_name), - fmt::arg("variant", layout_.variant))); - label_.set_tooltip_markup(tooltip_display_layout); - } else { - label_.set_tooltip_markup(display_layout); - } + if (tooltip_format_ != "") { + auto tooltip_display_layout = trim(fmt::format(tooltip_format_, + fmt::arg("short", layout_.short_name), + fmt::arg("shortDescription", layout_.short_description), + fmt::arg("long", layout_.full_name), + fmt::arg("variant", layout_.variant))); + label_.set_tooltip_markup(tooltip_display_layout); + } else { + label_.set_tooltip_markup(display_layout); + } } event_box_.show(); @@ -126,7 +126,7 @@ auto Language::set_current_layout(std::string current_layout) -> void { auto Language::init_layouts_map(const std::vector& used_layouts) -> void { std::map> found_by_short_names; - XKBContext xkb_context; + XKBContext xkb_context; auto layout = xkb_context.next_layout(); for (; layout != nullptr; layout = xkb_context.next_layout()) { if (std::find(used_layouts.begin(), used_layouts.end(), layout->full_name) == @@ -161,15 +161,15 @@ auto Language::init_layouts_map(const std::vector& used_layouts) -> if (short_name_to_number_map.count(used_layout->short_name) == 0) { short_name_to_number_map[used_layout->short_name] = 1; } - - if (displayed_short_flag != static_cast(0)) { - int& number = short_name_to_number_map[used_layout->short_name]; - used_layout->short_name = - used_layout->short_name + std::to_string(number); - used_layout->short_description = - used_layout->short_description + std::to_string(number); - ++number; - } + + if (displayed_short_flag != static_cast(0)) { + int& number = short_name_to_number_map[used_layout->short_name]; + used_layout->short_name = + used_layout->short_name + std::to_string(number); + used_layout->short_description = + used_layout->short_description + std::to_string(number); + ++number; + } } } @@ -195,14 +195,14 @@ auto Language::XKBContext::next_layout() -> Layout* { auto variant_ = rxkb_layout_get_variant(xkb_layout_); std::string variant = variant_ == nullptr ? "" : std::string(variant_); auto short_description_ = rxkb_layout_get_brief(xkb_layout_); - std::string short_description; - if (short_description_ != nullptr) { - short_description = std::string(short_description_); - base_layouts_by_name_.emplace(name, xkb_layout_); - } else { - auto base_layout = base_layouts_by_name_[name]; - short_description = base_layout == nullptr ? "" : std::string(rxkb_layout_get_brief(base_layout)); - } + std::string short_description; + if (short_description_ != nullptr) { + short_description = std::string(short_description_); + base_layouts_by_name_.emplace(name, xkb_layout_); + } else { + auto base_layout = base_layouts_by_name_[name]; + short_description = base_layout == nullptr ? "" : std::string(rxkb_layout_get_brief(base_layout)); + } delete layout_; layout_ = new Layout{description, name, variant, short_description}; return layout_; From 6e5a0bc80a3301f4f30ce58909eadb7d54bd739e Mon Sep 17 00:00:00 2001 From: Darkclainer Date: Sun, 19 Sep 2021 13:41:59 +0300 Subject: [PATCH 35/61] Add cpu usage for every core --- include/modules/cpu.hpp | 10 +++++----- man/waybar-cpu.5.scd | 22 ++++++++++++++++++-- src/modules/cpu/common.cpp | 41 ++++++++++++++++++++++++++++---------- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/include/modules/cpu.hpp b/include/modules/cpu.hpp index 866b5af..7e32a43 100644 --- a/include/modules/cpu.hpp +++ b/include/modules/cpu.hpp @@ -19,11 +19,11 @@ class Cpu : public ALabel { auto update() -> void; private: - double getCpuLoad(); - std::tuple getCpuUsage(); - std::tuple getCpuFrequency(); - std::vector> parseCpuinfo(); - std::vector parseCpuFrequencies(); + double getCpuLoad(); + std::tuple, std::string> getCpuUsage(); + std::tuple getCpuFrequency(); + std::vector> parseCpuinfo(); + std::vector parseCpuFrequencies(); std::vector> prev_times_; diff --git a/man/waybar-cpu.5.scd b/man/waybar-cpu.5.scd index 679ca2c..2e0d6c7 100644 --- a/man/waybar-cpu.5.scd +++ b/man/waybar-cpu.5.scd @@ -82,7 +82,9 @@ The *cpu* module displays the current cpu utilization. *{load}*: Current cpu load. -*{usage}*: Current cpu usage. +*{usage}*: Current overall cpu usage. + +*{usage*{n}*}*: Current cpu core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}. *{avg_frequency}*: Current cpu average frequency (based on all cores) in GHz. @@ -90,7 +92,13 @@ The *cpu* module displays the current cpu utilization. *{min_frequency}*: Current cpu min frequency (based on the core with the lowest frequency) in GHz. -# EXAMPLE +*{icon}*: Icon for overall cpu usage. + +*{icon*{n}*}*: Icon for cpu core n usage. Use like {icon0}. + +# EXAMPLES + +Basic configuration: ``` "cpu": { @@ -100,6 +108,16 @@ The *cpu* module displays the current cpu utilization. } ``` +Cpu usage per core rendered as icons: + +``` +"cpu": { + "interval": 1, + "format": "{icon0}{icon1}{icon2}{icon3} {usage:>2}% ", + "format-icons": ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"], +}, +``` + # STYLE - *#cpu* diff --git a/src/modules/cpu/common.cpp b/src/modules/cpu/common.cpp index 767cde9..4cf67eb 100644 --- a/src/modules/cpu/common.cpp +++ b/src/modules/cpu/common.cpp @@ -1,5 +1,14 @@ #include "modules/cpu.hpp" +// In the 80000 version of fmt library authors decided to optimize imports +// and moved declarations required for fmt::dynamic_format_arg_store in new +// header fmt/args.h +#if (FMT_VERSION >= 80000) +#include +#else +#include +#endif + waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config) : ALabel(config, "cpu", id, "{usage}%", 10) { thread_ = [this] { @@ -17,7 +26,8 @@ auto waybar::modules::Cpu::update() -> void { label_.set_tooltip_text(tooltip); } auto format = format_; - auto state = getState(cpu_usage); + auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0]; + auto state = getState(total_usage); if (!state.empty() && config_["format-" + state].isString()) { format = config_["format-" + state].asString(); } @@ -27,13 +37,22 @@ auto waybar::modules::Cpu::update() -> void { } else { event_box_.show(); auto icons = std::vector{state}; - label_.set_markup(fmt::format(format, - fmt::arg("load", cpu_load), - fmt::arg("usage", cpu_usage), - fmt::arg("icon", getIcon(cpu_usage, icons)), - fmt::arg("max_frequency", max_frequency), - fmt::arg("min_frequency", min_frequency), - fmt::arg("avg_frequency", avg_frequency))); + fmt::dynamic_format_arg_store store; + store.push_back(fmt::arg("load", cpu_load)); + store.push_back(fmt::arg("load", cpu_load)); + store.push_back(fmt::arg("usage", total_usage)); + store.push_back(fmt::arg("icon", getIcon(total_usage, icons))); + store.push_back(fmt::arg("max_frequency", max_frequency)); + store.push_back(fmt::arg("min_frequency", min_frequency)); + store.push_back(fmt::arg("avg_frequency", avg_frequency)); + for (size_t i = 1; i < cpu_usage.size(); ++i) { + auto core_i = i - 1; + auto core_format = fmt::format("usage{}", core_i); + store.push_back(fmt::arg(core_format.c_str(), cpu_usage[i])); + auto icon_format = fmt::format("icon{}", core_i); + store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons))); + } + label_.set_markup(fmt::vformat(format, store)); } // Call parent update @@ -48,14 +67,14 @@ double waybar::modules::Cpu::getCpuLoad() { throw std::runtime_error("Can't get Cpu load"); } -std::tuple waybar::modules::Cpu::getCpuUsage() { +std::tuple, std::string> waybar::modules::Cpu::getCpuUsage() { if (prev_times_.empty()) { prev_times_ = parseCpuinfo(); std::this_thread::sleep_for(std::chrono::milliseconds(100)); } std::vector> curr_times = parseCpuinfo(); std::string tooltip; - uint16_t usage = 0; + std::vector usage; for (size_t i = 0; i < curr_times.size(); ++i) { auto [curr_idle, curr_total] = curr_times[i]; auto [prev_idle, prev_total] = prev_times_[i]; @@ -63,11 +82,11 @@ std::tuple waybar::modules::Cpu::getCpuUsage() { const float delta_total = curr_total - prev_total; uint16_t tmp = 100 * (1 - delta_idle / delta_total); if (i == 0) { - usage = tmp; tooltip = fmt::format("Total: {}%", tmp); } else { tooltip = tooltip + fmt::format("\nCore{}: {}%", i - 1, tmp); } + usage.push_back(tmp); } prev_times_ = curr_times; return {usage, tooltip}; From 8d04da1551bdfae54d17e16c6e49e7e0819e1f71 Mon Sep 17 00:00:00 2001 From: WuerfelDev Date: Tue, 21 Sep 2021 13:15:36 +0200 Subject: [PATCH 36/61] dont escape essid in tooltip just like https://github.com/Alexays/Waybar/pull/834 but for the network name. --- src/modules/network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 3b9fb18..14a6d86 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -342,7 +342,7 @@ auto waybar::modules::Network::update() -> void { auto text = fmt::format( format_, - fmt::arg("essid", essid_), + fmt::arg("essid", Glib::Markup::escape_text(essid_)), fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_), fmt::arg("ifname", ifname_), @@ -793,7 +793,7 @@ void waybar::modules::Network::parseEssid(struct nlattr **bss) { auto essid_end = essid_begin + ies[1]; std::string essid_raw; std::copy(essid_begin, essid_end, std::back_inserter(essid_raw)); - essid_ = Glib::Markup::escape_text(essid_raw); + essid_ = essid_raw; } } } From f638fe473a54e62d0ec41e143b4cf616ce388099 Mon Sep 17 00:00:00 2001 From: Ryan Walklin Date: Wed, 22 Sep 2021 11:43:25 +1200 Subject: [PATCH 37/61] Update catch2 dependency 2.13.3 -> 2.13.7 --- subprojects/catch2.wrap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/subprojects/catch2.wrap b/subprojects/catch2.wrap index 356c406..c82b310 100644 --- a/subprojects/catch2.wrap +++ b/subprojects/catch2.wrap @@ -1,11 +1,11 @@ [wrap-file] -directory = Catch2-2.13.3 -source_url = https://github.com/catchorg/Catch2/archive/v2.13.3.zip -source_filename = Catch2-2.13.3.zip -source_hash = 1804feb72bc15c0856b4a43aa586c661af9c3685a75973b6a8fc0b950c7cfd13 -patch_url = https://github.com/mesonbuild/catch2/releases/download/2.13.3-2/catch2.zip -patch_filename = catch2-2.13.3-2-wrap.zip -patch_hash = 21b590ab8c65b593ad5ee8f8e5b822bf9877b2c2672f97fbb52459751053eadf +directory = Catch2-2.13.7 +source_url = https://github.com/catchorg/Catch2/archive/v2.13.7.zip +source_filename = Catch2-2.13.7.zip +source_hash = 3f3ccd90ad3a8fbb1beeb15e6db440ccdcbebe378dfd125d07a1f9a587a927e9 +patch_filename = catch2_2.13.7-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/catch2_2.13.7-1/get_patch +patch_hash = 2f7369645d747e5bd866317ac1dd4c3d04dc97d3aad4fc6b864bdf75d3b57158 [provide] catch2 = catch2_dep From fbedc3d133d627b8ff4f8c9fe5744739bf8dd0b3 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Sun, 19 Sep 2021 18:30:41 +0300 Subject: [PATCH 38/61] fix(tray): fix visibility of Passive items `show_all` call from `Tray::update` attempts to walk the widget tree and make every widget visible. Since we control individual tray item visibility based on `Status` SNI property, we don't want that to happen. Modify `Tray::update` to control the visibility of a whole tray module only and ensure that the children of `Item` are still visible when necessary. --- src/modules/sni/item.cpp | 1 + src/modules/sni/tray.cpp | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/modules/sni/item.cpp b/src/modules/sni/item.cpp index d9748ed..b504c8d 100644 --- a/src/modules/sni/item.cpp +++ b/src/modules/sni/item.cpp @@ -62,6 +62,7 @@ Item::Item(const std::string& bn, const std::string& op, const Json::Value& conf event_box.signal_button_press_event().connect(sigc::mem_fun(*this, &Item::handleClick)); event_box.signal_scroll_event().connect(sigc::mem_fun(*this, &Item::handleScroll)); // initial visibility + event_box.show_all(); event_box.set_visible(show_passive_); cancellable_ = Gio::Cancellable::create(); diff --git a/src/modules/sni/tray.cpp b/src/modules/sni/tray.cpp index e73c9eb..70b0d37 100644 --- a/src/modules/sni/tray.cpp +++ b/src/modules/sni/tray.cpp @@ -35,11 +35,8 @@ void Tray::onRemove(std::unique_ptr& item) { } auto Tray::update() -> void { - if (box_.get_children().empty()) { - box_.hide(); - } else { - box_.show_all(); - } + // Show tray only when items are availale + box_.set_visible(!box_.get_children().empty()); // Call parent update AModule::update(); } From f18eb71ad7b6b1a523fdbb8416bbc713213b6ccd Mon Sep 17 00:00:00 2001 From: Elyes HAOUAS Date: Sat, 2 Oct 2021 18:13:17 +0200 Subject: [PATCH 39/61] Fix spelling errors Signed-off-by: Elyes HAOUAS --- resources/custom_modules/mediaplayer.py | 2 +- src/modules/clock.cpp | 2 +- src/modules/network.cpp | 2 +- src/modules/sni/tray.cpp | 2 +- test/config.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/resources/custom_modules/mediaplayer.py b/resources/custom_modules/mediaplayer.py index cf3df4b..fa9aa58 100755 --- a/resources/custom_modules/mediaplayer.py +++ b/resources/custom_modules/mediaplayer.py @@ -79,7 +79,7 @@ def signal_handler(sig, frame): def parse_arguments(): parser = argparse.ArgumentParser() - # Increase verbosity with every occurence of -v + # Increase verbosity with every occurrence of -v parser.add_argument('-v', '--verbose', action='count', default=0) # Define for which player we're listening diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 82c5701..0c38cb6 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -16,7 +16,7 @@ using waybar::modules::waybar_time; waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), fixed_time_zone_(false) { if (config_["timezone"].isString()) { - spdlog::warn("As using a timezone, some format args may be missing as the date library havn't got a release since 2018."); + spdlog::warn("As using a timezone, some format args may be missing as the date library haven't got a release since 2018."); time_zone_ = date::locate_zone(config_["timezone"].asString()); fixed_time_zone_ = true; } diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 3b9fb18..99ccd8e 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -469,7 +469,7 @@ int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { } if (!is_del_event && ifi->ifi_index == net->ifid_) { - // Update inferface information + // Update interface information if (net->ifname_.empty() && ifname != NULL) { std::string new_ifname (ifname, ifname_len); net->ifname_ = new_ifname; diff --git a/src/modules/sni/tray.cpp b/src/modules/sni/tray.cpp index 70b0d37..c32c0d6 100644 --- a/src/modules/sni/tray.cpp +++ b/src/modules/sni/tray.cpp @@ -35,7 +35,7 @@ void Tray::onRemove(std::unique_ptr& item) { } auto Tray::update() -> void { - // Show tray only when items are availale + // Show tray only when items are available box_.set_visible(!box_.get_children().empty()); // Call parent update AModule::update(); diff --git a/test/config.cpp b/test/config.cpp index f09f5da..edd6d6b 100644 --- a/test/config.cpp +++ b/test/config.cpp @@ -85,7 +85,7 @@ TEST_CASE("Load multiple bar config with include", "[config]") { conf.load("test/config/include-multi.json"); SECTION("bar config with sole include") { - auto data = conf.getOutputConfigs("OUT-0", "Fake ouptut #0"); + auto data = conf.getOutputConfigs("OUT-0", "Fake output #0"); REQUIRE(data.size() == 1); REQUIRE(data[0]["height"].asInt() == 20); } From 99723845976fb577a057b86e36b502c966bf254f Mon Sep 17 00:00:00 2001 From: "Rene D. Obermueller" Date: Sat, 2 Oct 2021 18:35:38 +0200 Subject: [PATCH 40/61] sway/window: include floating_nodes when considering window count for class --- src/modules/sway/window.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/modules/sway/window.cpp b/src/modules/sway/window.cpp index b677958..fc81b2c 100644 --- a/src/modules/sway/window.cpp +++ b/src/modules/sway/window.cpp @@ -68,15 +68,22 @@ auto Window::update() -> void { int leafNodesInWorkspace(const Json::Value& node) { auto const& nodes = node["nodes"]; - if(nodes.empty()) { + auto const& floating_nodes = node["floating_nodes"]; + if(nodes.empty() && floating_nodes.empty()) { if(node["type"] == "workspace") return 0; else return 1; } int sum = 0; - for(auto const& node : nodes) - sum += leafNodesInWorkspace(node); + if (!nodes.empty()) { + for(auto const& node : nodes) + sum += leafNodesInWorkspace(node); + } + if (!floating_nodes.empty()) { + for(auto const& node : floating_nodes) + sum += leafNodesInWorkspace(node); + } return sum; } From 174db444d6a6a78814e0c93430755d92312832a0 Mon Sep 17 00:00:00 2001 From: Sergey Mishin Date: Sun, 3 Oct 2021 03:27:54 +0000 Subject: [PATCH 41/61] Fix Clock crash on empty string in timezones field Also fixed timezones behavior: now waybar starting with the first timezone in timezones list and falling back to timezone field only if timezones omit or has no elements. --- include/modules/clock.hpp | 1 + man/waybar-clock.5.scd | 3 ++- src/modules/clock.cpp | 30 +++++++++++++++++++----------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp index b3e2634..17752e4 100644 --- a/include/modules/clock.hpp +++ b/include/modules/clock.hpp @@ -37,6 +37,7 @@ class Clock : public ALabel { auto calendar_text(const waybar_time& wtime) -> std::string; auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void; auto first_day_of_week() -> date::weekday; + bool setTimeZone(Json::Value zone_name); }; } // namespace waybar::modules diff --git a/man/waybar-clock.5.scd b/man/waybar-clock.5.scd index 28688ee..2c901d2 100644 --- a/man/waybar-clock.5.scd +++ b/man/waybar-clock.5.scd @@ -24,7 +24,8 @@ The *clock* module displays the current date and time. *timezone*: ++ typeof: string ++ default: inferred local timezone ++ - The timezone to display the time in, e.g. America/New_York. + The timezone to display the time in, e.g. America/New_York. ++ + This field will be ignored if *timezones* field is set and have at least one value. *timezones*: ++ typeof: list of strings ++ diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 0c38cb6..7c94c45 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -15,10 +15,14 @@ using waybar::modules::waybar_time; waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), fixed_time_zone_(false) { - if (config_["timezone"].isString()) { + if (config_["timezones"].isArray() && !config_["timezones"].empty()) { + time_zone_idx_ = 0; + setTimeZone(config_["timezones"][time_zone_idx_]); + } else { + setTimeZone(config_["timezone"]); + } + if (fixed_time_zone_) { spdlog::warn("As using a timezone, some format args may be missing as the date library haven't got a release since 2018."); - time_zone_ = date::locate_zone(config_["timezone"].asString()); - fixed_time_zone_ = true; } if (config_["locale"].isString()) { @@ -72,6 +76,17 @@ auto waybar::modules::Clock::update() -> void { ALabel::update(); } +bool waybar::modules::Clock::setTimeZone(Json::Value zone_name) { + if (!zone_name.isString() || zone_name.asString().empty()) { + fixed_time_zone_ = false; + return false; + } + + time_zone_ = date::locate_zone(zone_name.asString()); + fixed_time_zone_ = true; + return true; +} + bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) { // defer to user commands if set if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) { @@ -92,14 +107,7 @@ bool waybar::modules::Clock::handleScroll(GdkEventScroll *e) { } else { time_zone_idx_ = time_zone_idx_ == 0 ? nr_zones - 1 : time_zone_idx_ - 1; } - auto zone_name = config_["timezones"][time_zone_idx_]; - if (!zone_name.isString() || zone_name.empty()) { - fixed_time_zone_ = false; - } else { - time_zone_ = date::locate_zone(zone_name.asString()); - fixed_time_zone_ = true; - } - + setTimeZone(config_["timezones"][time_zone_idx_]); update(); return true; } From 75a6dddea5ae5f96d40e0b823ee65bf94ef329f6 Mon Sep 17 00:00:00 2001 From: dmitry Date: Wed, 20 Oct 2021 01:23:00 +0300 Subject: [PATCH 42/61] Finish --- include/modules/wlr/taskbar.hpp | 1 + man/waybar-wlr-taskbar.5.scd | 2 +- src/modules/wlr/taskbar.cpp | 20 ++++++++++++-------- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index 891ad55..f9233ba 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -77,6 +77,7 @@ class Task private: std::string repr() const; std::string state_string(bool = false) const; + void hide_if_ignored(); public: /* Getter functions */ diff --git a/man/waybar-wlr-taskbar.5.scd b/man/waybar-wlr-taskbar.5.scd index 0e86238..6645cc2 100644 --- a/man/waybar-wlr-taskbar.5.scd +++ b/man/waybar-wlr-taskbar.5.scd @@ -70,7 +70,7 @@ Addressed by *wlr/taskbar* *ignore-list*: ++ typeof: array ++ - List of app_id to be invisible. + List of app_id/titles to be invisible. # FORMAT REPLACEMENTS diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index 932a95e..b27e9f8 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -276,8 +276,7 @@ Task::Task(const waybar::Bar &bar, const Json::Value &config, Taskbar *tbar, struct zwlr_foreign_toplevel_handle_v1 *tl_handle, struct wl_seat *seat) : bar_{bar}, config_{config}, tbar_{tbar}, handle_{tl_handle}, seat_{seat}, id_{global_id++}, - content_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0}, - button_visible_{false}, ignored_{false} + content_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} { zwlr_foreign_toplevel_handle_v1_add_listener(handle_, &toplevel_handle_impl, this); @@ -377,13 +376,12 @@ std::string Task::state_string(bool shortened) const void Task::handle_title(const char *title) { title_ = title; + hide_if_ignored(); } -void Task::handle_app_id(const char *app_id) +void Task::hide_if_ignored() { - app_id_ = app_id; - - if (tbar_->ignore_list().count(app_id)) { + if (tbar_->ignore_list().count(app_id_) || tbar_->ignore_list().count(title_)) { ignored_ = true; if (button_visible_) { auto output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); @@ -397,6 +395,12 @@ void Task::handle_app_id(const char *app_id) handle_output_enter(output); } } +} + +void Task::handle_app_id(const char *app_id) +{ + app_id_ = app_id; + hide_if_ignored(); if (!with_icon_) return; @@ -418,13 +422,13 @@ void Task::handle_app_id(const char *app_id) void Task::handle_output_enter(struct wl_output *output) { - spdlog::debug("{} entered output {}", repr(), (void*)output); - if (ignored_) { spdlog::debug("{} is ignored", repr()); return; } + spdlog::debug("{} entered output {}", repr(), (void*)output); + if (!button_visible_ && (tbar_->all_outputs() || tbar_->show_output(output))) { /* The task entered the output of the current bar make the button visible */ tbar_->add_button(button_); From 0b66454d5c9cf526b889d16cd656cd2c4834c7ee Mon Sep 17 00:00:00 2001 From: Robin Ebert Date: Wed, 20 Oct 2021 11:11:49 +0200 Subject: [PATCH 43/61] Add spacing config option This option allows to add spaces between the modules. It uses Gtk:Box's spacing property. --- src/bar.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bar.cpp b/src/bar.cpp index 7d76359..54e487d 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -438,6 +438,13 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) center_.get_style_context()->add_class("modules-center"); right_.get_style_context()->add_class("modules-right"); + if (config["spacing"].isInt()) { + int spacing = config["spacing"].asInt(); + left_.set_spacing(spacing); + center_.set_spacing(spacing); + right_.set_spacing(spacing); + } + uint32_t height = config["height"].isUInt() ? config["height"].asUInt() : 0; uint32_t width = config["width"].isUInt() ? config["width"].asUInt() : 0; From 7669029bfece53d171eead18baff0520a52859fb Mon Sep 17 00:00:00 2001 From: Robin Ebert Date: Wed, 20 Oct 2021 11:15:49 +0200 Subject: [PATCH 44/61] Add man documentation for spacing config option --- man/waybar.5.scd.in | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 997a48d..eaa8d78 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -64,6 +64,10 @@ Also a minimal example configuration can be found on the at the bottom of this m typeof: integer ++ Margins value without units. +*spacing* ++ + typeof: integer ++ + Size of gaps in between of the different modules. + *name* ++ typeof: string ++ Optional name added as a CSS class, for styling multiple waybars. From 01bfbc46560bf2daac3317b9541b46196e6673fd Mon Sep 17 00:00:00 2001 From: Robin Ebert Date: Wed, 20 Oct 2021 11:23:57 +0200 Subject: [PATCH 45/61] Use spacing in config --- resources/config | 1 + resources/style.css | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/config b/resources/config index b315721..063393b 100644 --- a/resources/config +++ b/resources/config @@ -3,6 +3,7 @@ // "position": "bottom", // Waybar position (top|bottom|left|right) "height": 30, // Waybar height (to be removed for auto height) // "width": 1280, // Waybar width + "spacing": 4, // Gaps between modules (4px) // Choose the order of the modules "modules-left": ["sway/workspaces", "sway/mode", "custom/media"], "modules-center": ["sway/window"], diff --git a/resources/style.css b/resources/style.css index c0d4d9b..0235942 100644 --- a/resources/style.css +++ b/resources/style.css @@ -80,7 +80,6 @@ window#waybar.chromium { #idle_inhibitor, #mpd { padding: 0 10px; - margin: 0 4px; color: #ffffff; } From a015b2e3db979fa4603f8d942d0f2e2877b9327b Mon Sep 17 00:00:00 2001 From: jonbakke <49371446+jonbakke@users.noreply.github.com> Date: Thu, 28 Oct 2021 09:37:11 -0700 Subject: [PATCH 46/61] Clarify less than/greater than in warning. I was seeing "[warning] Requested height: 20 exceeds the minimum height: 30 required..." Lines 114-134 are relevant; 133 overrides the requested height with the minimum height when GTK wants more pixels to work with. So, the code is behaving as expected, and "less than" matches the code's logic. --- src/bar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bar.cpp b/src/bar.cpp index 54e487d..a8b230e 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -13,10 +13,10 @@ namespace waybar { static constexpr const char* MIN_HEIGHT_MSG = - "Requested height: {} exceeds the minimum height: {} required by the modules"; + "Requested height: {} is less than the minimum height: {} required by the modules"; static constexpr const char* MIN_WIDTH_MSG = - "Requested width: {} exceeds the minimum width: {} required by the modules"; + "Requested width: {} is less than the minimum width: {} required by the modules"; static constexpr const char* BAR_SIZE_MSG = "Bar configured (width: {}, height: {}) for output: {}"; From decb13eef0a3c42d5bf7356c0d21f6fc5af93585 Mon Sep 17 00:00:00 2001 From: Marwin Glaser Date: Thu, 28 Oct 2021 19:10:46 +0200 Subject: [PATCH 47/61] mark zfs arc size as free in memory --- src/modules/memory/common.cpp | 4 ++-- src/modules/memory/linux.cpp | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/modules/memory/common.cpp b/src/modules/memory/common.cpp index 31219ed..75e0530 100644 --- a/src/modules/memory/common.cpp +++ b/src/modules/memory/common.cpp @@ -15,11 +15,11 @@ auto waybar::modules::Memory::update() -> void { unsigned long memfree; if (meminfo_.count("MemAvailable")) { // New kernels (3.4+) have an accurate available memory field. - memfree = meminfo_["MemAvailable"]; + memfree = meminfo_["MemAvailable"] + meminfo_["zfs_size"]; } else { // Old kernel; give a best-effort approximation of available memory. memfree = meminfo_["MemFree"] + meminfo_["Buffers"] + meminfo_["Cached"] + - meminfo_["SReclaimable"] - meminfo_["Shmem"]; + meminfo_["SReclaimable"] - meminfo_["Shmem"] + meminfo_["zfs_size"]; } if (memtotal > 0 && memfree >= 0) { diff --git a/src/modules/memory/linux.cpp b/src/modules/memory/linux.cpp index 75f05fe..34d55c9 100644 --- a/src/modules/memory/linux.cpp +++ b/src/modules/memory/linux.cpp @@ -1,8 +1,29 @@ #include "modules/memory.hpp" +static unsigned zfsArcSize() { + std::ifstream zfs_arc_stats{"/proc/spl/kstat/zfs/arcstats"}; + + if (zfs_arc_stats.is_open()) { + std::string name; + std::string type; + unsigned long data{0}; + + std::string line; + while (std::getline(zfs_arc_stats, line)) { + std::stringstream(line) >> name >> type >> data; + + if (name == "size") { + return data / 1024; // convert to kB + } + } + } + + return 0; +} + void waybar::modules::Memory::parseMeminfo() { const std::string data_dir_ = "/proc/meminfo"; - std::ifstream info(data_dir_); + std::ifstream info(data_dir_); if (!info.is_open()) { throw std::runtime_error("Can't open " + data_dir_); } @@ -17,4 +38,6 @@ void waybar::modules::Memory::parseMeminfo() { int64_t value = std::stol(line.substr(posDelim + 1)); meminfo_[name] = value; } + + meminfo_["zfs_size"] = zfsArcSize(); } From 48117a2e971e3d64dd1a7321802da9019a1fc9e1 Mon Sep 17 00:00:00 2001 From: Mohammad Amin Sameti Date: Fri, 29 Oct 2021 14:12:48 +0330 Subject: [PATCH 48/61] Fix divide by zero (#1303) --- src/ALabel.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/ALabel.cpp b/src/ALabel.cpp index dd41a32..b9b3d1d 100644 --- a/src/ALabel.cpp +++ b/src/ALabel.cpp @@ -67,8 +67,10 @@ std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_ } if (format_icons.isArray()) { auto size = format_icons.size(); - auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1); - format_icons = format_icons[idx]; + if (size) { + auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1); + format_icons = format_icons[idx]; + } } if (format_icons.isString()) { return format_icons.asString(); @@ -90,8 +92,10 @@ std::string ALabel::getIcon(uint16_t percentage, const std::vector& } if (format_icons.isArray()) { auto size = format_icons.size(); - auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1); - format_icons = format_icons[idx]; + if (size) { + auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1); + format_icons = format_icons[idx]; + } } if (format_icons.isString()) { return format_icons.asString(); From 769b12f16a05f1c86c9966810dee93185bbc8a15 Mon Sep 17 00:00:00 2001 From: Birger Schacht <1143280+b1rger@users.noreply.github.com> Date: Sat, 6 Nov 2021 09:00:15 +0000 Subject: [PATCH 49/61] Fix typo --- man/waybar-battery.5.scd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/waybar-battery.5.scd b/man/waybar-battery.5.scd index 48c2ee1..e8053c9 100644 --- a/man/waybar-battery.5.scd +++ b/man/waybar-battery.5.scd @@ -120,7 +120,7 @@ The two arguments are: # CUSTOM FORMATS -The *battery* module allows to define custom formats based on up to two factors. The best fitting format will be selected. +The *battery* module allows one to define custom formats based on up to two factors. The best fitting format will be selected. *format-*: With *states*, a custom format can be set depending on the capacity of your battery. From b24f9ea5690a949f91f367eb90bbe25472f55a74 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Thu, 11 Nov 2021 21:42:05 +0100 Subject: [PATCH 50/61] Ensure MPD volume is not negative If the primary output does not support changing volume MPD will report -1. Ensure that negative volume levels will be represented as 0 instead. Signed-off-by: Sefa Eyeoglu --- src/modules/mpd/mpd.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/mpd/mpd.cpp b/src/modules/mpd/mpd.cpp index 0a7c970..6d27286 100644 --- a/src/modules/mpd/mpd.cpp +++ b/src/modules/mpd/mpd.cpp @@ -131,6 +131,9 @@ void waybar::modules::MPD::setLabel() { date = getTag(MPD_TAG_DATE); song_pos = mpd_status_get_song_pos(status_.get()); volume = mpd_status_get_volume(status_.get()); + if (volume < 0) { + volume = 0; + } queue_length = mpd_status_get_queue_length(status_.get()); elapsedTime = std::chrono::seconds(mpd_status_get_elapsed_time(status_.get())); totalTime = std::chrono::seconds(mpd_status_get_total_time(status_.get())); From ad3f46214d791b98364dd95719ee49c9446f20a5 Mon Sep 17 00:00:00 2001 From: John Fredriksson <94405030+jfred9@users.noreply.github.com> Date: Mon, 15 Nov 2021 21:23:36 +0100 Subject: [PATCH 51/61] river/tags: Add possibility for mouse clicks Left mouse click - set-focused-tags Right mouse click - toggle-focused-tags --- include/modules/river/tags.hpp | 6 ++ man/waybar-river-tags.5.scd | 5 ++ protocol/meson.build | 1 + protocol/river-control-unstable-v1.xml | 85 ++++++++++++++++++++++++++ src/modules/river/tags.cpp | 72 +++++++++++++++++++++- 5 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 protocol/river-control-unstable-v1.xml diff --git a/include/modules/river/tags.hpp b/include/modules/river/tags.hpp index 9b75fbd..c49ec60 100644 --- a/include/modules/river/tags.hpp +++ b/include/modules/river/tags.hpp @@ -6,6 +6,7 @@ #include "AModule.hpp" #include "bar.hpp" #include "river-status-unstable-v1-client-protocol.h" +#include "river-control-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" namespace waybar::modules::river { @@ -20,7 +21,12 @@ class Tags : public waybar::AModule { void handle_view_tags(struct wl_array *tags); void handle_urgent_tags(uint32_t tags); + void handle_primary_clicked(uint32_t tag); + bool handle_button_press(GdkEventButton *event_button, uint32_t tag); + struct zriver_status_manager_v1 *status_manager_; + struct zriver_control_v1 *control_; + struct wl_seat *seat_; private: const waybar::Bar & bar_; diff --git a/man/waybar-river-tags.5.scd b/man/waybar-river-tags.5.scd index 65b9033..7814ee4 100644 --- a/man/waybar-river-tags.5.scd +++ b/man/waybar-river-tags.5.scd @@ -21,6 +21,11 @@ Addressed by *river/tags* typeof: array ++ The label to display for each tag. +*disable-click*: ++ + typeof: bool ++ + default: false ++ + If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled. + # EXAMPLE ``` diff --git a/protocol/meson.build b/protocol/meson.build index 07d524a..ea988ef 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -28,6 +28,7 @@ client_protocols = [ ['wlr-layer-shell-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], ['river-status-unstable-v1.xml'], + ['river-control-unstable-v1.xml'], ] client_protos_src = [] diff --git a/protocol/river-control-unstable-v1.xml b/protocol/river-control-unstable-v1.xml new file mode 100644 index 0000000..b8faa45 --- /dev/null +++ b/protocol/river-control-unstable-v1.xml @@ -0,0 +1,85 @@ + + + + Copyright 2020 The River Developers + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + + + + This interface allows clients to run compositor commands and receive a + success/failure response with output or a failure message respectively. + + Each command is built up in a series of add_argument requests and + executed with a run_command request. The first argument is the command + to be run. + + A complete list of commands should be made available in the man page of + the compositor. + + + + + This request indicates that the client will not use the + river_control object any more. Objects that have been created + through this instance are not affected. + + + + + + Arguments are stored by the server in the order they were sent until + the run_command request is made. + + + + + + + Execute the command built up using the add_argument request for the + given seat. + + + + + + + + + This object is created by the run_command request. Exactly one of the + success or failure events will be sent. This object will be destroyed + by the compositor after one of the events is sent. + + + + + Sent when the command has been successfully received and executed by + the compositor. Some commands may produce output, in which case the + output argument will be a non-empty string. + + + + + + + Sent when the command could not be carried out. This could be due to + sending a non-existent command, no command, not enough arguments, too + many arguments, invalid arguments, etc. + + + + + diff --git a/src/modules/river/tags.cpp b/src/modules/river/tags.cpp index 2628af2..87655be 100644 --- a/src/modules/river/tags.cpp +++ b/src/modules/river/tags.cpp @@ -7,7 +7,6 @@ #include "client.hpp" #include "modules/river/tags.hpp" -#include "river-status-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" namespace waybar::modules::river { @@ -33,6 +32,23 @@ static const zriver_output_status_v1_listener output_status_listener_impl{ .urgent_tags = listen_urgent_tags, }; +static void listen_command_success(void *data, + struct zriver_command_callback_v1 *zriver_command_callback_v1, + const char *output) { + // Do nothing but keep listener to avoid crashing when command was successful +} + +static void listen_command_failure(void *data, + struct zriver_command_callback_v1 *zriver_command_callback_v1, + const char *output) { + spdlog::error("failure when selecting/toggling tags {}", output); +} + +static const zriver_command_callback_v1_listener command_callback_listener_impl { + .success = listen_command_success, + .failure = listen_command_failure, +}; + static void handle_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { if (std::strcmp(interface, zriver_status_manager_v1_interface.name) == 0) { @@ -43,18 +59,33 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam static_cast(data)->status_manager_ = static_cast( wl_registry_bind(registry, name, &zriver_status_manager_v1_interface, version)); } + + if (std::strcmp(interface, zriver_control_v1_interface.name) == 0) { + version = std::min(version, 1); + static_cast(data)->control_ = static_cast( + wl_registry_bind(registry, name, &zriver_control_v1_interface, version)); + } + + if (std::strcmp(interface, wl_seat_interface.name) == 0) { + version = std::min(version, 1); + static_cast(data)->seat_ = static_cast( + wl_registry_bind(registry, name, &wl_seat_interface, version)); + } } static void handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) { /* Ignore event */ } + static const wl_registry_listener registry_listener_impl = {.global = handle_global, .global_remove = handle_global_remove}; Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &config) : waybar::AModule(config, "tags", id, false, false), status_manager_{nullptr}, + control_{nullptr}, + seat_{nullptr}, bar_(bar), box_{bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0}, output_status_{nullptr} { @@ -68,6 +99,14 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con return; } + if (!control_) { + spdlog::error("river_control_v1 not advertised"); + } + + if (!seat_) { + spdlog::error("wl_seat not advertised"); + } + box_.set_name("tags"); if (!id.empty()) { box_.get_style_context()->add_class(id); @@ -89,11 +128,17 @@ Tags::Tags(const std::string &id, const waybar::Bar &bar, const Json::Value &con } } + uint32_t i = 1; for (const auto &tag_label : tag_labels) { Gtk::Button &button = buttons_.emplace_back(tag_label); button.set_relief(Gtk::RELIEF_NONE); box_.pack_start(button, false, false, 0); + if (!config_["disable-click"].asBool()) { + button.signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &Tags::handle_primary_clicked), i)); + button.signal_button_press_event().connect(sigc::bind(sigc::mem_fun(*this, &Tags::handle_button_press), i)); + } button.show(); + i <<= 1; } struct wl_output *output = gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); @@ -107,6 +152,31 @@ Tags::~Tags() { if (output_status_) { zriver_output_status_v1_destroy(output_status_); } + + if (control_) { + zriver_control_v1_destroy(control_); + } +} + +void Tags::handle_primary_clicked(uint32_t tag) { + // Send river command to select tag on left mouse click + zriver_command_callback_v1 *callback; + zriver_control_v1_add_argument(control_, "set-focused-tags"); + zriver_control_v1_add_argument(control_, std::to_string(tag).c_str()); + callback = zriver_control_v1_run_command(control_, seat_); + zriver_command_callback_v1_add_listener(callback, &command_callback_listener_impl, nullptr); +} + +bool Tags::handle_button_press(GdkEventButton *event_button, uint32_t tag) { + if (event_button->type == GDK_BUTTON_PRESS && event_button->button == 3) { + // Send river command to toggle tag on right mouse click + zriver_command_callback_v1 *callback; + zriver_control_v1_add_argument(control_, "toggle-focused-tags"); + zriver_control_v1_add_argument(control_, std::to_string(tag).c_str()); + callback = zriver_control_v1_run_command(control_, seat_); + zriver_command_callback_v1_add_listener(callback, &command_callback_listener_impl, nullptr); + } + return true; } void Tags::handle_focused_tags(uint32_t tags) { From 23955fdcc25ea40cc8d7b4d1386cc83f0ed0ddff Mon Sep 17 00:00:00 2001 From: Anakael Date: Fri, 19 Nov 2021 18:38:59 +0300 Subject: [PATCH 52/61] Update taskbar.hpp --- include/modules/wlr/taskbar.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index f9233ba..cdef9f1 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -77,7 +77,7 @@ class Task private: std::string repr() const; std::string state_string(bool = false) const; - void hide_if_ignored(); + void hide_if_ignored(); public: /* Getter functions */ From 18ea53fcbcefe445f98a6f8575bcd1944d2c7710 Mon Sep 17 00:00:00 2001 From: Anakael Date: Fri, 19 Nov 2021 18:39:49 +0300 Subject: [PATCH 53/61] Update taskbar.hpp --- include/modules/wlr/taskbar.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index cdef9f1..c7e6628 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -77,7 +77,7 @@ class Task private: std::string repr() const; std::string state_string(bool = false) const; - void hide_if_ignored(); + void hide_if_ignored(); public: /* Getter functions */ From cb6af026f632d4cb56546bbce73ad114c01a9957 Mon Sep 17 00:00:00 2001 From: Anakael Date: Fri, 19 Nov 2021 18:51:28 +0300 Subject: [PATCH 54/61] Update taskbar.hpp --- include/modules/wlr/taskbar.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/modules/wlr/taskbar.hpp b/include/modules/wlr/taskbar.hpp index c7e6628..3fe032f 100644 --- a/include/modules/wlr/taskbar.hpp +++ b/include/modules/wlr/taskbar.hpp @@ -61,8 +61,8 @@ class Task Gtk::Image icon_; Gtk::Label text_before_; Gtk::Label text_after_; - bool button_visible_; - bool ignored_; + bool button_visible_ = false; + bool ignored_ = false; bool with_icon_; std::string format_before_; From 60c1706273808937ab460367d350f217e31ebfb0 Mon Sep 17 00:00:00 2001 From: Anakael Date: Fri, 19 Nov 2021 18:54:37 +0300 Subject: [PATCH 55/61] Update taskbar.cpp --- src/modules/wlr/taskbar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/wlr/taskbar.cpp b/src/modules/wlr/taskbar.cpp index b27e9f8..af1b0da 100644 --- a/src/modules/wlr/taskbar.cpp +++ b/src/modules/wlr/taskbar.cpp @@ -376,7 +376,7 @@ std::string Task::state_string(bool shortened) const void Task::handle_title(const char *title) { title_ = title; - hide_if_ignored(); + hide_if_ignored(); } void Task::hide_if_ignored() @@ -400,7 +400,7 @@ void Task::hide_if_ignored() void Task::handle_app_id(const char *app_id) { app_id_ = app_id; - hide_if_ignored(); + hide_if_ignored(); if (!with_icon_) return; From 4154492603ddec3fc8e091cf34bcbc8081fa780a Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Fri, 19 Nov 2021 20:35:51 -0800 Subject: [PATCH 56/61] ci: update FreeBSD configuration Use latest action v0.1.5. Pin runner to macos-10.15. macos-latest will start using macos-11 images without VirtualBox in less than a month[1]. [1] https://github.com/actions/virtual-environments/issues/4060 --- .github/workflows/freebsd.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index 8af7a04..03e5d70 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -4,11 +4,14 @@ on: [ push, pull_request ] jobs: clang: - runs-on: macos-latest # until https://github.com/actions/runner/issues/385 + # Run actions in a FreeBSD vm on the macos-10.15 runner + # https://github.com/actions/runner/issues/385 - for FreeBSD runner support + # https://github.com/actions/virtual-environments/issues/4060 - for lack of VirtualBox on MacOS 11 runners + runs-on: macos-10.15 steps: - uses: actions/checkout@v2 - name: Test in FreeBSD VM - uses: vmactions/freebsd-vm@v0.1.4 # aka FreeBSD 12.2 + uses: vmactions/freebsd-vm@v0.1.5 # aka FreeBSD 13.0 with: usesh: true prepare: | From ffeecf626ceaaa3dfd2ac4f2a9bd6b0c3f5a40ae Mon Sep 17 00:00:00 2001 From: dmitry Date: Sun, 21 Nov 2021 15:01:25 +0300 Subject: [PATCH 57/61] Update names --- include/modules/wlr/workspace_manager.hpp | 16 +-- .../modules/wlr/workspace_manager_binding.hpp | 10 +- ...e-v1.xml => ext-workspace-unstable-v1.xml} | 104 ++++++++++++------ protocol/meson.build | 2 +- src/modules/wlr/workspace_manager.cpp | 28 ++--- src/modules/wlr/workspace_manager_binding.cpp | 54 ++++----- 6 files changed, 125 insertions(+), 89 deletions(-) rename protocol/{wlr-workspace-unstable-v1.xml => ext-workspace-unstable-v1.xml} (73%) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index 73c5893..02f4e37 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -11,7 +11,7 @@ #include "AModule.hpp" #include "bar.hpp" -#include "wlr-workspace-unstable-v1-client-protocol.h" +#include "ext-workspace-unstable-v1-client-protocol.h" namespace waybar::modules::wlr { @@ -21,7 +21,7 @@ class WorkspaceGroup; class Workspace { public: Workspace(const waybar::Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, - zwlr_workspace_handle_v1 *workspace, uint32_t id); + zext_workspace_handle_v1 *workspace, uint32_t id); ~Workspace(); auto update() -> void; @@ -51,7 +51,7 @@ class Workspace { WorkspaceGroup & workspace_group_; // wlr stuff - zwlr_workspace_handle_v1 *workspace_handle_; + zext_workspace_handle_v1 *workspace_handle_; uint32_t state_ = 0; uint32_t id_; @@ -69,7 +69,7 @@ class Workspace { class WorkspaceGroup { public: WorkspaceGroup(const waybar::Bar &bar, Gtk::Box &box, const Json::Value &config, - WorkspaceManager &manager, zwlr_workspace_group_handle_v1 *workspace_group_handle, + WorkspaceManager &manager, zext_workspace_group_handle_v1 *workspace_group_handle, uint32_t id); ~WorkspaceGroup(); auto update() -> void; @@ -79,7 +79,7 @@ class WorkspaceGroup { auto remove_workspace(uint32_t id_) -> void; // wlr stuff - auto handle_workspace_create(zwlr_workspace_handle_v1 *workspace_handle) -> void; + auto handle_workspace_create(zext_workspace_handle_v1 *workspace_handle) -> void; auto handle_remove() -> void; auto handle_output_enter(wl_output *output) -> void; auto handle_output_leave() -> void; @@ -98,7 +98,7 @@ class WorkspaceGroup { WorkspaceManager & workspace_manager_; // wlr stuff - zwlr_workspace_group_handle_v1 *workspace_group_handle_; + zext_workspace_group_handle_v1 *workspace_group_handle_; wl_output * output_ = nullptr; uint32_t id_; @@ -117,7 +117,7 @@ class WorkspaceManager : public AModule { // wlr stuff auto register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void; - auto handle_workspace_group_create(zwlr_workspace_group_handle_v1 *workspace_group_handle) + auto handle_workspace_group_create(zext_workspace_group_handle_v1 *workspace_group_handle) -> void; auto handle_done() -> void; auto handle_finished() -> void; @@ -130,7 +130,7 @@ class WorkspaceManager : public AModule { std::vector> groups_; // wlr stuff - zwlr_workspace_manager_v1 *workspace_manager_ = nullptr; + zext_workspace_manager_v1 *workspace_manager_ = nullptr; static uint32_t group_global_id; }; diff --git a/include/modules/wlr/workspace_manager_binding.hpp b/include/modules/wlr/workspace_manager_binding.hpp index 1cef652..0bfe663 100644 --- a/include/modules/wlr/workspace_manager_binding.hpp +++ b/include/modules/wlr/workspace_manager_binding.hpp @@ -1,8 +1,8 @@ -#include "wlr-workspace-unstable-v1-client-protocol.h" +#include "ext-workspace-unstable-v1-client-protocol.h" namespace waybar::modules::wlr { void add_registry_listener(void *data); - void add_workspace_listener(zwlr_workspace_handle_v1 *workspace_handle, void *data); - void add_workspace_group_listener(zwlr_workspace_group_handle_v1 *workspace_group_handle, void *data); - zwlr_workspace_manager_v1* workspace_manager_bind(wl_registry *registry, uint32_t name, uint32_t version, void *data); -} \ No newline at end of file + void add_workspace_listener(zext_workspace_handle_v1 *workspace_handle, void *data); + void add_workspace_group_listener(zext_workspace_group_handle_v1 *workspace_group_handle, void *data); + zext_workspace_manager_v1* workspace_manager_bind(wl_registry *registry, uint32_t name, uint32_t version, void *data); +} diff --git a/protocol/wlr-workspace-unstable-v1.xml b/protocol/ext-workspace-unstable-v1.xml similarity index 73% rename from protocol/wlr-workspace-unstable-v1.xml rename to protocol/ext-workspace-unstable-v1.xml index ae0e44d..24410b6 100644 --- a/protocol/wlr-workspace-unstable-v1.xml +++ b/protocol/ext-workspace-unstable-v1.xml @@ -1,5 +1,5 @@ - + Copyright © 2019 Christopher Billington Copyright © 2020 Ilia Bozhinov @@ -26,7 +26,7 @@ THIS SOFTWARE. - + Workspaces, also called virtual desktops, are groups of surfaces. A compositor with a concept of workspaces may only show some such groups of @@ -45,7 +45,7 @@ docks by providing them with a list of workspaces and their properties, and allowing them to activate and deactivate workspaces. - After a client binds the zwlr_workspace_manager_v1, each workspace will be + After a client binds the zext_workspace_manager_v1, each workspace will be sent via the workspace event. @@ -55,9 +55,9 @@ All initial details of the workspace group (workspaces, outputs) will be sent immediately after this event via the corresponding events in - zwlr_workspace_group_handle_v1. + zext_workspace_group_handle_v1. - + @@ -68,21 +68,21 @@ This allows changes to the workspace properties to be seen as atomic, even if they happen via multiple events, and even if they involve - multiple zwlr_workspace_handle_v1 objects, for example, deactivating one + multiple zext_workspace_handle_v1 objects, for example, deactivating one workspace and activating another. - This event is sent after all changes in all workspace groups have been - sent. + This event is sent after all changes in all workspace groups have been + sent. - This allows changes to one or more zwlr_workspace_group_handle_v1 + This allows changes to one or more zext_workspace_group_handle_v1 properties to be seen as atomic, even if they happen via multiple events. In particular, an output moving from one workspace group to another sends an output_enter event and an output_leave event to the two - zwlr_workspace_group_handle_v1 objects in question. The compositor sends + zext_workspace_group_handle_v1 objects in question. The compositor sends the done event only after updating the output information in both workspace groups. @@ -91,7 +91,7 @@ This event indicates that the compositor is done sending events to the - zwlr_workspace_manager_v1. The server will destroy the object + zext_workspace_manager_v1. The server will destroy the object immediately after sending this request, so it will become invalid and the client should free any resources associated with it. @@ -108,14 +108,19 @@ - + - A zwlr_workspace_group_handle_v1 object represents a a workspace group + A zext_workspace_group_handle_v1 object represents a a workspace group that is assigned a set of outputs and contains a number of workspaces. The set of outputs assigned to the workspace group is conveyed to the client via output_enter and output_leave events, and its workspaces are conveyed with workspace events. + + For example, a compositor which has a set of workspaces for each output may + advertise a workspace group (and its workspaces) per output, whereas a compositor + where a workspace spans all outputs may advertise a single workspace group for all + outputs. @@ -140,26 +145,36 @@ All initial details of the workspace (name, coordinates, state) will be sent immediately after this event via the corresponding events in - zwlr_workspace_handle_v1. + zext_workspace_handle_v1. - + - This event means the zwlr_workspace_group_handle_v1 has been destroyed. - It is guaranteed there won't be any more events for this - zwlr_workspace_group_handle_v1. The zwlr_workspace_group_handle_v1 becomes - inert so any requests will be ignored except the destroy request. + This event means the zext_workspace_group_handle_v1 has been destroyed. + It is guaranteed there won't be any more events for this + zext_workspace_group_handle_v1. The zext_workspace_group_handle_v1 becomes + inert so any requests will be ignored except the destroy request. - The compositor must remove all workspaces belonging to a workspace group - before removing the workspace group. + The compositor must remove all workspaces belonging to a workspace group + before removing the workspace group. + + + Request that the compositor create a new workspace with the given name. + + There is no guarantee that the compositor will create a new workspace, + or that the created workspace will have the provided name. + + + + - - Destroys the zwlr_workspace_handle_v1 object. + + Destroys the zext_workspace_handle_v1 object. This request should be called either when the client does not want to use the workspace object any more or after the remove event to finalize @@ -168,9 +183,9 @@ - + - A zwlr_workspace_handle_v1 object represents a a workspace that handles a + A zext_workspace_handle_v1 object represents a a workspace that handles a group of surfaces. Each workspace has a name, conveyed to the client with the name event; a @@ -178,11 +193,16 @@ optionally a set of coordinates, conveyed to the client with the coordinates event. The client may request that the compositor activate or deactivate the workspace. + + Each workspace can belong to only a single workspace group. + Depepending on the compositor policy, there might be workspaces with + the same name in different workspace groups, but these workspaces are still + separate (e.g. one of them might be active while the other is not). - This event is emitted immediately after the zwlr_workspace_handle_v1 is + This event is emitted immediately after the zext_workspace_handle_v1 is created and whenever the name of the workspace changes. @@ -192,13 +212,13 @@ This event is used to organize workspaces into an N-dimensional grid within a workspace group, and if supported, is emitted immediately after - the zwlr_workspace_handle_v1 is created and whenever the coordinates of + the zext_workspace_handle_v1 is created and whenever the coordinates of the workspace change. Compositors may not send this event if they do not conceptually arrange workspaces in this way. If compositors simply number workspaces, without any geometric interpretation, they may send 1D coordinates, which clients should not interpret as implying any - geometry. Sending an empty array means that the compositor no longer - orders the workspace geometrically. + geometry. Sending an empty array means that the compositor no longer + orders the workspace geometrically. Coordinates have an arbitrary number of dimensions N with an uint32 position along each dimension. By convention if N > 1, the first @@ -214,7 +234,7 @@ - This event is emitted immediately after the zwlr_workspace_handle_v1 is + This event is emitted immediately after the zext_workspace_handle_v1 is created and each time the workspace state changes, either because of a compositor action or because of a request in this protocol. @@ -227,20 +247,28 @@ + + + + The workspace is not visible in its workspace group, and clients + attempting to visualize the compositor workspace state should not + display such workspaces. + + - This event means the zwlr_workspace_handle_v1 has been destroyed. It is + This event means the zext_workspace_handle_v1 has been destroyed. It is guaranteed there won't be any more events for this - zwlr_workspace_handle_v1. The zwlr_workspace_handle_v1 becomes inert so + zext_workspace_handle_v1. The zext_workspace_handle_v1 becomes inert so any requests will be ignored except the destroy request. - - Destroys the zwlr_workspace_handle_v1 object. + + Destroys the zext_workspace_handle_v1 object. This request should be called either when the client does not want to use the workspace object any more or after the remove event to finalize @@ -266,5 +294,13 @@ There is no guarantee the workspace will be actually deactivated. + + + + Request that this workspace be removed. + + There is no guarantee the workspace will be actually removed. + + diff --git a/protocol/meson.build b/protocol/meson.build index 467260b..f81cb0d 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -27,7 +27,7 @@ client_protocols = [ [wl_protocol_dir, 'unstable/idle-inhibit/idle-inhibit-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], - ['wlr-workspace-unstable-v1.xml'], + ['ext-workspace-unstable-v1.xml'], ['river-status-unstable-v1.xml'], ] diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 20294f4..26556ec 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -44,7 +44,7 @@ auto WorkspaceManager::register_manager(wl_registry *registry, uint32_t name, ui } auto WorkspaceManager::handle_workspace_group_create( - zwlr_workspace_group_handle_v1 *workspace_group_handle) -> void { + zext_workspace_group_handle_v1 *workspace_group_handle) -> void { auto new_id = ++group_global_id; groups_.push_back( std::make_unique(bar_, box_, config_, *this, workspace_group_handle, new_id)); @@ -52,7 +52,7 @@ auto WorkspaceManager::handle_workspace_group_create( } auto WorkspaceManager::handle_finished() -> void { - zwlr_workspace_manager_v1_destroy(workspace_manager_); + zext_workspace_manager_v1_destroy(workspace_manager_); workspace_manager_ = nullptr; } @@ -75,7 +75,7 @@ WorkspaceManager::~WorkspaceManager() { return; } - zwlr_workspace_manager_v1_destroy(workspace_manager_); + zext_workspace_manager_v1_destroy(workspace_manager_); workspace_manager_ = nullptr; } @@ -91,11 +91,11 @@ auto WorkspaceManager::remove_workspace_group(uint32_t id) -> void { groups_.erase(it); } -auto WorkspaceManager::commit() -> void { zwlr_workspace_manager_v1_commit(workspace_manager_); } +auto WorkspaceManager::commit() -> void { zext_workspace_manager_v1_commit(workspace_manager_); } WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value &config, WorkspaceManager & manager, - zwlr_workspace_group_handle_v1 *workspace_group_handle, uint32_t id) + zext_workspace_group_handle_v1 *workspace_group_handle, uint32_t id) : bar_(bar), box_(box), config_(config), @@ -123,18 +123,18 @@ WorkspaceGroup::~WorkspaceGroup() { return; } - zwlr_workspace_group_handle_v1_destroy(workspace_group_handle_); + zext_workspace_group_handle_v1_destroy(workspace_group_handle_); workspace_group_handle_ = nullptr; } -auto WorkspaceGroup::handle_workspace_create(zwlr_workspace_handle_v1 *workspace) -> void { +auto WorkspaceGroup::handle_workspace_create(zext_workspace_handle_v1 *workspace) -> void { auto new_id = ++workspace_global_id; workspaces_.push_back(std::make_unique(bar_, config_, *this, workspace, new_id)); spdlog::debug("Workspace {} created", new_id); } auto WorkspaceGroup::handle_remove() -> void { - zwlr_workspace_group_handle_v1_destroy(workspace_group_handle_); + zext_workspace_group_handle_v1_destroy(workspace_group_handle_); workspace_group_handle_ = nullptr; workspace_manager_.remove_workspace_group(id_); } @@ -226,7 +226,7 @@ auto WorkspaceGroup::remove_button(Gtk::Button &button) -> void { } Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, - zwlr_workspace_handle_v1 *workspace, uint32_t id) + zext_workspace_handle_v1 *workspace, uint32_t id) : bar_(bar), config_(config), workspace_group_(workspace_group), @@ -267,7 +267,7 @@ Workspace::~Workspace() { return; } - zwlr_workspace_handle_v1_destroy(workspace_handle_); + zext_workspace_handle_v1_destroy(workspace_handle_); workspace_handle_ = nullptr; } @@ -280,7 +280,7 @@ auto Workspace::handle_state(const std::vector &state) -> void { state_ = 0; for (auto state_entry : state) { switch (state_entry) { - case ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE: + case ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE: state_ |= (uint32_t)State::ACTIVE; break; } @@ -288,7 +288,7 @@ auto Workspace::handle_state(const std::vector &state) -> void { } auto Workspace::handle_remove() -> void { - zwlr_workspace_handle_v1_destroy(workspace_handle_); + zext_workspace_handle_v1_destroy(workspace_handle_); workspace_handle_ = nullptr; workspace_group_.remove_workspace(id_); } @@ -326,7 +326,7 @@ auto Workspace::get_icon() -> std::string { auto Workspace::handle_clicked() -> void { spdlog::debug("Workspace {} clicked", (void *)workspace_handle_); - zwlr_workspace_handle_v1_activate(workspace_handle_); + zext_workspace_handle_v1_activate(workspace_handle_); workspace_group_.commit(); } @@ -339,4 +339,4 @@ auto Workspace::handle_coordinates(const std::vector &coordinates) -> coordinates_ = coordinates; workspace_group_.sort_workspaces(); } -} // namespace waybar::modules::wlr \ No newline at end of file +} // namespace waybar::modules::wlr diff --git a/src/modules/wlr/workspace_manager_binding.cpp b/src/modules/wlr/workspace_manager_binding.cpp index c7d84bb..6a33973 100644 --- a/src/modules/wlr/workspace_manager_binding.cpp +++ b/src/modules/wlr/workspace_manager_binding.cpp @@ -9,7 +9,7 @@ namespace waybar::modules::wlr { static void handle_global(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { - if (std::strcmp(interface, zwlr_workspace_manager_v1_interface.name) == 0) { + if (std::strcmp(interface, zext_workspace_manager_v1_interface.name) == 0) { static_cast(data)->register_manager(registry, name, version); } } @@ -31,72 +31,72 @@ void add_registry_listener(void *data) { } static void workspace_manager_handle_workspace_group( - void *data, zwlr_workspace_manager_v1 *_, zwlr_workspace_group_handle_v1 *workspace_group) { + void *data, zext_workspace_manager_v1 *_, zext_workspace_group_handle_v1 *workspace_group) { static_cast(data)->handle_workspace_group_create(workspace_group); } -static void workspace_manager_handle_done(void *data, zwlr_workspace_manager_v1 *_) { +static void workspace_manager_handle_done(void *data, zext_workspace_manager_v1 *_) { static_cast(data)->handle_done(); } -static void workspace_manager_handle_finished(void *data, zwlr_workspace_manager_v1 *_) { +static void workspace_manager_handle_finished(void *data, zext_workspace_manager_v1 *_) { static_cast(data)->handle_finished(); } -static const zwlr_workspace_manager_v1_listener workspace_manager_impl = { +static const zext_workspace_manager_v1_listener workspace_manager_impl = { .workspace_group = workspace_manager_handle_workspace_group, .done = workspace_manager_handle_done, .finished = workspace_manager_handle_finished, }; -zwlr_workspace_manager_v1 *workspace_manager_bind(wl_registry *registry, uint32_t name, +zext_workspace_manager_v1 *workspace_manager_bind(wl_registry *registry, uint32_t name, uint32_t version, void *data) { - auto *workspace_manager = static_cast( - wl_registry_bind(registry, name, &zwlr_workspace_manager_v1_interface, version)); + auto *workspace_manager = static_cast( + wl_registry_bind(registry, name, &zext_workspace_manager_v1_interface, version)); if (workspace_manager) - zwlr_workspace_manager_v1_add_listener(workspace_manager, &workspace_manager_impl, data); + zext_workspace_manager_v1_add_listener(workspace_manager, &workspace_manager_impl, data); else spdlog::error("Failed to register manager"); return workspace_manager; } -static void workspace_group_handle_output_enter(void *data, zwlr_workspace_group_handle_v1 *_, +static void workspace_group_handle_output_enter(void *data, zext_workspace_group_handle_v1 *_, wl_output *output) { static_cast(data)->handle_output_enter(output); } -static void workspace_group_handle_output_leave(void *data, zwlr_workspace_group_handle_v1 *_, +static void workspace_group_handle_output_leave(void *data, zext_workspace_group_handle_v1 *_, wl_output *output) { static_cast(data)->handle_output_leave(); } -static void workspace_group_handle_workspace(void *data, zwlr_workspace_group_handle_v1 *_, - zwlr_workspace_handle_v1 *workspace) { +static void workspace_group_handle_workspace(void *data, zext_workspace_group_handle_v1 *_, + zext_workspace_handle_v1 *workspace) { static_cast(data)->handle_workspace_create(workspace); } -static void workspace_group_handle_remove(void *data, zwlr_workspace_group_handle_v1 *_) { +static void workspace_group_handle_remove(void *data, zext_workspace_group_handle_v1 *_) { static_cast(data)->handle_remove(); } -static const zwlr_workspace_group_handle_v1_listener workspace_group_impl = { +static const zext_workspace_group_handle_v1_listener workspace_group_impl = { .output_enter = workspace_group_handle_output_enter, .output_leave = workspace_group_handle_output_leave, .workspace = workspace_group_handle_workspace, .remove = workspace_group_handle_remove}; -void add_workspace_group_listener(zwlr_workspace_group_handle_v1 *workspace_group_handle, +void add_workspace_group_listener(zext_workspace_group_handle_v1 *workspace_group_handle, void * data) { - zwlr_workspace_group_handle_v1_add_listener(workspace_group_handle, &workspace_group_impl, data); + zext_workspace_group_handle_v1_add_listener(workspace_group_handle, &workspace_group_impl, data); } -void workspace_handle_name(void *data, struct zwlr_workspace_handle_v1 *_, const char *name) { +void workspace_handle_name(void *data, struct zext_workspace_handle_v1 *_, const char *name) { static_cast(data)->handle_name(name); } -void workspace_handle_coordinates(void *data, struct zwlr_workspace_handle_v1 *_, +void workspace_handle_coordinates(void *data, struct zext_workspace_handle_v1 *_, struct wl_array *coordinates) { std::vector coords_vec; auto coords = static_cast(coordinates->data); @@ -107,16 +107,16 @@ void workspace_handle_coordinates(void *data, struct zwlr_workspace_handle_v1 *_ static_cast(data)->handle_coordinates(coords_vec); } -void workspace_handle_state(void *data, struct zwlr_workspace_handle_v1 *workspace_handle, +void workspace_handle_state(void *data, struct zext_workspace_handle_v1 *workspace_handle, struct wl_array *state) { std::vector state_vec; auto states = static_cast(state->data); for (size_t i = 0; i < state->size; ++i) { // To sync server and pending states - if (states[i] == ZWLR_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { - zwlr_workspace_handle_v1_activate(workspace_handle); + if (states[i] == ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { + zext_workspace_handle_v1_activate(workspace_handle); } else { - zwlr_workspace_handle_v1_deactivate(workspace_handle); + zext_workspace_handle_v1_deactivate(workspace_handle); } state_vec.push_back(states[i]); } @@ -124,17 +124,17 @@ void workspace_handle_state(void *data, struct zwlr_workspace_handle_v1 *workspa static_cast(data)->handle_state(state_vec); } -void workspace_handle_remove(void *data, struct zwlr_workspace_handle_v1 *_) { +void workspace_handle_remove(void *data, struct zext_workspace_handle_v1 *_) { static_cast(data)->handle_remove(); } -static const zwlr_workspace_handle_v1_listener workspace_impl = { +static const zext_workspace_handle_v1_listener workspace_impl = { .name = workspace_handle_name, .coordinates = workspace_handle_coordinates, .state = workspace_handle_state, .remove = workspace_handle_remove}; -void add_workspace_listener(zwlr_workspace_handle_v1 *workspace_handle, void *data) { - zwlr_workspace_handle_v1_add_listener(workspace_handle, &workspace_impl, data); +void add_workspace_listener(zext_workspace_handle_v1 *workspace_handle, void *data) { + zext_workspace_handle_v1_add_listener(workspace_handle, &workspace_impl, data); } } // namespace waybar::modules::wlr From ef4c6a9ba3c65235e0af0c6456a14f39a4974408 Mon Sep 17 00:00:00 2001 From: dmitry Date: Mon, 22 Nov 2021 01:12:55 +0300 Subject: [PATCH 58/61] Update to proto. Fix displaying. Rename classes. --- include/modules/wlr/workspace_manager.hpp | 15 ++- man/waybar-wlr-workspaces.5.scd | 11 ++- src/modules/wlr/workspace_manager.cpp | 99 ++++++++++++++----- src/modules/wlr/workspace_manager_binding.cpp | 6 -- 4 files changed, 98 insertions(+), 33 deletions(-) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index 02f4e37..1fcfc22 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -27,6 +27,8 @@ class Workspace { auto id() const -> uint32_t { return id_; } auto is_active() const -> bool { return state_ & static_cast(State::ACTIVE); } + auto is_urgent() const -> bool { return state_ & static_cast(State::URGENT); } + auto is_hidden() const -> bool { return state_ & static_cast(State::HIDDEN); } // wlr stuff auto handle_name(const std::string &name) -> void; auto handle_coordinates(const std::vector &coordinates) -> void; @@ -34,14 +36,19 @@ class Workspace { auto handle_remove() -> void; auto handle_done() -> void; - auto handle_clicked() -> void; + auto handle_clicked(GdkEventButton *bt) -> bool; auto show() -> void { button_.show(); } auto hide() -> void { button_.hide(); } auto get_button_ref() -> Gtk::Button & { return button_; } auto get_name() -> std::string & { return name_; } auto get_coords() -> std::vector & { return coordinates_; } - enum class State { ACTIVE = 1 << 0 }; + enum class State + { + ACTIVE = 1 << 0, + URGENT = 1 << 1, + HIDDEN = 1 << 2, + }; private: auto get_icon() -> std::string; @@ -75,7 +82,7 @@ class WorkspaceGroup { auto update() -> void; auto id() const -> uint32_t { return id_; } - auto is_visible() const -> bool { return output_ != nullptr; } + auto is_visible() const -> bool; auto remove_workspace(uint32_t id_) -> void; // wlr stuff @@ -89,6 +96,7 @@ class WorkspaceGroup { auto handle_done() -> void; auto commit() -> void; auto sort_workspaces() -> void; + auto set_need_to_sort() -> void { need_to_sort = true; } private: static uint32_t workspace_global_id; @@ -105,6 +113,7 @@ class WorkspaceGroup { std::vector> workspaces_; bool sort_by_name = true; bool sort_by_coordinates = true; + bool need_to_sort = false; }; class WorkspaceManager : public AModule { diff --git a/man/waybar-wlr-workspaces.5.scd b/man/waybar-wlr-workspaces.5.scd index c1e827f..344d932 100644 --- a/man/waybar-wlr-workspaces.5.scd +++ b/man/waybar-wlr-workspaces.5.scd @@ -28,7 +28,7 @@ Addressed by *wlr/workspaces* *sort-by-coordinates*: ++ typeof: bool ++ - default: false ++ + default: true ++ Should workspaces be sorted by coordinates. Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first. If both are false - sort by id will be performed. @@ -39,6 +39,11 @@ Addressed by *wlr/workspaces* *{icon}*: Icon, as defined in *format-icons*. +# CLICK ACTIONS + +*activate*: Switch to workspace. +*close*: Close the workspace. + # ICONS Additional to workspace name matching, the following *format-icons* can be set. @@ -67,4 +72,6 @@ Additional to workspace name matching, the following *format-icons* can be set. - *#workspaces* - *#workspaces button* -- *#workspaces button.focused* +- *#workspaces button.active* +- *#workspaces button.urgent* +- *#workspaces button.hidden* diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 26556ec..1d67b04 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -143,15 +143,19 @@ auto WorkspaceGroup::handle_output_enter(wl_output *output) -> void { spdlog::debug("Output {} assigned to {} group", (void *)output, id_); output_ = output; - if (output != gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj())) { - return; + if (!is_visible()) { + return; } for (auto &workspace : workspaces_) { - workspace->show(); + add_button(workspace->get_button_ref()); } } +auto WorkspaceGroup::is_visible() const -> bool { + return output_ != nullptr && output_ == gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); +} + auto WorkspaceGroup::handle_output_leave() -> void { spdlog::debug("Output {} remove from {} group", (void *)output_, id_); output_ = nullptr; @@ -161,7 +165,7 @@ auto WorkspaceGroup::handle_output_leave() -> void { } for (auto &workspace : workspaces_) { - workspace->hide(); + remove_button(workspace->get_button_ref()); } } @@ -185,9 +189,16 @@ auto WorkspaceGroup::remove_workspace(uint32_t id) -> void { } auto WorkspaceGroup::handle_done() -> void { + need_to_sort = false; + if (!is_visible()) { + return; + } + for (auto &workspace : workspaces_) { workspace->handle_done(); } + + sort_workspaces(); } auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } @@ -215,9 +226,7 @@ auto WorkspaceGroup::sort_workspaces() -> void { std::sort(workspaces_.begin(), workspaces_.end(), cmp); for (size_t i = 0; i < workspaces_.size(); ++i) { - for (auto &workspace : workspaces_) { - box_.reorder_child(workspace->get_button_ref(), i); - } + box_.reorder_child(workspaces_[i]->get_button_ref(), i); } } @@ -246,16 +255,23 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & } } - button_.signal_clicked().connect(sigc::mem_fun(this, &Workspace::handle_clicked)); + /* Handle click events if configured */ + if (config_["on-click"].isString() || config_["on-click-middle"].isString() + || config_["on-click-right"].isString()) { + button_.add_events(Gdk::BUTTON_PRESS_MASK); + button_.signal_button_press_event().connect( + sigc::mem_fun(*this, &Workspace::handle_clicked), false); + } - workspace_group.add_button(button_); button_.set_relief(Gtk::RELIEF_NONE); content_.set_center_widget(label_); button_.add(content_); + if (!workspace_group.is_visible()) { return; } + workspace_group.add_button(button_); button_.show(); label_.show(); content_.show(); @@ -283,6 +299,12 @@ auto Workspace::handle_state(const std::vector &state) -> void { case ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE: state_ |= (uint32_t)State::ACTIVE; break; + case ZEXT_WORKSPACE_HANDLE_V1_STATE_URGENT: + state_ |= (uint32_t)State::URGENT; + break; + case ZEXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN: + state_ |= (uint32_t)State::URGENT; + break; } } } @@ -293,21 +315,27 @@ auto Workspace::handle_remove() -> void { workspace_group_.remove_workspace(id_); } +auto add_or_remove_class(Glib::RefPtr context, bool condition, const std::string& class_name) { + if (condition) { + context->add_class(class_name); + } else { + context->remove_class(class_name); + } +} + auto Workspace::handle_done() -> void { spdlog::debug("Workspace {} changed to state {}", id_, state_); auto style_context = button_.get_style_context(); - if (is_active()) { - style_context->add_class("focused"); - } else { - style_context->remove_class("focused"); - } + add_or_remove_class(style_context, is_active(), "active"); + add_or_remove_class(style_context, is_urgent(), "urgent"); + add_or_remove_class(style_context, is_hidden(), "hidden"); } auto Workspace::get_icon() -> std::string { if (is_active()) { - auto focused_icon_it = icons_map_.find("focused"); - if (focused_icon_it != icons_map_.end()) { - return focused_icon_it->second; + auto active_icon_it = icons_map_.find("active"); + if (active_icon_it != icons_map_.end()) { + return active_icon_it->second; } } @@ -324,19 +352,46 @@ auto Workspace::get_icon() -> std::string { return name_; } -auto Workspace::handle_clicked() -> void { - spdlog::debug("Workspace {} clicked", (void *)workspace_handle_); - zext_workspace_handle_v1_activate(workspace_handle_); +auto Workspace::handle_clicked(GdkEventButton *bt) -> bool { + std::string action; + if (config_["on-click"].isString() && bt->button == 1) { + action = config_["on-click"].asString(); + } + else if (config_["on-click-middle"].isString() && bt->button == 2) { + action = config_["on-click-middle"].asString(); + } + else if (config_["on-click-right"].isString() && bt->button == 3) { + action = config_["on-click-right"].asString(); + } + + if (action.empty()) + return true; + else if (action == "activate") { + zext_workspace_handle_v1_activate(workspace_handle_); + } + else if (action == "close") { + zext_workspace_handle_v1_remove(workspace_handle_); + } + else { + spdlog::warn("Unknown action {}", action); + } + workspace_group_.commit(); + + return true; } auto Workspace::handle_name(const std::string &name) -> void { + if (name_ != name) { + workspace_group_.set_need_to_sort(); + } name_ = name; - workspace_group_.sort_workspaces(); } auto Workspace::handle_coordinates(const std::vector &coordinates) -> void { + if (coordinates_ != coordinates) { + workspace_group_.set_need_to_sort(); + } coordinates_ = coordinates; - workspace_group_.sort_workspaces(); } } // namespace waybar::modules::wlr diff --git a/src/modules/wlr/workspace_manager_binding.cpp b/src/modules/wlr/workspace_manager_binding.cpp index 6a33973..1005d5c 100644 --- a/src/modules/wlr/workspace_manager_binding.cpp +++ b/src/modules/wlr/workspace_manager_binding.cpp @@ -112,12 +112,6 @@ void workspace_handle_state(void *data, struct zext_workspace_handle_v1 *workspa std::vector state_vec; auto states = static_cast(state->data); for (size_t i = 0; i < state->size; ++i) { - // To sync server and pending states - if (states[i] == ZEXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE) { - zext_workspace_handle_v1_activate(workspace_handle); - } else { - zext_workspace_handle_v1_deactivate(workspace_handle); - } state_vec.push_back(states[i]); } From 23991b65430c8b06e360ef289c0db6d9f3e297ec Mon Sep 17 00:00:00 2001 From: dmitry Date: Tue, 23 Nov 2021 03:10:44 +0300 Subject: [PATCH 59/61] Finish --- include/modules/wlr/workspace_manager.hpp | 55 +++-- man/waybar-wlr-workspaces.5.scd | 10 + src/modules/wlr/workspace_manager.cpp | 198 ++++++++++++------ src/modules/wlr/workspace_manager_binding.cpp | 5 +- 4 files changed, 183 insertions(+), 85 deletions(-) diff --git a/include/modules/wlr/workspace_manager.hpp b/include/modules/wlr/workspace_manager.hpp index 1fcfc22..e4cdb4d 100644 --- a/include/modules/wlr/workspace_manager.hpp +++ b/include/modules/wlr/workspace_manager.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -37,25 +38,24 @@ class Workspace { auto handle_done() -> void; auto handle_clicked(GdkEventButton *bt) -> bool; - auto show() -> void { button_.show(); } - auto hide() -> void { button_.hide(); } + auto show() -> void; + auto hide() -> void; auto get_button_ref() -> Gtk::Button & { return button_; } auto get_name() -> std::string & { return name_; } auto get_coords() -> std::vector & { return coordinates_; } - enum class State - { - ACTIVE = 1 << 0, - URGENT = 1 << 1, - HIDDEN = 1 << 2, + enum class State { + ACTIVE = (1 << 0), + URGENT = (1 << 1), + HIDDEN = (1 << 2), }; private: auto get_icon() -> std::string; - const Bar & bar_; + const Bar &bar_; const Json::Value &config_; - WorkspaceGroup & workspace_group_; + WorkspaceGroup &workspace_group_; // wlr stuff zext_workspace_handle_v1 *workspace_handle_; @@ -84,35 +84,36 @@ class WorkspaceGroup { auto id() const -> uint32_t { return id_; } auto is_visible() const -> bool; auto remove_workspace(uint32_t id_) -> void; + auto active_only() const -> bool; + auto creation_delayed() const -> bool; + auto workspaces() -> std::vector> & { return workspaces_; } + + auto sort_workspaces() -> void; + auto set_need_to_sort() -> void { need_to_sort = true; } + auto add_button(Gtk::Button &button) -> void; + auto remove_button(Gtk::Button &button) -> void; // wlr stuff auto handle_workspace_create(zext_workspace_handle_v1 *workspace_handle) -> void; auto handle_remove() -> void; auto handle_output_enter(wl_output *output) -> void; auto handle_output_leave() -> void; - - auto add_button(Gtk::Button &button) -> void; - auto remove_button(Gtk::Button &button) -> void; auto handle_done() -> void; auto commit() -> void; - auto sort_workspaces() -> void; - auto set_need_to_sort() -> void { need_to_sort = true; } private: static uint32_t workspace_global_id; const waybar::Bar &bar_; - Gtk::Box & box_; + Gtk::Box &box_; const Json::Value &config_; - WorkspaceManager & workspace_manager_; + WorkspaceManager &workspace_manager_; // wlr stuff zext_workspace_group_handle_v1 *workspace_group_handle_; - wl_output * output_ = nullptr; + wl_output *output_ = nullptr; uint32_t id_; std::vector> workspaces_; - bool sort_by_name = true; - bool sort_by_coordinates = true; bool need_to_sort = false; }; @@ -122,6 +123,13 @@ class WorkspaceManager : public AModule { ~WorkspaceManager() override; auto update() -> void override; + auto all_outputs() const -> bool { return all_outputs_; } + auto active_only() const -> bool { return active_only_; } + auto workspace_comparator() const + -> std::function &, std::unique_ptr &)>; + auto creation_delayed() const -> bool { return creation_delayed_; } + + auto sort_workspaces() -> void; auto remove_workspace_group(uint32_t id_) -> void; // wlr stuff @@ -130,11 +138,10 @@ class WorkspaceManager : public AModule { -> void; auto handle_done() -> void; auto handle_finished() -> void; - auto commit() -> void; private: - const waybar::Bar & bar_; + const waybar::Bar &bar_; Gtk::Box box_; std::vector> groups_; @@ -142,6 +149,12 @@ class WorkspaceManager : public AModule { zext_workspace_manager_v1 *workspace_manager_ = nullptr; static uint32_t group_global_id; + + bool sort_by_name_ = true; + bool sort_by_coordinates_ = true; + bool all_outputs_ = false; + bool active_only_ = false; + bool creation_delayed_ = false; }; } // namespace waybar::modules::wlr diff --git a/man/waybar-wlr-workspaces.5.scd b/man/waybar-wlr-workspaces.5.scd index 344d932..f0df5e9 100644 --- a/man/waybar-wlr-workspaces.5.scd +++ b/man/waybar-wlr-workspaces.5.scd @@ -33,6 +33,16 @@ Addressed by *wlr/workspaces* Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first. If both are false - sort by id will be performed. +*all-outputs*: ++ + typeof: bool ++ + default: false ++ + If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown. + +*active-only*: ++ + typeof: bool ++ + default: false ++ + If set to true only active or urgent workspaces will be shown. + # FORMAT REPLACEMENTS *{name}*: Name of workspace assigned by compositor diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 1d67b04..9077dc8 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -5,7 +5,10 @@ #include #include +#include +#include +#include "gtkmm/widget.h" #include "modules/wlr/workspace_manager_binding.hpp" namespace waybar::modules::wlr { @@ -19,6 +22,27 @@ WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar : waybar::AModule(config, "workspaces", id, false, false), bar_(bar), box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { + auto config_sort_by_name = config_["sort-by-name"]; + if (config_sort_by_name.isBool()) { + sort_by_name_ = config_sort_by_name.asBool(); + } + + auto config_sort_by_coordinates = config_["sort-by-coordinates"]; + if (config_sort_by_coordinates.isBool()) { + sort_by_coordinates_ = config_sort_by_coordinates.asBool(); + } + + auto config_all_outputs = config_["all-outputs"]; + if (config_all_outputs.isBool()) { + all_outputs_ = config_all_outputs.asBool(); + } + + auto config_active_only = config_["active-only"]; + if (config_active_only.isBool()) { + active_only_ = config_active_only.asBool(); + creation_delayed_ = active_only_; + } + box_.set_name("workspaces"); if (!id.empty()) { box_.get_style_context()->add_class(id); @@ -31,6 +55,54 @@ WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar } } +auto WorkspaceManager::workspace_comparator() const + -> std::function &, std::unique_ptr &)> { + return [=](std::unique_ptr &lhs, std::unique_ptr &rhs) { + auto is_name_less = lhs->get_name() < rhs->get_name(); + auto is_name_eq = lhs->get_name() == rhs->get_name(); + auto is_coords_less = lhs->get_coords() < rhs->get_coords(); + if (sort_by_name_) { + if (sort_by_coordinates_) { + return is_name_eq ? is_coords_less : is_name_less; + } else { + return is_name_less; + } + } + + if (sort_by_coordinates_) { + return is_coords_less; + } + + return lhs->id() < rhs->id(); + }; +} + +auto WorkspaceManager::sort_workspaces() -> void { + std::vector>> all_workspaces; + for (auto &group : groups_) { + auto &group_workspaces = group->workspaces(); + all_workspaces.reserve(all_workspaces.size() + + std::distance(group_workspaces.begin(), group_workspaces.end())); + if (!active_only()) { + all_workspaces.insert(all_workspaces.end(), group_workspaces.begin(), group_workspaces.end()); + continue; + } + + for (auto &workspace : group_workspaces) { + if (!workspace->is_active()) { + continue; + } + + all_workspaces.push_back(workspace); + } + } + + std::sort(all_workspaces.begin(), all_workspaces.end(), workspace_comparator()); + for (size_t i = 0; i < all_workspaces.size(); ++i) { + box_.reorder_child(all_workspaces[i].get()->get_button_ref(), i); + } +} + auto WorkspaceManager::register_manager(wl_registry *registry, uint32_t name, uint32_t version) -> void { if (workspace_manager_) { @@ -67,6 +139,9 @@ auto WorkspaceManager::update() -> void { for (auto &group : groups_) { group->update(); } + if (creation_delayed()) { + creation_delayed_ = false; + } AModule::update(); } @@ -94,7 +169,7 @@ auto WorkspaceManager::remove_workspace_group(uint32_t id) -> void { auto WorkspaceManager::commit() -> void { zext_workspace_manager_v1_commit(workspace_manager_); } WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value &config, - WorkspaceManager & manager, + WorkspaceManager &manager, zext_workspace_group_handle_v1 *workspace_group_handle, uint32_t id) : bar_(bar), box_(box), @@ -103,15 +178,11 @@ WorkspaceGroup::WorkspaceGroup(const Bar &bar, Gtk::Box &box, const Json::Value workspace_group_handle_(workspace_group_handle), id_(id) { add_workspace_group_listener(workspace_group_handle, this); - auto config_sort_by_name = config_["sort-by-name"]; - if (config_sort_by_name.isBool()) { - sort_by_name = config_sort_by_name.asBool(); - } +} - auto config_sort_by_coordinates = config_["sort-by-coordinates"]; - if (config_sort_by_coordinates.isBool()) { - sort_by_coordinates = config_sort_by_coordinates.asBool(); - } +auto WorkspaceGroup::active_only() const -> bool { return workspace_manager_.active_only(); } +auto WorkspaceGroup::creation_delayed() const -> bool { + return workspace_manager_.creation_delayed(); } auto WorkspaceGroup::add_button(Gtk::Button &button) -> void { @@ -143,8 +214,8 @@ auto WorkspaceGroup::handle_output_enter(wl_output *output) -> void { spdlog::debug("Output {} assigned to {} group", (void *)output, id_); output_ = output; - if (!is_visible()) { - return; + if (!is_visible() || workspace_manager_.creation_delayed()) { + return; } for (auto &workspace : workspaces_) { @@ -153,7 +224,9 @@ auto WorkspaceGroup::handle_output_enter(wl_output *output) -> void { } auto WorkspaceGroup::is_visible() const -> bool { - return output_ != nullptr && output_ == gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj()); + return output_ != nullptr && + (workspace_manager_.all_outputs() || + output_ == gdk_wayland_monitor_get_wl_output(bar_.output->monitor->gobj())); } auto WorkspaceGroup::handle_output_leave() -> void { @@ -171,6 +244,13 @@ auto WorkspaceGroup::handle_output_leave() -> void { auto WorkspaceGroup::update() -> void { for (auto &workspace : workspaces_) { + if (workspace_manager_.creation_delayed()) { + add_button(workspace->get_button_ref()); + if (is_visible() && (workspace->is_active() || workspace->is_urgent())) { + workspace->show(); + } + } + workspace->update(); } } @@ -198,41 +278,27 @@ auto WorkspaceGroup::handle_done() -> void { workspace->handle_done(); } - sort_workspaces(); + if (creation_delayed()) { + return; + } + + if (!workspace_manager_.all_outputs()) { + //sort_workspaces(); + } else { + workspace_manager_.sort_workspaces(); + } } auto WorkspaceGroup::commit() -> void { workspace_manager_.commit(); } auto WorkspaceGroup::sort_workspaces() -> void { - auto cmp = [=](std::unique_ptr &lhs, std::unique_ptr &rhs) { - auto is_name_less = lhs->get_name() < rhs->get_name(); - auto is_name_eq = lhs->get_name() == rhs->get_name(); - auto is_coords_less = lhs->get_coords() < rhs->get_coords(); - if (sort_by_name) { - if (sort_by_coordinates) { - return is_name_eq ? is_coords_less : is_name_less; - } - else { - return is_name_less; - } - } - - if (sort_by_coordinates) { - return is_coords_less; - } - - return lhs->id() < rhs->id(); - }; - - std::sort(workspaces_.begin(), workspaces_.end(), cmp); + std::sort(workspaces_.begin(), workspaces_.end(), workspace_manager_.workspace_comparator()); for (size_t i = 0; i < workspaces_.size(); ++i) { box_.reorder_child(workspaces_[i]->get_button_ref(), i); } } -auto WorkspaceGroup::remove_button(Gtk::Button &button) -> void { - box_.remove(button); -} +auto WorkspaceGroup::remove_button(Gtk::Button &button) -> void { box_.remove(button); } Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup &workspace_group, zext_workspace_handle_v1 *workspace, uint32_t id) @@ -256,11 +322,11 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & } /* Handle click events if configured */ - if (config_["on-click"].isString() || config_["on-click-middle"].isString() - || config_["on-click-right"].isString()) { + if (config_["on-click"].isString() || config_["on-click-middle"].isString() || + config_["on-click-right"].isString()) { button_.add_events(Gdk::BUTTON_PRESS_MASK); - button_.signal_button_press_event().connect( - sigc::mem_fun(*this, &Workspace::handle_clicked), false); + button_.signal_button_press_event().connect(sigc::mem_fun(*this, &Workspace::handle_clicked), + false); } button_.set_relief(Gtk::RELIEF_NONE); @@ -272,9 +338,7 @@ Workspace::Workspace(const Bar &bar, const Json::Value &config, WorkspaceGroup & } workspace_group.add_button(button_); - button_.show(); - label_.show(); - content_.show(); + button_.show_all(); } Workspace::~Workspace() { @@ -303,7 +367,7 @@ auto Workspace::handle_state(const std::vector &state) -> void { state_ |= (uint32_t)State::URGENT; break; case ZEXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN: - state_ |= (uint32_t)State::URGENT; + state_ |= (uint32_t)State::HIDDEN; break; } } @@ -315,7 +379,8 @@ auto Workspace::handle_remove() -> void { workspace_group_.remove_workspace(id_); } -auto add_or_remove_class(Glib::RefPtr context, bool condition, const std::string& class_name) { +auto add_or_remove_class(Glib::RefPtr context, bool condition, + const std::string &class_name) { if (condition) { context->add_class(class_name); } else { @@ -329,6 +394,16 @@ auto Workspace::handle_done() -> void { add_or_remove_class(style_context, is_active(), "active"); add_or_remove_class(style_context, is_urgent(), "urgent"); add_or_remove_class(style_context, is_hidden(), "hidden"); + + if (workspace_group_.creation_delayed()) { + return; + } + + if (workspace_group_.active_only() && (is_active() || is_urgent())) { + button_.show_all(); + } else if (workspace_group_.active_only() && !(is_active() || is_urgent())) { + button_.hide(); + } } auto Workspace::get_icon() -> std::string { @@ -355,24 +430,20 @@ auto Workspace::get_icon() -> std::string { auto Workspace::handle_clicked(GdkEventButton *bt) -> bool { std::string action; if (config_["on-click"].isString() && bt->button == 1) { - action = config_["on-click"].asString(); - } - else if (config_["on-click-middle"].isString() && bt->button == 2) { - action = config_["on-click-middle"].asString(); - } - else if (config_["on-click-right"].isString() && bt->button == 3) { - action = config_["on-click-right"].asString(); + action = config_["on-click"].asString(); + } else if (config_["on-click-middle"].isString() && bt->button == 2) { + action = config_["on-click-middle"].asString(); + } else if (config_["on-click-right"].isString() && bt->button == 3) { + action = config_["on-click-right"].asString(); } if (action.empty()) - return true; + return true; else if (action == "activate") { - zext_workspace_handle_v1_activate(workspace_handle_); - } - else if (action == "close") { - zext_workspace_handle_v1_remove(workspace_handle_); - } - else { + zext_workspace_handle_v1_activate(workspace_handle_); + } else if (action == "close") { + zext_workspace_handle_v1_remove(workspace_handle_); + } else { spdlog::warn("Unknown action {}", action); } @@ -381,16 +452,19 @@ auto Workspace::handle_clicked(GdkEventButton *bt) -> bool { return true; } +auto Workspace::show() -> void { button_.show_all(); } +auto Workspace::hide() -> void { button_.hide(); } + auto Workspace::handle_name(const std::string &name) -> void { if (name_ != name) { - workspace_group_.set_need_to_sort(); + workspace_group_.set_need_to_sort(); } name_ = name; } auto Workspace::handle_coordinates(const std::vector &coordinates) -> void { if (coordinates_ != coordinates) { - workspace_group_.set_need_to_sort(); + workspace_group_.set_need_to_sort(); } coordinates_ = coordinates; } diff --git a/src/modules/wlr/workspace_manager_binding.cpp b/src/modules/wlr/workspace_manager_binding.cpp index 1005d5c..30c6041 100644 --- a/src/modules/wlr/workspace_manager_binding.cpp +++ b/src/modules/wlr/workspace_manager_binding.cpp @@ -1,6 +1,7 @@ #include "modules/wlr/workspace_manager_binding.hpp" #include +#include #include "client.hpp" #include "modules/wlr/workspace_manager.hpp" @@ -100,7 +101,7 @@ void workspace_handle_coordinates(void *data, struct zext_workspace_handle_v1 *_ struct wl_array *coordinates) { std::vector coords_vec; auto coords = static_cast(coordinates->data); - for (size_t i = 0; i < coordinates->size; ++i) { + for (size_t i = 0; i < coordinates->size / sizeof(uint32_t); ++i) { coords_vec.push_back(coords[i]); } @@ -111,7 +112,7 @@ void workspace_handle_state(void *data, struct zext_workspace_handle_v1 *workspa struct wl_array *state) { std::vector state_vec; auto states = static_cast(state->data); - for (size_t i = 0; i < state->size; ++i) { + for (size_t i = 0; i < state->size / sizeof(uint32_t); ++i) { state_vec.push_back(states[i]); } From 98f7a10a51d6cecc1422edfcb0bc3886e0a1121a Mon Sep 17 00:00:00 2001 From: dmitry Date: Tue, 23 Nov 2021 03:18:00 +0300 Subject: [PATCH 60/61] Fix sort --- src/modules/wlr/workspace_manager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/wlr/workspace_manager.cpp b/src/modules/wlr/workspace_manager.cpp index 9077dc8..bacef35 100644 --- a/src/modules/wlr/workspace_manager.cpp +++ b/src/modules/wlr/workspace_manager.cpp @@ -141,6 +141,7 @@ auto WorkspaceManager::update() -> void { } if (creation_delayed()) { creation_delayed_ = false; + sort_workspaces(); } AModule::update(); } @@ -283,7 +284,7 @@ auto WorkspaceGroup::handle_done() -> void { } if (!workspace_manager_.all_outputs()) { - //sort_workspaces(); + sort_workspaces(); } else { workspace_manager_.sort_workspaces(); } From c51a973d602fb448aa0e11e37ddd7f3df0d588ee Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 23 Nov 2021 10:10:14 +0100 Subject: [PATCH 61/61] Revert "dont escape essid in tooltip" --- src/modules/network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/network.cpp b/src/modules/network.cpp index 020478a..e7b20ab 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -328,7 +328,7 @@ auto waybar::modules::Network::update() -> void { auto text = fmt::format( format_, - fmt::arg("essid", Glib::Markup::escape_text(essid_)), + fmt::arg("essid", essid_), fmt::arg("signaldBm", signal_strength_dbm_), fmt::arg("signalStrength", signal_strength_), fmt::arg("ifname", ifname_), @@ -779,7 +779,7 @@ void waybar::modules::Network::parseEssid(struct nlattr **bss) { auto essid_end = essid_begin + ies[1]; std::string essid_raw; std::copy(essid_begin, essid_end, std::back_inserter(essid_raw)); - essid_ = essid_raw; + essid_ = Glib::Markup::escape_text(essid_raw); } } }