Merge remote-tracking branch 'origin/master' into pr-4537

# Conflicts:
#	include/modules/niri/workspaces.hpp
#	src/modules/niri/workspaces.cpp
This commit is contained in:
Alex
2026-07-04 00:40:14 +02:00
273 changed files with 11627 additions and 3280 deletions
+4 -8
View File
@@ -10,13 +10,9 @@ jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v6
# TODO: bump to clang 19 release - uses: RafikFarhad/clang-format-github-action@v6
# - uses: DoozyX/clang-format-lint-action@v0.18.2
- uses: DoozyX/clang-format-lint-action@558090054b3f39e3d6af24f0cd73b319535da809
name: clang-format name: clang-format
with: with:
source: "." sources: "src/**/*.hpp,src/**/*.cpp"
extensions: "hpp,h,cpp,c" style: "file"
style: "file:.clang-format"
clangFormatVersion: 19
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
container: container:
image: alexays/waybar:debian image: alexays/waybar:debian
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v6
- name: configure - name: configure
run: | run: |
meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json meson -Dcpp_std=c++20 build # necessary to generate compile_commands.json
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 - uses: actions/checkout@v6
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v3 uses: docker/login-action@v3
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
# https://github.com/actions/runner/issues/385 - for FreeBSD runner support # https://github.com/actions/runner/issues/385 - for FreeBSD runner support
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v6
- name: Test in FreeBSD VM - name: Test in FreeBSD VM
uses: cross-platform-actions/action@v0.28.0 uses: cross-platform-actions/action@v0.28.0
timeout-minutes: 180 timeout-minutes: 180
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
image: alexays/waybar:${{ matrix.distro }} image: alexays/waybar:${{ matrix.distro }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v6
- name: configure - name: configure
run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build run: meson setup -Dman-pages=enabled -Dcpp_std=${{matrix.cpp_std}} build
- name: build - name: build
+5 -2
View File
@@ -2,12 +2,15 @@ name: "Nix-Tests"
on: on:
pull_request: pull_request:
push: push:
concurrency:
group: ${{ github.workflow }}-nix-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs: jobs:
nix-flake-check: nix-flake-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v6
- uses: cachix/install-nix-action@v27 - uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
experimental-features = nix-command flakes experimental-features = nix-command flakes
+3 -3
View File
@@ -12,11 +12,11 @@ jobs:
if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar' if: github.event_name != 'schedule' || github.repository == 'Alexays/Waybar'
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 - uses: actions/checkout@v6
- name: Install Nix - name: Install Nix
uses: cachix/install-nix-action@v27 uses: cachix/install-nix-action@v31
with: with:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Update flake.lock - name: Update flake.lock
uses: DeterminateSystems/update-flake-lock@v21 uses: DeterminateSystems/update-flake-lock@v28
+3
View File
@@ -7,6 +7,7 @@ vgcore.*
*.swp *.swp
packagecache packagecache
/subprojects/**/ /subprojects/**/
/subprojects/.wraplock
/build* /build*
/dist /dist
/meson.egg-info /meson.egg-info
@@ -50,3 +51,5 @@ result
result-* result-*
.ccls-cache .ccls-cache
_codeql_detected_source_root
heaptrack*
+6 -1
View File
@@ -9,6 +9,7 @@
- River (Mapping mode, Tags, Focused window name) - River (Mapping mode, Tags, Focused window name)
- Hyprland (Window Icons, Workspaces, Focused window name) - Hyprland (Window Icons, Workspaces, Focused window name)
- Niri (Workspaces, Focused window name, Language) - Niri (Workspaces, Focused window name, Language)
- Mango (Workspaces, Focused window name, Language, Keymode)
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc) - DWL (Tags, Focused window name) [requires dwl ipc patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/ipc)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21) - Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time - Local time
@@ -119,7 +120,7 @@ sudo apt install \
On Arch, you can use this command: On Arch, you can use this command:
``` ```
pacman -S \ pacman -S --asdeps \
gtkmm3 \ gtkmm3 \
jsoncpp \ jsoncpp \
libsigc++ \ libsigc++ \
@@ -151,6 +152,10 @@ Contributions welcome!<br>
Have fun :)<br> Have fun :)<br>
The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html) The style guidelines are [Google's](https://google.github.io/styleguide/cppguide.html)
> [!CAUTION]
> Distributions of Waybar are only released on the [official GitHub page](https://github.com/Alexays/Waybar).<br/>
> Waybar does **not** have an official website. Do not trust any sites that claim to be official.
## License ## License
Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE). Waybar is licensed under the MIT license. [See LICENSE for more information](https://github.com/Alexays/Waybar/blob/master/LICENSE).
+1
View File
@@ -0,0 +1 @@
.
Generated
+6 -6
View File
@@ -3,11 +3,11 @@
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1747046372, "lastModified": 1767039857,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -18,11 +18,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1759036355, "lastModified": 1769461804,
"narHash": "sha256-0m27AKv6ka+q270dw48KflE0LwQYrO7Fm4/2//KCVWg=", "narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e9f00bd893984bc8ce46c895c3bf7cac95331127", "rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"type": "github" "type": "github"
}, },
"original": { "original": {
+57
View File
@@ -0,0 +1,57 @@
#pragma once
#include <glibmm/markup.h>
#include <gtkmm/label.h>
#include <json/json.h>
#include <deque>
#include <vector>
#include "AModule.hpp"
namespace waybar {
enum class GraphType { LINE, BAR, GAUGE };
class AGraph : public AModule {
public:
AGraph(const Json::Value&, const std::string&, const std::string&, uint16_t interval = 0,
bool enable_click = false, bool enable_scroll = false);
virtual ~AGraph() = default;
auto update() -> void override;
protected:
Gtk::DrawingArea graph_;
std::deque<int> values_;
uint16_t datapoints_ = 20;
GraphType graph_type_ = GraphType::LINE;
void addValue(const int n);
const std::chrono::seconds interval_;
bool onDraw(const Cairo::RefPtr<Cairo::Context>& cr);
std::map<std::string, GtkMenuItem*> submenus_;
std::map<std::string, std::string> menuActionsMap_;
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
private:
void drawFilledArea(const Cairo::RefPtr<Cairo::Context>& cr,
const std::vector<std::pair<double, double>>& points, double height,
const Gdk::RGBA& bg_color);
void drawLine(const Cairo::RefPtr<Cairo::Context>& cr,
const std::vector<std::pair<double, double>>& points, const Gdk::RGBA& fg_color);
void drawPath(const Cairo::RefPtr<Cairo::Context>& cr,
const std::vector<std::pair<double, double>>& points);
void drawBars(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
int current_value, const Gdk::RGBA& fg_color);
void drawGauge(const Cairo::RefPtr<Cairo::Context>& cr, double width, double height,
int current_value, const Gdk::RGBA& fg_color);
};
} // namespace waybar
+4
View File
@@ -14,10 +14,14 @@ class AIconLabel : public ALabel {
bool enable_click = false, bool enable_scroll = false); bool enable_click = false, bool enable_scroll = false);
virtual ~AIconLabel() = default; virtual ~AIconLabel() = default;
auto update() -> void override; auto update() -> void override;
static std::tuple<std::string, std::string> extractIcon(const std::string& input);
protected: protected:
Gtk::Image image_; Gtk::Image image_;
Gtk::Box box_; Gtk::Box box_;
unsigned app_icon_size_{24};
bool label_contains_icon{false};
bool iconEnabled() const; bool iconEnabled() const;
}; };
+58
View File
@@ -1,9 +1,15 @@
#pragma once #pragma once
#include <fmt/args.h>
#include <fmt/format.h>
#include <glibmm/markup.h> #include <glibmm/markup.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <json/json.h> #include <json/json.h>
#include <optional>
#include <string>
#include <utility>
#include "AModule.hpp" #include "AModule.hpp"
namespace waybar { namespace waybar {
@@ -25,12 +31,64 @@ class ALabel : public AModule {
bool alt_ = false; bool alt_ = false;
std::string default_format_; std::string default_format_;
bool setLabelMarkup(const Glib::ustring& markup);
bool setTooltipMarkup(const Glib::ustring& markup);
// resolveTooltipFormat() / resolveFormat() are inherited from AModule.
// Combined label + tooltip helper. Builds a single fmt argument store from
// `args`, renders `labelFormat` into the label and the resolved tooltip format
// into the tooltip, both through the dedup-aware setters. Honors the `tooltip`
// toggle. This replaces the label/tooltip formatting boilerplate that modules
// used to duplicate. `state` selects `tooltip-format-<state>` when non-empty.
template <typename... Args>
void updateLabelAndTooltipForState(const std::string& state, const std::string& labelFormat,
const std::string& tooltipDefault, Args&&... args) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
(store.push_back(std::forward<Args>(args)), ...);
setLabelMarkup(fmt::vformat(labelFormat, store));
if (tooltipEnabled()) {
setTooltipMarkup(fmt::vformat(resolveTooltipFormat(tooltipDefault, state), store));
}
}
template <typename... Args>
void updateLabelAndTooltip(const std::string& labelFormat, const std::string& tooltipDefault,
Args&&... args) {
updateLabelAndTooltipForState("", labelFormat, tooltipDefault, std::forward<Args>(args)...);
}
// Overloads accepting a pre-built argument store, for modules that must
// assemble a dynamic set of format arguments (e.g. per-core CPU stats) that
// cannot be expressed through a fixed variadic call.
// A non-const reference is used so this overload is preferred over the
// variadic template above (which would otherwise bind the store as a single
// forwarded argument).
void updateLabelAndTooltipForState(const std::string& state, const std::string& labelFormat,
const std::string& tooltipDefault,
fmt::dynamic_format_arg_store<fmt::format_context>& store) {
setLabelMarkup(fmt::vformat(labelFormat, store));
if (tooltipEnabled()) {
setTooltipMarkup(fmt::vformat(resolveTooltipFormat(tooltipDefault, state), store));
}
}
void updateLabelAndTooltip(const std::string& labelFormat, const std::string& tooltipDefault,
fmt::dynamic_format_arg_store<fmt::format_context>& store) {
updateLabelAndTooltipForState("", labelFormat, tooltipDefault, store);
}
bool handleToggle(GdkEventButton* const& e) override; bool handleToggle(GdkEventButton* const& e) override;
void copyToClipboard(const std::string&);
virtual std::string getState(uint8_t value, bool lesser = false); virtual std::string getState(uint8_t value, bool lesser = false);
std::map<std::string, GtkMenuItem*> submenus_; std::map<std::string, GtkMenuItem*> submenus_;
std::map<std::string, std::string> menuActionsMap_; std::map<std::string, std::string> menuActionsMap_;
static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data); static void handleGtkMenuEvent(GtkMenuItem* menuitem, gpointer data);
private:
std::optional<Glib::ustring> last_label_markup_;
std::optional<Glib::ustring> last_tooltip_markup_;
}; };
} // namespace waybar } // namespace waybar
+50 -3
View File
@@ -1,11 +1,16 @@
#pragma once #pragma once
#include <fmt/args.h>
#include <fmt/format.h>
#include <glibmm/dispatcher.h> #include <glibmm/dispatcher.h>
#include <glibmm/markup.h> #include <glibmm/markup.h>
#include <gtkmm.h> #include <gtkmm.h>
#include <gtkmm/eventbox.h> #include <gtkmm/eventbox.h>
#include <json/json.h> #include <json/json.h>
#include <string>
#include <utility>
#include "IModule.hpp" #include "IModule.hpp"
namespace waybar { namespace waybar {
@@ -25,6 +30,10 @@ class AModule : public IModule {
bool expandEnabled() const; bool expandEnabled() const;
virtual void suspend() {};
virtual void resume() {};
bool shouldSuspend() const { return disable_on_sleep_; }
protected: protected:
// Don't need to make an object directly // Don't need to make an object directly
// Derived classes are able to use it // Derived classes are able to use it
@@ -36,19 +45,55 @@ class AModule : public IModule {
SCROLL_DIR getScrollDir(GdkEventScroll* e); SCROLL_DIR getScrollDir(GdkEventScroll* e);
bool tooltipEnabled() const; bool tooltipEnabled() const;
// --- Generic format/tooltip resolution (config-only, usable by any module,
// ALabel-derived or not). Prefers `<key>-<state>`, then `<key>`, then default.
std::string resolveFormat(const std::string& defaultFormat, const std::string& state = "") const {
if (!state.empty() && config_["format-" + state].isString()) {
return config_["format-" + state].asString();
}
if (config_["format"].isString()) {
return config_["format"].asString();
}
return defaultFormat;
}
std::string resolveTooltipFormat(const std::string& defaultFormat,
const std::string& state = "") const {
if (!state.empty() && config_["tooltip-format-" + state].isString()) {
return config_["tooltip-format-" + state].asString();
}
if (config_["tooltip-format"].isString()) {
return config_["tooltip-format"].asString();
}
return defaultFormat;
}
// Generic tooltip for any widget: honors the `tooltip` toggle and
// `tooltip-format`, formats with the given args and applies it. Lets modules
// that are not ALabel-derived (e.g. gamemode) reuse the shared logic.
template <typename... Args>
void updateTooltip(Gtk::Widget& widget, const std::string& defaultFormat, Args&&... args) {
if (!tooltipEnabled()) {
return;
}
widget.set_tooltip_markup(
fmt::format(fmt::runtime(resolveTooltipFormat(defaultFormat)), std::forward<Args>(args)...));
}
std::vector<int> pid_children_; std::vector<int> pid_children_;
const std::string name_; const std::string name_;
const Json::Value& config_; const Json::Value& config_;
Gtk::EventBox event_box_; Gtk::EventBox event_box_;
virtual void setCursor(Gdk::CursorType const &c); virtual void setCursor(std::string const& c);
virtual bool handleToggle(GdkEventButton* const& ev); virtual bool handleToggle(GdkEventButton* const& ev);
virtual bool handleMouseEnter(GdkEventCrossing* const& ev); virtual bool handleMouseEnter(GdkEventCrossing* const& ev);
virtual bool handleMouseLeave(GdkEventCrossing* const& ev); virtual bool handleMouseLeave(GdkEventCrossing* const& ev);
virtual bool handleScroll(GdkEventScroll*); virtual bool handleScroll(GdkEventScroll*);
virtual bool handleRelease(GdkEventButton* const& ev); virtual bool handleRelease(GdkEventButton* const& ev);
GObject *menu_;
bool disable_on_sleep_{false};
GObject* menu_ = nullptr;
private: private:
bool handleUserEvent(GdkEventButton* const& ev); bool handleUserEvent(GdkEventButton* const& ev);
@@ -57,6 +102,7 @@ class AModule : public IModule {
bool hasUserEvents_; bool hasUserEvents_;
gdouble distance_scrolled_y_; gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_; gdouble distance_scrolled_x_;
sigc::connection cursor_timeout_conn_;
std::map<std::string, std::string> eventActionMap_; std::map<std::string, std::string> eventActionMap_;
static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{ static const inline std::map<std::pair<uint, GdkEventType>, std::string> eventMap_{
{std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"}, {std::make_pair(1, GdkEventType::GDK_BUTTON_PRESS), "on-click"},
@@ -78,7 +124,8 @@ class AModule : public IModule {
{std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"}, {std::make_pair(9, GdkEventType::GDK_BUTTON_PRESS), "on-click-forward"},
{std::make_pair(9, GdkEventType::GDK_BUTTON_RELEASE), "on-click-forward-release"}, {std::make_pair(9, GdkEventType::GDK_BUTTON_RELEASE), "on-click-forward-release"},
{std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"}, {std::make_pair(9, GdkEventType::GDK_2BUTTON_PRESS), "on-double-click-forward"},
{std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"}}; {std::make_pair(9, GdkEventType::GDK_3BUTTON_PRESS), "on-triple-click-forward"},
{std::make_pair(10, GdkEventType::GDK_BUTTON_PRESS), "on-click-copy"}};
}; };
} // namespace waybar } // namespace waybar
+3
View File
@@ -75,6 +75,8 @@ class Bar : public sigc::trackable {
util::KillSignalAction getOnSigusr1Action(); util::KillSignalAction getOnSigusr1Action();
util::KillSignalAction getOnSigusr2Action(); util::KillSignalAction getOnSigusr2Action();
void toggleSuspend(bool suspend);
struct waybar_output* output; struct waybar_output* output;
Json::Value config; Json::Value config;
struct wl_surface* surface; struct wl_surface* surface;
@@ -99,6 +101,7 @@ class Bar : public sigc::trackable {
void setMode(const bar_mode&); void setMode(const bar_mode&);
void setPassThrough(bool passthrough); void setPassThrough(bool passthrough);
void setPosition(Gtk::PositionType position); void setPosition(Gtk::PositionType position);
void forceLayerCommit();
void onConfigure(GdkEventConfigure* ev); void onConfigure(GdkEventConfigure* ev);
void configureGlobalOffset(int width, int height); void configureGlobalOffset(int width, int height);
void onOutputGeometryChanged(); void onOutputGeometryChanged();
+7
View File
@@ -12,6 +12,7 @@
struct zwp_idle_inhibitor_v1; struct zwp_idle_inhibitor_v1;
struct zwp_idle_inhibit_manager_v1; struct zwp_idle_inhibit_manager_v1;
struct ext_idle_notifier_v1;
namespace waybar { namespace waybar {
@@ -27,6 +28,7 @@ class Client {
struct wl_registry* registry = nullptr; struct wl_registry* registry = nullptr;
struct zxdg_output_manager_v1* xdg_output_manager = nullptr; struct zxdg_output_manager_v1* xdg_output_manager = nullptr;
struct zwp_idle_inhibit_manager_v1* idle_inhibit_manager = nullptr; struct zwp_idle_inhibit_manager_v1* idle_inhibit_manager = nullptr;
struct ext_idle_notifier_v1* idle_notifier = nullptr;
std::vector<std::unique_ptr<Bar>> bars; std::vector<std::unique_ptr<Bar>> bars;
Config config; Config config;
std::string bar_id; std::string bar_id;
@@ -44,6 +46,7 @@ class Client {
const char* interface, uint32_t version); const char* interface, uint32_t version);
static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name); static void handleGlobalRemove(void* data, struct wl_registry* registry, uint32_t name);
static void handleOutputDone(void*, struct zxdg_output_v1*); static void handleOutputDone(void*, struct zxdg_output_v1*);
void createBarsBatch();
static void handleOutputName(void*, struct zxdg_output_v1*, const char*); static void handleOutputName(void*, struct zxdg_output_v1*, const char*);
static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*); static void handleOutputDescription(void*, struct zxdg_output_v1*, const char*);
void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor); void handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor);
@@ -56,6 +59,10 @@ class Client {
std::list<struct waybar_output> outputs_; std::list<struct waybar_output> outputs_;
std::unique_ptr<CssReloadHelper> m_cssReloadHelper; std::unique_ptr<CssReloadHelper> m_cssReloadHelper;
std::string m_cssFile; std::string m_cssFile;
sigc::connection monitor_added_connection_;
sigc::connection monitor_removed_connection_;
std::list<waybar_output*> pending_outputs_;
bool bars_scheduled_ = false;
}; };
} // namespace waybar } // namespace waybar
+4
View File
@@ -10,6 +10,8 @@
namespace waybar { namespace waybar {
class Group : public AModule { class Group : public AModule {
sigc::connection reveal_timeout_;
public: public:
Group(const std::string&, const std::string&, const Json::Value&, bool); Group(const std::string&, const std::string&, const Json::Value&, bool);
~Group() override = default; ~Group() override = default;
@@ -26,10 +28,12 @@ class Group : public AModule {
bool is_first_widget = true; bool is_first_widget = true;
bool is_drawer = false; bool is_drawer = false;
bool click_to_reveal = false; bool click_to_reveal = false;
int reveal_delay = 0;
std::string add_class_to_drawer_children; std::string add_class_to_drawer_children;
bool handleMouseEnter(GdkEventCrossing* const& ev) override; bool handleMouseEnter(GdkEventCrossing* const& ev) override;
bool handleMouseLeave(GdkEventCrossing* const& ev) override; bool handleMouseLeave(GdkEventCrossing* const& ev) override;
bool handleToggle(GdkEventButton* const& ev) override; bool handleToggle(GdkEventButton* const& ev) override;
bool handleScroll(GdkEventScroll* e) override;
void show_group(); void show_group();
void hide_group(); void hide_group();
}; };
+12 -2
View File
@@ -6,8 +6,10 @@
#if defined(__linux__) #if defined(__linux__)
#include <sys/inotify.h> #include <sys/inotify.h>
#endif #endif
#include <poll.h>
#include <algorithm> #include <algorithm>
#include <chrono>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -15,6 +17,7 @@
#include "ALabel.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
#include "util/udev_deleter.hpp"
namespace waybar::modules { namespace waybar::modules {
@@ -37,16 +40,23 @@ class Battery : public ALabel {
void setBarClass(std::string&); void setBarClass(std::string&);
void processEvents(std::string& state, std::string& status, uint8_t capacity); void processEvents(std::string& state, std::string& status, uint8_t capacity);
int global_watch;
std::map<fs::path, int> batteries_; std::map<fs::path, int> batteries_;
std::unique_ptr<udev, util::UdevDeleter> udev_;
std::array<pollfd, 1> poll_fds_;
std::unique_ptr<udev_monitor, util::UdevMonitorDeleter> mon_;
fs::path adapter_; fs::path adapter_;
int battery_watch_fd_; int battery_watch_fd_;
int global_watch_fd_;
std::mutex battery_list_mutex_; std::mutex battery_list_mutex_;
std::string old_status_; std::string old_status_;
std::string last_event_; std::string last_event_;
bool warnFirstTime_{true}; bool warnFirstTime_{true};
bool weightedAverage_{true};
const Bar& bar_; const Bar& bar_;
bool smoothPowerEnable_{false};
double time_constant_s_{260.0};
double smooth_power_{0.0}; // µW
std::chrono::steady_clock::time_point last_t_{std::chrono::steady_clock::now()};
std::string old_status_raw_{""};
util::SleeperThread thread_; util::SleeperThread thread_;
util::SleeperThread thread_battery_update_; util::SleeperThread thread_battery_update_;
+7
View File
@@ -41,6 +41,7 @@ class Bluetooth : public ALabel {
bool services_resolved; bool services_resolved;
// NOTE: experimental feature in bluez // NOTE: experimental feature in bluez
std::optional<unsigned char> battery_percentage; std::optional<unsigned char> battery_percentage;
std::optional<unsigned char> battery_percentage_peripheral;
}; };
public: public:
@@ -59,6 +60,12 @@ class Bluetooth : public ALabel {
gpointer) -> void; gpointer) -> void;
auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional<unsigned char>; auto getDeviceBatteryPercentage(GDBusObject*) -> std::optional<unsigned char>;
auto getDeviceGattBatteryLevels(GDBusObject*, std::optional<unsigned char>&,
std::optional<unsigned char>&) -> void;
static auto processBatteryServiceCharacteristics(GList*, const std::string&, const std::string&,
const std::string&,
std::optional<unsigned char>&,
std::optional<unsigned char>&) -> void;
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool; auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool; auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <epoxy/gl.h>
#include "AModule.hpp"
#include "cava_backend.hpp"
namespace waybar::modules::cava {
class CavaGLSL final : public AModule, public Gtk::GLArea {
public:
CavaGLSL(const std::string&, const Json::Value&);
~CavaGLSL() = default;
private:
std::shared_ptr<CavaBackend> backend_;
struct ::cava::config_params prm_;
int frame_counter{0};
bool silence_{false};
bool hide_on_silence_{false};
// Cava method
auto onUpdate(const ::cava::audio_raw& input) -> void;
auto onSilence() -> void;
// Member variable to store the shared pointer
std::shared_ptr<::cava::audio_raw> m_data_;
GLuint shaderProgram_;
// OpenGL variables
GLuint fbo_;
GLuint texture_;
GLint uniform_bars_;
GLint uniform_previous_bars_;
GLint uniform_bars_count_;
GLint uniform_time_;
// Methods
void onRealize();
bool onRender(const Glib::RefPtr<Gdk::GLContext>& context);
void initShaders();
void initSurface();
void initGLSL();
GLuint loadShader(const std::string& fileName, GLenum type);
};
} // namespace waybar::modules::cava
@@ -9,20 +9,20 @@ class Cava final : public ALabel, public sigc::trackable {
public: public:
Cava(const std::string&, const Json::Value&); Cava(const std::string&, const Json::Value&);
~Cava() = default; ~Cava() = default;
auto onUpdate(const std::string& input) -> void;
auto onSilence() -> void;
auto doAction(const std::string& name) -> void override; auto doAction(const std::string& name) -> void override;
private: private:
std::shared_ptr<CavaBackend> backend_; std::shared_ptr<CavaBackend> backend_;
// Text to display // Text to display
std::string label_text_{""}; Glib::ustring label_text_{""};
bool silence_{false};
bool hide_on_silence_{false}; bool hide_on_silence_{false};
std::string format_silent_{""}; std::string format_silent_{""};
int ascii_range_{0}; int ascii_range_{0};
bool silence_{false};
// Cava method // Cava method
void pause_resume(); void pause_resume();
auto onUpdate(const std::string& input) -> void;
auto onSilence() -> void;
// ModuleActionMap // ModuleActionMap
static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()> static inline std::map<const std::string, void (waybar::modules::cava::Cava::* const)()>
actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}}; actionMap_{{"mode", &waybar::modules::cava::Cava::pause_resume}};
+13 -3
View File
@@ -32,29 +32,36 @@ class CavaBackend final {
int getAsciiRange(); int getAsciiRange();
void doPauseResume(); void doPauseResume();
void Update(); void Update();
const struct ::cava::config_params* getPrm();
std::chrono::milliseconds getFrameTimeMilsec();
// Signal accessor // Signal accessor
using type_signal_update = sigc::signal<void(const std::string&)>; using type_signal_update = sigc::signal<void(const std::string&)>;
type_signal_update signal_update(); type_signal_update signal_update();
using type_signal_audio_raw_update = sigc::signal<void(const ::cava::audio_raw&)>;
type_signal_audio_raw_update signal_audio_raw_update();
using type_signal_silence = sigc::signal<void()>; using type_signal_silence = sigc::signal<void()>;
type_signal_silence signal_silence(); type_signal_silence signal_silence();
private: private:
CavaBackend(const Json::Value& config); CavaBackend(const Json::Value& config);
util::SleeperThread thread_;
util::SleeperThread read_thread_; util::SleeperThread read_thread_;
util::SleeperThread out_thread_;
// Cava API to read audio source // Cava API to read audio source
::cava::ptr input_source_; ::cava::ptr input_source_{NULL};
struct ::cava::error_s error_{}; // cava errors struct ::cava::error_s error_{}; // cava errors
struct ::cava::config_params prm_{}; // cava parameters struct ::cava::config_params prm_{}; // cava parameters
struct ::cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data) struct ::cava::audio_raw audio_raw_{}; // cava handled raw audio data(is based on audio_data)
struct ::cava::audio_data audio_data_{}; // cava audio data struct ::cava::audio_data audio_data_{}; // cava audio data
struct ::cava::cava_plan* plan_; //{new cava_plan{}}; struct ::cava::cava_plan* plan_{NULL}; //{new cava_plan{}};
std::chrono::seconds fetch_input_delay_{4}; std::chrono::seconds fetch_input_delay_{4};
// Delay to handle audio source // Delay to handle audio source
std::chrono::milliseconds frame_time_milsec_{1s}; std::chrono::milliseconds frame_time_milsec_{1s};
const Json::Value& config_;
int re_paint_{0}; int re_paint_{0};
bool silence_{false}; bool silence_{false};
bool silence_prev_{false}; bool silence_prev_{false};
@@ -66,9 +73,12 @@ class CavaBackend final {
void execute(); void execute();
bool isSilence(); bool isSilence();
void doUpdate(bool force = false); void doUpdate(bool force = false);
void loadConfig();
void freeBackend();
// Signal // Signal
type_signal_update m_signal_update_; type_signal_update m_signal_update_;
type_signal_audio_raw_update m_signal_audio_raw_;
type_signal_silence m_signal_silence_; type_signal_silence m_signal_silence_;
}; };
} // namespace waybar::modules::cava } // namespace waybar::modules::cava
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#ifdef HAVE_LIBCAVA
#include "cavaRaw.hpp"
#include "cava_backend.hpp"
#ifdef HAVE_LIBCAVAGLSL
#include "cavaGLSL.hpp"
#endif
#endif
namespace waybar::modules::cava {
AModule* getModule(const std::string& id, const Json::Value& config) {
#ifdef HAVE_LIBCAVA
const std::shared_ptr<CavaBackend> backend_{waybar::modules::cava::CavaBackend::inst(config)};
switch (backend_->getPrm()->output) {
#ifdef HAVE_LIBCAVAGLSL
case ::cava::output_method::OUTPUT_SDL_GLSL:
return new waybar::modules::cava::CavaGLSL(id, config);
#endif
default:
return new waybar::modules::cava::Cava(id, config);
}
#else
throw std::runtime_error("Unknown module");
#endif
};
} // namespace waybar::modules::cava
+4
View File
@@ -80,6 +80,7 @@ class Clock final : public ALabel {
void cldShift_reset(); void cldShift_reset();
void tz_up(); void tz_up();
void tz_down(); void tz_down();
void action_exec(const std::string& action);
// Module Action Map // Module Action Map
static inline std::map<const std::string, void (waybar::modules::Clock::* const)()> actionMap_{ static inline std::map<const std::string, void (waybar::modules::Clock::* const)()> actionMap_{
{"mode", &waybar::modules::Clock::cldModeSwitch}, {"mode", &waybar::modules::Clock::cldModeSwitch},
@@ -88,6 +89,9 @@ class Clock final : public ALabel {
{"shift_reset", &waybar::modules::Clock::cldShift_reset}, {"shift_reset", &waybar::modules::Clock::cldShift_reset},
{"tz_up", &waybar::modules::Clock::tz_up}, {"tz_up", &waybar::modules::Clock::tz_up},
{"tz_down", &waybar::modules::Clock::tz_down}}; {"tz_down", &waybar::modules::Clock::tz_down}};
static inline std::map<const std::string,
void (waybar::modules::Clock::* const)(const std::string& action)>
actionWithArgsMap_{{"exec", &waybar::modules::Clock::action_exec}};
}; };
} // namespace waybar::modules } // namespace waybar::modules
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include <fmt/format.h>
#include <cstdint>
#include <fstream>
#include <numeric>
#include <string>
#include <utility>
#include <vector>
#include "AGraph.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class CpuGraph : public AGraph {
public:
CpuGraph(const std::string&, const Json::Value&);
virtual ~CpuGraph() = default;
auto update() -> void override;
private:
static constexpr const char* MODERATE_CLASS = "cpu-moderate";
static constexpr const char* HIGH_CLASS = "cpu-high";
static constexpr const char* INTENSIVE_CLASS = "cpu-intensive";
std::vector<std::tuple<size_t, size_t>> prev_times_;
util::SleeperThread thread_;
};
} // namespace waybar::modules
+6 -2
View File
@@ -5,14 +5,14 @@
#include <csignal> #include <csignal>
#include <string> #include <string>
#include "ALabel.hpp" #include "AIconLabel.hpp"
#include "util/command.hpp" #include "util/command.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Custom : public ALabel { class Custom : public AIconLabel {
public: public:
Custom(const std::string&, const std::string&, const Json::Value&, const std::string&); Custom(const std::string&, const std::string&, const Json::Value&, const std::string&);
virtual ~Custom(); virtual ~Custom();
@@ -35,6 +35,10 @@ class Custom : public ALabel {
std::string id_; std::string id_;
std::string alt_; std::string alt_;
std::string tooltip_; std::string tooltip_;
std::string last_tooltip_markup_;
std::string image_path_;
std::string image_name_;
unsigned app_icon_size_{24};
const bool tooltip_format_enabled_; const bool tooltip_format_enabled_;
std::vector<std::string> class_; std::vector<std::string> class_;
int percentage_; int percentage_;
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include <fmt/format.h>
#include <csignal>
#include <string>
#include "AGraph.hpp"
#include "util/command.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
class CustomGraph : public AGraph {
public:
CustomGraph(const std::string&, const std::string&, const Json::Value&, const std::string&);
virtual ~CustomGraph();
auto update() -> void override;
void refresh(int /*signal*/) override;
private:
void delayWorker();
void continuousWorker();
void waitingWorker();
void parseOutputRaw();
void parseOutputJson();
void handleEvent();
bool handleScroll(GdkEventScroll* e) override;
bool handleToggle(GdkEventButton* const& e) override;
const std::string name_;
const std::string output_name_;
std::string text_;
std::string id_;
std::string alt_;
std::string tooltip_;
const bool tooltip_format_enabled_;
std::vector<std::string> class_;
int percentage_;
FILE* fp_;
int pid_;
util::command::res output_;
util::JsonParser parser_;
util::SleeperThread thread_;
};
} // namespace waybar::modules
+5 -2
View File
@@ -4,6 +4,7 @@
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <fstream> #include <fstream>
#include <vector>
#include "ALabel.hpp" #include "ALabel.hpp"
#include "util/format.hpp" #include "util/format.hpp"
@@ -19,10 +20,12 @@ class Disk : public ALabel {
private: private:
util::SleeperThread thread_; util::SleeperThread thread_;
std::string path_; std::string header_;
std::vector<std::string> paths_;
std::string separator_;
std::string unit_; std::string unit_;
float calc_specific_divisor(const std::string divisor); float calc_specific_divisor(const std::string& divisor);
}; };
} // namespace waybar::modules } // namespace waybar::modules
+3
View File
@@ -21,6 +21,8 @@ class Tags : public waybar::AModule {
void handle_primary_clicked(uint32_t tag); void handle_primary_clicked(uint32_t tag);
bool handle_button_press(GdkEventButton* event_button, uint32_t tag); bool handle_button_press(GdkEventButton* event_button, uint32_t tag);
void handle_active_output(zdwl_ipc_output_v2* zdwl_output_v2, uint32_t active);
struct zdwl_ipc_manager_v2* status_manager_; struct zdwl_ipc_manager_v2* status_manager_;
struct wl_seat* seat_; struct wl_seat* seat_;
@@ -28,6 +30,7 @@ class Tags : public waybar::AModule {
const waybar::Bar& bar_; const waybar::Bar& bar_;
Gtk::Box box_; Gtk::Box box_;
std::vector<Gtk::Button> buttons_; std::vector<Gtk::Button> buttons_;
bool hide_vacant_;
struct zdwl_ipc_output_v2* output_status_; struct zdwl_ipc_output_v2* output_status_;
}; };
+4
View File
@@ -19,6 +19,7 @@ class Window : public AAppIconLabel, public sigc::trackable {
void handle_layout(const uint32_t layout); void handle_layout(const uint32_t layout);
void handle_title(const char* title); void handle_title(const char* title);
void handle_appid(const char* ppid); void handle_appid(const char* ppid);
void handle_active(const uint32_t active);
void handle_layout_symbol(const char* layout_symbol); void handle_layout_symbol(const char* layout_symbol);
void handle_frame(); void handle_frame();
@@ -30,6 +31,9 @@ class Window : public AAppIconLabel, public sigc::trackable {
std::string title_; std::string title_;
std::string appid_; std::string appid_;
std::string layout_symbol_; std::string layout_symbol_;
bool active_;
bool hide_inactive_;
bool hide_empty_;
uint32_t layout_; uint32_t layout_;
struct zdwl_ipc_output_v2* output_status_; struct zdwl_ipc_output_v2* output_status_;
+1 -1
View File
@@ -26,7 +26,7 @@ class Gamemode : public AModule {
const std::string DEFAULT_FORMAT = "{glyph}"; const std::string DEFAULT_FORMAT = "{glyph}";
const std::string DEFAULT_FORMAT_ALT = "{glyph} {count}"; const std::string DEFAULT_FORMAT_ALT = "{glyph} {count}";
const std::string DEFAULT_TOOLTIP_FORMAT = "Games running: {count}"; const std::string DEFAULT_TOOLTIP_FORMAT = "Games running: {count}";
const std::string DEFAULT_GLYPH = ""; const std::string DEFAULT_GLYPH = "󰊴";
void appear(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& name, void appear(const Glib::RefPtr<Gio::DBus::Connection>& connection, const Glib::ustring& name,
const Glib::ustring& name_owner); const Glib::ustring& name_owner);
+19 -3
View File
@@ -1,8 +1,10 @@
#pragma once #pragma once
#include <atomic>
#include <filesystem> #include <filesystem>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <optional>
#include <string> #include <string>
#include <thread> #include <thread>
#include <utility> #include <utility>
@@ -34,19 +36,33 @@ class IPC {
Json::Value getSocket1JsonReply(const std::string& rq); Json::Value getSocket1JsonReply(const std::string& rq);
static std::filesystem::path getSocketFolder(const char* instanceSig); static std::filesystem::path getSocketFolder(const char* instanceSig);
/// Dispatch a Hyprland command. Automatically uses the correct protocol
/// (legacy text or Lua-based) depending on the running Hyprland version.
static std::string dispatch(const std::string& dispatcher, const std::string& arg);
/// Build a Lua-format dispatch command string.
static std::string buildLuaDispatch(const std::string& dispatcher, const std::string& arg);
protected: protected:
static std::filesystem::path socketFolder_; static std::filesystem::path socketFolder_;
/// Detect whether the running Hyprland uses the Lua-based IPC protocol.
/// Returns true for Hyprland >= 0.54 (Lua config), false for older versions.
static bool isLuaProtocol();
static std::optional<bool> s_luaProtocolDetected_; // cached detection result
private: private:
void socketListener(); void socketListener();
void parseIPC(const std::string&); void parseIPC(const std::string&);
std::thread ipcThread_; std::thread ipcThread_;
std::mutex callbackMutex_; std::mutex callbackMutex_;
std::mutex socketMutex_;
util::JsonParser parser_; util::JsonParser parser_;
std::list<std::pair<std::string, EventHandler*>> callbacks_; std::list<std::pair<std::string, EventHandler*>> callbacks_;
int socketfd_; // the hyprland socket file descriptor int socketfd_ = -1; // the hyprland socket file descriptor
pid_t socketOwnerPid_; pid_t socketOwnerPid_ = -1;
bool running_ = true; // the ipcThread will stop running when this is false std::atomic<bool> running_ = true; // the ipcThread will stop running when this is false
}; };
}; // namespace waybar::modules::hyprland }; // namespace waybar::modules::hyprland
+2
View File
@@ -30,6 +30,8 @@ class Language : public waybar::ALabel, public EventHandler {
std::string short_description; std::string short_description;
}; };
auto removeXkbLayoutCssClass() -> void;
auto addXkbLayoutCssClass() -> void;
static auto getLayout(const std::string&) -> Layout; static auto getLayout(const std::string&) -> Layout;
std::mutex mutex_; std::mutex mutex_;
+1
View File
@@ -26,6 +26,7 @@ class Submap : public waybar::ALabel, public EventHandler {
const Bar& bar_; const Bar& bar_;
util::JsonParser parser_; util::JsonParser parser_;
std::string submap_; std::string submap_;
std::string prev_submap_;
bool always_on_ = false; bool always_on_ = false;
std::string default_submap_ = "Default"; std::string default_submap_ = "Default";
+11 -11
View File
@@ -20,8 +20,8 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
private: private:
struct Workspace { struct Workspace {
int id; int id = 0;
int windows; int windows = 0;
std::string last_window; std::string last_window;
std::string last_window_title; std::string last_window_title;
@@ -29,14 +29,14 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
}; };
struct WindowData { struct WindowData {
bool floating; bool floating = false;
int monitor = -1; int monitor = -1;
std::string class_name; std::string class_name;
std::string initial_class_name; std::string initial_class_name;
std::string title; std::string title;
std::string initial_title; std::string initial_title;
bool fullscreen; bool fullscreen = false;
bool grouped; bool grouped = false;
static auto parse(const Json::Value&) -> WindowData; static auto parse(const Json::Value&) -> WindowData;
}; };
@@ -47,7 +47,7 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
void queryActiveWorkspace(); void queryActiveWorkspace();
void setClass(const std::string&, bool enable); void setClass(const std::string&, bool enable);
bool separateOutputs_; bool separateOutputs_ = false;
std::mutex mutex_; std::mutex mutex_;
const Bar& bar_; const Bar& bar_;
util::JsonParser parser_; util::JsonParser parser_;
@@ -55,11 +55,11 @@ class Window : public waybar::AAppIconLabel, public EventHandler {
Workspace workspace_; Workspace workspace_;
std::string soloClass_; std::string soloClass_;
std::string lastSoloClass_; std::string lastSoloClass_;
bool solo_; bool solo_ = false;
bool allFloating_; bool allFloating_ = false;
bool swallowing_; bool swallowing_ = false;
bool fullscreen_; bool fullscreen_ = false;
bool focused_; bool focused_ = false;
IPC& m_ipc; IPC& m_ipc;
}; };
@@ -40,10 +40,11 @@ struct WindowRepr {
class WindowCreationPayload { class WindowCreationPayload {
public: public:
WindowCreationPayload(std::string workspace_name, WindowAddress window_address, WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
WindowRepr window_repr); WindowRepr window_repr);
WindowCreationPayload(std::string workspace_name, WindowAddress window_address, WindowCreationPayload(const std::string& workspace_name, WindowAddress window_address,
std::string window_class, std::string window_title, bool is_active); const std::string& window_class, const std::string& window_title,
bool is_active);
WindowCreationPayload(Json::Value const& client_data); WindowCreationPayload(Json::Value const& client_data);
int incrementTimeSpentUncreated(); int incrementTimeSpentUncreated();
+13
View File
@@ -30,6 +30,7 @@ class Workspace {
public: public:
explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager, explicit Workspace(const Json::Value& workspace_data, Workspaces& workspace_manager,
const Json::Value& clients_data = Json::Value::nullRef); const Json::Value& clients_data = Json::Value::nullRef);
~Workspace();
std::string& selectIcon(std::map<std::string, std::string>& icons_map); std::string& selectIcon(std::map<std::string, std::string>& icons_map);
Gtk::Button& button() { return m_button; }; Gtk::Button& button() { return m_button; };
@@ -45,6 +46,15 @@ class Workspace {
bool isUrgent() const { return m_isUrgent; }; bool isUrgent() const { return m_isUrgent; };
bool handleClicked(GdkEventButton* bt) const; bool handleClicked(GdkEventButton* bt) const;
bool handleEnter(GdkEventCrossing* event);
bool handleLeave(GdkEventCrossing* event);
void startHoverCheck();
void stopHoverCheck();
bool syncHoverClass();
bool pointerInsideButton();
void setActive(bool value = true) { m_isActive = value; }; void setActive(bool value = true) { m_isActive = value; };
void setPersistentRule(bool value = true) { m_isPersistentRule = value; }; void setPersistentRule(bool value = true) { m_isPersistentRule = value; };
void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; }; void setPersistentConfig(bool value = true) { m_isPersistentConfig = value; };
@@ -71,6 +81,7 @@ class Workspace {
int m_id; int m_id;
std::string m_name; std::string m_name;
std::string m_prevNameClass;
std::string m_output; std::string m_output;
uint m_windows; uint m_windows;
bool m_isActive = false; bool m_isActive = false;
@@ -80,6 +91,8 @@ class Workspace {
bool m_isUrgent = false; bool m_isUrgent = false;
bool m_isVisible = false; bool m_isVisible = false;
sigc::connection m_hoverCheckConnection;
std::vector<WindowRepr> m_windowMap; std::vector<WindowRepr> m_windowMap;
Gtk::Button m_button; Gtk::Button m_button;
+16 -1
View File
@@ -4,6 +4,7 @@
#include <gtkmm/enums.h> #include <gtkmm/enums.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <json/value.h> #include <json/value.h>
#include <sigc++/connection.h>
#include <cstdint> #include <cstdint>
#include <map> #include <map>
@@ -38,11 +39,13 @@ class Workspaces : public AModule, public EventHandler {
auto allOutputs() const -> bool { return m_allOutputs; } auto allOutputs() const -> bool { return m_allOutputs; }
auto showSpecial() const -> bool { return m_showSpecial; } auto showSpecial() const -> bool { return m_showSpecial; }
auto activeOnly() const -> bool { return m_activeOnly; } auto activeOnly() const -> bool { return m_activeOnly; }
auto hideActive() const -> bool { return m_hideActive; }
auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; } auto specialVisibleOnly() const -> bool { return m_specialVisibleOnly; }
auto persistentOnly() const -> bool { return m_persistentOnly; } auto persistentOnly() const -> bool { return m_persistentOnly; }
auto moveToMonitor() const -> bool { return m_moveToMonitor; } auto moveToMonitor() const -> bool { return m_moveToMonitor; }
auto enableTaskbar() const -> bool { return m_enableTaskbar; } auto enableTaskbar() const -> bool { return m_enableTaskbar; }
auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; } auto taskbarWithIcon() const -> bool { return m_taskbarWithIcon; }
auto barScroll() const -> bool { return m_barScroll; }
auto getBarOutput() const -> std::string { return m_bar.output->name; } auto getBarOutput() const -> std::string { return m_bar.output->name; }
auto formatBefore() const -> std::string { return m_formatBefore; } auto formatBefore() const -> std::string { return m_formatBefore; }
@@ -54,12 +57,15 @@ class Workspaces : public AModule, public EventHandler {
auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; } auto taskbarReverseDirection() const -> bool { return m_taskbarReverseDirection; }
auto onClickWindow() const -> std::string { return m_onClickWindow; } auto onClickWindow() const -> std::string { return m_onClickWindow; }
auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; } auto getIgnoredWindows() const -> std::vector<std::regex> { return m_ignoreWindows; }
auto maxWindows() const -> int { return m_maxWindows; }
enum class ActiveWindowPosition { NONE, FIRST, LAST }; enum class ActiveWindowPosition { NONE, FIRST, LAST };
auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; } auto activeWindowPosition() const -> ActiveWindowPosition { return m_activeWindowPosition; }
std::string getRewrite(std::string window_class, std::string window_title); std::string getRewrite(const std::string& window_class, const std::string& window_title);
std::string& getWindowSeparator() { return m_formatWindowSeparator; } std::string& getWindowSeparator() { return m_formatWindowSeparator; }
auto windowRewriteGroupThreshold() const -> int { return m_windowRewriteGroupThreshold; }
auto const& getWindowRewriteGroupFormat() const { return m_windowRewriteGroupFormat; }
bool isWorkspaceIgnored(std::string const& workspace_name); bool isWorkspaceIgnored(std::string const& workspace_name);
bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; } bool windowRewriteConfigUsesTitle() const { return m_anyWindowRewriteRuleUsesTitle; }
@@ -87,6 +93,7 @@ class Workspaces : public AModule, public EventHandler {
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void; auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void; auto populateFormatWindowSeparatorConfig(const Json::Value& config) -> void;
auto populateWindowRewriteConfig(const Json::Value& config) -> void; auto populateWindowRewriteConfig(const Json::Value& config) -> void;
auto populateMaxWindowsConfig(const Json::Value& config) -> void;
auto populateWorkspaceTaskbarConfig(const Json::Value& config) -> void; auto populateWorkspaceTaskbarConfig(const Json::Value& config) -> void;
void registerIpc(); void registerIpc();
@@ -122,6 +129,8 @@ class Workspaces : public AModule, public EventHandler {
static std::pair<std::string, std::string> splitDoublePayload(std::string const& payload); static std::pair<std::string, std::string> splitDoublePayload(std::string const& payload);
static std::tuple<std::string, std::string, std::string> splitTriplePayload( static std::tuple<std::string, std::string, std::string> splitTriplePayload(
std::string const& payload); std::string const& payload);
// scroll events
bool handleScroll(GdkEventScroll* e) override;
// Update methods // Update methods
void doUpdate(); void doUpdate();
@@ -142,9 +151,11 @@ class Workspaces : public AModule, public EventHandler {
bool m_allOutputs = false; bool m_allOutputs = false;
bool m_showSpecial = false; bool m_showSpecial = false;
bool m_activeOnly = false; bool m_activeOnly = false;
bool m_hideActive = false;
bool m_specialVisibleOnly = false; bool m_specialVisibleOnly = false;
bool m_persistentOnly = false; bool m_persistentOnly = false;
bool m_moveToMonitor = false; bool m_moveToMonitor = false;
bool m_barScroll = false;
Json::Value m_persistentWorkspaceConfig; Json::Value m_persistentWorkspaceConfig;
// Map for windows stored in workspaces not present in the current bar. // Map for windows stored in workspaces not present in the current bar.
@@ -168,6 +179,8 @@ class Workspaces : public AModule, public EventHandler {
util::RegexCollection m_windowRewriteRules; util::RegexCollection m_windowRewriteRules;
bool m_anyWindowRewriteRuleUsesTitle = false; bool m_anyWindowRewriteRuleUsesTitle = false;
std::string m_formatWindowSeparator; std::string m_formatWindowSeparator;
int m_windowRewriteGroupThreshold = 0;
std::string m_windowRewriteGroupFormat = "{icon}×{count}";
bool m_withIcon; bool m_withIcon;
uint64_t m_monitorId; uint64_t m_monitorId;
@@ -197,6 +210,7 @@ class Workspaces : public AModule, public EventHandler {
}; };
std::string m_onClickWindow; std::string m_onClickWindow;
std::string m_currentActiveWindowAddress; std::string m_currentActiveWindowAddress;
int m_maxWindows = 0;
std::vector<std::regex> m_ignoreWorkspaces; std::vector<std::regex> m_ignoreWorkspaces;
std::vector<std::regex> m_ignoreWindows; std::vector<std::regex> m_ignoreWindows;
@@ -204,6 +218,7 @@ class Workspaces : public AModule, public EventHandler {
std::mutex m_mutex; std::mutex m_mutex;
const Bar& m_bar; const Bar& m_bar;
Gtk::Box m_box; Gtk::Box m_box;
sigc::connection m_scrollEventConnection_;
IPC& m_ipc; IPC& m_ipc;
}; };
+10
View File
@@ -6,25 +6,35 @@
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
struct ext_idle_notification_v1;
namespace waybar::modules { namespace waybar::modules {
class IdleInhibitor : public ALabel { class IdleInhibitor : public ALabel {
sigc::connection timeout_; sigc::connection timeout_;
ext_idle_notification_v1* idle_notification_;
uint32_t idle_timeout_ms_;
public: public:
IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&); IdleInhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~IdleInhibitor(); virtual ~IdleInhibitor();
auto update() -> void override; auto update() -> void override;
auto refresh(int) -> void override;
static std::list<waybar::AModule*> modules; static std::list<waybar::AModule*> modules;
static bool status; static bool status;
private: private:
bool handleToggle(GdkEventButton* const& e) override; bool handleToggle(GdkEventButton* const& e) override;
void toggleStatus(); void toggleStatus();
void setupIdleNotification();
void teardownIdleNotification();
static void handleIdled(void* data, ext_idle_notification_v1* notification);
static void handleResumed(void* data, ext_idle_notification_v1* notification);
const Bar& bar_; const Bar& bar_;
struct zwp_idle_inhibitor_v1* idle_inhibitor_; struct zwp_idle_inhibitor_v1* idle_inhibitor_;
int pid_; int pid_;
bool wait_for_activity_;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+3 -2
View File
@@ -3,6 +3,7 @@
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <mutex>
#include <set> #include <set>
#include <unordered_map> #include <unordered_map>
@@ -35,12 +36,12 @@ class KeyboardState : public AModule {
std::string capslock_format_; std::string capslock_format_;
std::string scrolllock_format_; std::string scrolllock_format_;
const std::chrono::seconds interval_; const std::chrono::seconds interval_;
std::string icon_locked_; std::unordered_map<std::string, std::vector<std::string>> key_icon_states_;
std::string icon_unlocked_;
std::string devices_path_; std::string devices_path_;
struct libinput* libinput_; struct libinput* libinput_;
std::unordered_map<std::string, struct libinput_device*> libinput_devices_; std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
std::mutex devices_mutex_; // protects libinput_devices_
std::set<int> binding_keys; std::set<int> binding_keys;
util::SleeperThread libinput_thread_, hotplug_thread_; util::SleeperThread libinput_thread_, hotplug_thread_;
+67
View File
@@ -0,0 +1,67 @@
// include/modules/mango/backend.hpp
#pragma once
#include <list>
#include <mutex>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>
#include "util/json.hpp"
namespace waybar::modules::mango {
class EventHandler {
public:
virtual void onEvent(const Json::Value& ev) = 0;
virtual ~EventHandler() = default;
};
class IPC {
public:
static IPC& getInstance();
IPC(const IPC&) = delete;
IPC& operator=(const IPC&) = delete;
void registerForIPC(const std::string& ev, EventHandler* handler);
void unregisterForIPC(EventHandler* handler);
static Json::Value send(const Json::Value& request);
static void sendAsync(const Json::Value& request);
std::unique_lock<std::mutex> lockData() { return std::unique_lock<std::mutex>(data_mutex_); }
std::unordered_map<std::string, Json::Value> getMonitors() const;
Json::Value getMonitor(const std::string& name);
Json::Value getActiveClientForMonitor(const std::string& name) const;
std::string getKeyboardLayout() const;
std::string getKeymode() const;
std::string getLayoutSymbolForMonitor(const std::string& name) const;
private:
IPC();
~IPC();
void startIPC();
static int connectToSocket();
void parseIPC(const std::string& line);
void handleMonitorUpdate(const Json::Value& mon);
void updateFocusingClient(const Json::Value& client);
void updateKeyboardLayout(const std::string& layout);
static Json::Value sendCommand(const std::string& cmd);
int sockfd_ = -1;
std::thread ipc_thread_;
mutable std::mutex data_mutex_;
std::unordered_map<std::string, Json::Value> monitors_;
std::unordered_map<uint64_t, Json::Value> clients_;
uint64_t focusing_client_id_ = 0;
std::string keyboard_layout_;
std::string keymode_;
Json::Value active_client_;
std::mutex callback_mutex_;
std::list<std::pair<std::string, EventHandler*>> callbacks_;
};
} // namespace waybar::modules::mango
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <mutex>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Keymode : public ALabel, public EventHandler {
public:
Keymode(const std::string&, const Bar&, const Json::Value&);
~Keymode() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
std::mutex mutex_;
const Bar& bar_;
std::string last_keymode_;
};
} // namespace waybar::modules::mango
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <xkbcommon/xkbregistry.h>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Language : public ALabel, public EventHandler {
public:
Language(const std::string&, const Bar&, const Json::Value&);
~Language() override;
void update() override;
private:
void updateFromIPC();
void onEvent(const Json::Value& ev) override;
void doUpdate();
struct Layout {
std::string full_name;
std::string short_name;
std::string variant;
std::string short_description;
};
Layout getLayout(const std::string& fullName);
std::mutex mutex_;
const Bar& bar_;
std::vector<Layout> layouts_;
unsigned current_idx_;
std::string last_short_name_;
struct rxkb_context* rxkb_ctx_ = nullptr;
};
} // namespace waybar::modules::mango
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <mutex>
#include <string>
#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Layout : public ALabel, public EventHandler {
public:
Layout(const std::string&, const Bar&, const Json::Value&);
~Layout() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
std::mutex mutex_;
const Bar& bar_;
std::string last_symbol_;
};
} // namespace waybar::modules::mango
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include <gtkmm/button.h>
#include <json/value.h>
#include <mutex>
#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Window : public AAppIconLabel, public EventHandler {
public:
Window(const std::string&, const Bar&, const Json::Value&);
~Window() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
void setClass(const std::string& className, bool enable);
const Bar& bar_;
std::string oldAppId_;
std::mutex mutex_;
};
} // namespace waybar::modules::mango
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include <gtkmm/button.h>
#include <json/value.h>
#include <unordered_map>
#include "AModule.hpp"
#include "bar.hpp"
#include "modules/mango/backend.hpp"
namespace waybar::modules::mango {
class Workspaces : public AModule, public EventHandler {
public:
Workspaces(const std::string&, const Bar&, const Json::Value&);
~Workspaces() override;
void update() override;
private:
void onEvent(const Json::Value& ev) override;
void doUpdate();
Gtk::Button& addButton(uint64_t idx);
void updateButtonState(Gtk::Button& button, const Json::Value& tag, const Json::Value& monitor);
std::string getIcon(const std::string& value, const Json::Value& tag);
bool handleButtonClick(GdkEventButton* event, uint64_t idx, bool isOverview);
const Bar& bar_;
Gtk::Box box_;
std::unordered_map<uint64_t, Gtk::Button> buttons_;
Gtk::Button* overview_button_ = nullptr;
std::string on_click_left_;
std::string on_click_middle_;
std::string on_click_right_;
};
} // namespace waybar::modules::mango
+2
View File
@@ -22,6 +22,8 @@ class Memory : public ALabel {
std::unordered_map<std::string, unsigned long> meminfo_; std::unordered_map<std::string, unsigned long> meminfo_;
util::SleeperThread thread_; util::SleeperThread thread_;
std::string unit_;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+9 -2
View File
@@ -28,11 +28,14 @@ class MPD : public ALabel {
unsigned timeout_; unsigned timeout_;
unsigned playing_interval_;
detail::unique_connection connection_; detail::unique_connection connection_;
detail::unique_status status_; detail::unique_status status_;
mpd_state state_; mpd_state state_;
detail::unique_song song_; detail::unique_song song_;
std::string ellipsis_;
public: public:
MPD(const std::string&, const Json::Value&); MPD(const std::string&, const Json::Value&);
@@ -44,7 +47,11 @@ class MPD : public ALabel {
std::string getFilename() const; std::string getFilename() const;
void setLabel(); void setLabel();
std::string getStateIcon() const; std::string getStateIcon() const;
std::string getOptionIcon(std::string optionName, bool activated) const; std::string getOptionIcon(const std::string& optionName, bool activated) const;
std::string getArtistStr(bool truncated) const;
std::string getAlbumArtistStr(bool truncated) const;
std::string getAlbumStr(bool truncated) const;
std::string getTitleStr(bool truncated) const;
// GUI-side methods // GUI-side methods
bool handlePlayPause(GdkEventButton* const&); bool handlePlayPause(GdkEventButton* const&);
@@ -54,11 +61,11 @@ class MPD : public ALabel {
void tryConnect(); void tryConnect();
void checkErrors(mpd_connection* conn); void checkErrors(mpd_connection* conn);
void fetchState(); void fetchState();
void queryMPD();
inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; } inline bool stopped() const { return connection_ && state_ == MPD_STATE_STOP; }
inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; } inline bool playing() const { return connection_ && state_ == MPD_STATE_PLAY; }
inline bool paused() const { return connection_ && state_ == MPD_STATE_PAUSE; } inline bool paused() const { return connection_ && state_ == MPD_STATE_PAUSE; }
inline unsigned playing_interval() const { return playing_interval_; }
}; };
#if !defined(MPD_NOINLINE) #if !defined(MPD_NOINLINE)
+5 -1
View File
@@ -82,6 +82,7 @@ class Idle : public State {
class Playing : public State { class Playing : public State {
Context* const ctx_; Context* const ctx_;
sigc::connection timer_connection_; sigc::connection timer_connection_;
sigc::connection idle_connection_;
public: public:
Playing(Context* const ctx) : ctx_{ctx} {} Playing(Context* const ctx) : ctx_{ctx} {}
@@ -98,7 +99,10 @@ class Playing : public State {
Playing(Playing const&) = delete; Playing(Playing const&) = delete;
Playing& operator=(Playing const&) = delete; Playing& operator=(Playing const&) = delete;
void timer() noexcept;
void idle() noexcept;
bool on_timer(); bool on_timer();
bool on_io(Glib::IOCondition const&);
}; };
class Paused : public State { class Paused : public State {
@@ -194,10 +198,10 @@ class Context {
bool is_paused() const; bool is_paused() const;
bool is_stopped() const; bool is_stopped() const;
constexpr std::size_t interval() const; constexpr std::size_t interval() const;
unsigned playing_interval() const;
void tryConnect() const; void tryConnect() const;
void checkErrors(mpd_connection*) const; void checkErrors(mpd_connection*) const;
void do_update(); void do_update();
void queryMPD() const;
void fetchState() const; void fetchState() const;
constexpr mpd_state state() const; constexpr mpd_state state() const;
void emit() const; void emit() const;
+3 -2
View File
@@ -1,13 +1,15 @@
#pragma once #pragma once
namespace detail { namespace detail {
using namespace std::literals::chrono_literals;
inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; } inline bool Context::is_connected() const { return mpd_module_->connection_ != nullptr; }
inline bool Context::is_playing() const { return mpd_module_->playing(); } inline bool Context::is_playing() const { return mpd_module_->playing(); }
inline bool Context::is_paused() const { return mpd_module_->paused(); } inline bool Context::is_paused() const { return mpd_module_->paused(); }
inline bool Context::is_stopped() const { return mpd_module_->stopped(); } inline bool Context::is_stopped() const { return mpd_module_->stopped(); }
constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_.count(); } constexpr inline std::size_t Context::interval() const { return mpd_module_->interval_ / 1s; }
inline unsigned Context::playing_interval() const { return mpd_module_->playing_interval(); }
inline void Context::tryConnect() const { mpd_module_->tryConnect(); } inline void Context::tryConnect() const { mpd_module_->tryConnect(); }
inline unique_connection& Context::connection() { return mpd_module_->connection_; } inline unique_connection& Context::connection() { return mpd_module_->connection_; }
constexpr inline mpd_state Context::state() const { return mpd_module_->state_; } constexpr inline mpd_state Context::state() const { return mpd_module_->state_; }
@@ -15,7 +17,6 @@ constexpr inline mpd_state Context::state() const { return mpd_module_->state_;
inline void Context::do_update() { mpd_module_->setLabel(); } inline void Context::do_update() { mpd_module_->setLabel(); }
inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); } inline void Context::checkErrors(mpd_connection* conn) const { mpd_module_->checkErrors(conn); }
inline void Context::queryMPD() const { mpd_module_->queryMPD(); }
inline void Context::fetchState() const { mpd_module_->fetchState(); } inline void Context::fetchState() const { mpd_module_->fetchState(); }
inline void Context::emit() const { mpd_module_->emit(); } inline void Context::emit() const { mpd_module_->emit(); }
+4
View File
@@ -38,6 +38,7 @@ class Mpris : public ALabel {
std::optional<std::string> artist; std::optional<std::string> artist;
std::optional<std::string> album; std::optional<std::string> album;
std::optional<std::string> album_artist;
std::optional<std::string> title; std::optional<std::string> title;
std::optional<std::string> length; // as HH:MM:SS std::optional<std::string> length; // as HH:MM:SS
std::optional<std::string> position; // same format std::optional<std::string> position; // same format
@@ -76,8 +77,11 @@ class Mpris : public ALabel {
std::string player_; std::string player_;
std::vector<std::string> ignored_players_; std::vector<std::string> ignored_players_;
bool prefer_album_artist_;
PlayerctlPlayerManager* manager; PlayerctlPlayerManager* manager;
PlayerctlPlayer* player; PlayerctlPlayer* player;
PlayerctlPlayer* last_active_player_ = nullptr;
std::string lastStatus; std::string lastStatus;
std::string lastPlayer; std::string lastPlayer;
+3
View File
@@ -70,6 +70,9 @@ class Network : public ALabel {
unsigned long long bandwidth_down_total_{0}; unsigned long long bandwidth_down_total_{0};
unsigned long long bandwidth_up_total_{0}; unsigned long long bandwidth_up_total_{0};
unsigned long long bandwidth_down_prev_{0};
unsigned long long bandwidth_up_prev_{0};
std::chrono::steady_clock::time_point bandwidth_last_sample_time_;
std::string state_; std::string state_;
std::string essid_; std::string essid_;
+1 -1
View File
@@ -17,7 +17,7 @@ class EventHandler {
class IPC { class IPC {
public: public:
IPC() { startIPC(); } IPC();
void registerForIPC(const std::string& ev, EventHandler* ev_handler); void registerForIPC(const std::string& ev, EventHandler* ev_handler);
void unregisterForIPC(EventHandler* handler); void unregisterForIPC(EventHandler* handler);
+7
View File
@@ -2,6 +2,7 @@
#include <gtkmm/button.h> #include <gtkmm/button.h>
#include <json/value.h> #include <json/value.h>
#include <regex> #include <regex>
#include <vector> #include <vector>
@@ -20,9 +21,11 @@ class Workspaces : public AModule, public EventHandler {
private: private:
void onEvent(const Json::Value& ev) override; void onEvent(const Json::Value& ev) override;
void doUpdate(); void doUpdate();
void sortWorkspaces(std::vector<Json::Value>& workspaces) const;
Gtk::Button& addButton(const Json::Value& ws); Gtk::Button& addButton(const Json::Value& ws);
std::string getIcon(const std::string& value, const Json::Value& ws); std::string getIcon(const std::string& value, const Json::Value& ws);
bool isWorkspaceIgnored(const std::string& name); bool isWorkspaceIgnored(const std::string& name);
bool handleScroll(GdkEventScroll* /*unused*/) override;
const Bar& bar_; const Bar& bar_;
Gtk::Box box_; Gtk::Box box_;
@@ -30,6 +33,10 @@ class Workspaces : public AModule, public EventHandler {
std::unordered_map<uint64_t, Gtk::Button> buttons_; std::unordered_map<uint64_t, Gtk::Button> buttons_;
// Vec of regex rules to ignore workspaces. // Vec of regex rules to ignore workspaces.
std::vector<std::regex> ignoreWorkspaces_; std::vector<std::regex> ignoreWorkspaces_;
bool sort_by_id_ = false;
bool sort_by_name_ = false;
bool sort_by_coordinates_ = false;
}; };
} // namespace waybar::modules::niri } // namespace waybar::modules::niri
+10 -1
View File
@@ -9,9 +9,18 @@ namespace waybar::modules {
struct Profile { struct Profile {
std::string name; std::string name;
// Legacy driver field, kept for backward compatibility with the
// `{driver}` format placeholder and with older power-profiles-daemon
// versions that only expose a single `Driver` DBus property.
std::string driver; std::string driver;
std::string cpuDriver;
std::string platformDriver;
Profile(std::string n, std::string d) : name(std::move(n)), driver(std::move(d)) {} Profile(std::string n, std::string d, std::string cd, std::string pd)
: name(std::move(n)),
driver(std::move(d)),
cpuDriver(std::move(cd)),
platformDriver(std::move(pd)) {}
}; };
class PowerProfilesDaemon : public ALabel { class PowerProfilesDaemon : public ALabel {
+1
View File
@@ -28,6 +28,7 @@ class Privacy : public AModule {
// Config // Config
Gtk::Box box_; Gtk::Box box_;
std::vector<PrivacyItem*> modules_;
uint iconSpacing = 4; uint iconSpacing = 4;
uint iconSize = 20; uint iconSize = 20;
uint transition_duration = 250; uint transition_duration = 250;
+1
View File
@@ -22,6 +22,7 @@ class Pulseaudio : public ALabel {
const std::vector<std::string> getPulseIcon() const; const std::vector<std::string> getPulseIcon() const;
std::shared_ptr<util::AudioBackend> backend = nullptr; std::shared_ptr<util::AudioBackend> backend = nullptr;
util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+9 -6
View File
@@ -6,11 +6,6 @@
#include "util/audio_backend.hpp" #include "util/audio_backend.hpp"
namespace waybar::modules { namespace waybar::modules {
enum class PulseaudioSliderTarget {
Sink,
Source,
};
class PulseaudioSlider : public ASlider { class PulseaudioSlider : public ASlider {
public: public:
PulseaudioSlider(const std::string&, const Json::Value&); PulseaudioSlider(const std::string&, const Json::Value&);
@@ -21,7 +16,15 @@ class PulseaudioSlider : public ASlider {
private: private:
std::shared_ptr<util::AudioBackend> backend = nullptr; std::shared_ptr<util::AudioBackend> backend = nullptr;
PulseaudioSliderTarget target = PulseaudioSliderTarget::Sink; util::PulseaudioTarget target = util::PulseaudioTarget::Sink;
bool zero_on_mute = true;
bool unmute_on_volume_change = true;
// zero_on_mute and unmute_on_volume_change default to true
// in order to maintain previous behaviour when using a
// config in which these values are undefined
bool previously_muted = false;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+4
View File
@@ -20,6 +20,8 @@ class Tags : public waybar::AModule {
void handle_focused_tags(uint32_t tags); void handle_focused_tags(uint32_t tags);
void handle_view_tags(struct wl_array* tags); void handle_view_tags(struct wl_array* tags);
void handle_urgent_tags(uint32_t tags); void handle_urgent_tags(uint32_t tags);
void handle_focused_output(struct wl_output* output);
void handle_unfocused_output(struct wl_output* output);
void handle_show(); void handle_show();
void handle_primary_clicked(uint32_t tag); void handle_primary_clicked(uint32_t tag);
@@ -31,9 +33,11 @@ class Tags : public waybar::AModule {
private: private:
const waybar::Bar& bar_; const waybar::Bar& bar_;
struct wl_output* output_; // stores the output this module belongs to
Gtk::Box box_; Gtk::Box box_;
std::vector<Gtk::Button> buttons_; std::vector<Gtk::Button> buttons_;
struct zriver_output_status_v1* output_status_; struct zriver_output_status_v1* output_status_;
struct zriver_seat_status_v1* seat_status_;
}; };
} /* namespace waybar::modules::river */ } /* namespace waybar::modules::river */
+14 -3
View File
@@ -14,11 +14,14 @@ namespace waybar::modules::SNI {
class Host { class Host {
public: public:
Host(const std::size_t id, const Json::Value&, const Bar&, Host(const std::size_t id, const Json::Value&, const Bar&, const std::vector<std::string>&,
const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void(std::unique_ptr<Item>&)>&,
const std::function<void(std::unique_ptr<Item>&)>&); const std::function<void(std::unique_ptr<Item>&)>&, const std::function<void()>&);
~Host(); ~Host();
void checkIgnoreList(const std::vector<std::string>& ignore_list,
const std::function<void(std::unique_ptr<Item>&)>& on_remove);
private: private:
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring); void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring, void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring,
@@ -28,9 +31,13 @@ class Host {
static void registerHost(GObject*, GAsyncResult*, gpointer); static void registerHost(GObject*, GAsyncResult*, gpointer);
static void itemRegistered(SnWatcher*, const gchar*, gpointer); static void itemRegistered(SnWatcher*, const gchar*, gpointer);
static void itemUnregistered(SnWatcher*, const gchar*, gpointer); static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
void itemReady(Item&);
void itemInvalidated(Item&);
void removeItem(std::vector<std::unique_ptr<Item>>::iterator);
void clearItems();
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string); std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
void addRegisteredItem(std::string service); void addRegisteredItem(const std::string& service);
std::vector<std::unique_ptr<Item>> items_; std::vector<std::unique_ptr<Item>> items_;
const std::string bus_name_; const std::string bus_name_;
@@ -39,10 +46,14 @@ class Host {
std::size_t watcher_id_; std::size_t watcher_id_;
GCancellable* cancellable_ = nullptr; GCancellable* cancellable_ = nullptr;
SnWatcher* watcher_ = nullptr; SnWatcher* watcher_ = nullptr;
sigc::connection retry_connection_;
unsigned retry_count_ = 0;
const Json::Value& config_; const Json::Value& config_;
const Bar& bar_; const Bar& bar_;
const std::vector<std::string> ignore_list_;
const std::function<void(std::unique_ptr<Item>&)> on_add_; const std::function<void(std::unique_ptr<Item>&)> on_add_;
const std::function<void(std::unique_ptr<Item>&)> on_remove_; const std::function<void(std::unique_ptr<Item>&)> on_remove_;
const std::function<void()> on_update_;
}; };
} // namespace waybar::modules::SNI } // namespace waybar::modules::SNI
+22 -2
View File
@@ -11,6 +11,7 @@
#include <libdbusmenu-gtk/dbusmenu-gtk.h> #include <libdbusmenu-gtk/dbusmenu-gtk.h>
#include <sigc++/trackable.h> #include <sigc++/trackable.h>
#include <functional>
#include <set> #include <set>
#include <string_view> #include <string_view>
@@ -25,9 +26,13 @@ struct ToolTip {
class Item : public sigc::trackable { class Item : public sigc::trackable {
public: public:
Item(const std::string&, const std::string&, const Json::Value&, const Bar&); Item(const std::string&, const std::string&, const Json::Value&, const Bar&,
const std::function<void(Item&)>&, const std::function<void(Item&)>&,
const std::function<void()>&);
~Item(); ~Item();
bool isReady() const;
std::string bus_name; std::string bus_name;
std::string object_path; std::string object_path;
@@ -41,9 +46,12 @@ class Item : public sigc::trackable {
std::string title; std::string title;
std::string icon_name; std::string icon_name;
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap; Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
bool has_custom_icon_ = false;
Glib::RefPtr<Gtk::IconTheme> icon_theme; Glib::RefPtr<Gtk::IconTheme> icon_theme;
std::string overlay_icon_name; std::string overlay_icon_name;
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
std::string attention_icon_name; std::string attention_icon_name;
Glib::RefPtr<Gdk::Pixbuf> attention_icon_pixmap;
std::string attention_movie_name; std::string attention_movie_name;
std::string icon_theme_path; std::string icon_theme_path;
std::string menu; std::string menu;
@@ -62,6 +70,8 @@ class Item : public sigc::trackable {
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result); void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
void setProperty(const Glib::ustring& name, Glib::VariantBase& value); void setProperty(const Glib::ustring& name, Glib::VariantBase& value);
void setStatus(const Glib::ustring& value); void setStatus(const Glib::ustring& value);
void setReady();
void invalidate();
void setCustomIcon(const std::string& id); void setCustomIcon(const std::string& id);
void getUpdatedProperties(); void getUpdatedProperties();
void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result); void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result);
@@ -69,8 +79,13 @@ class Item : public sigc::trackable {
const Glib::VariantContainerBase& arguments); const Glib::VariantContainerBase& arguments);
void updateImage(); void updateImage();
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant); static Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
Glib::RefPtr<Gdk::Pixbuf> getIconPixbuf(); Glib::RefPtr<Gdk::Pixbuf> getIconPixbuf();
Glib::RefPtr<Gdk::Pixbuf> getAttentionIconPixbuf();
Glib::RefPtr<Gdk::Pixbuf> getOverlayIconPixbuf();
Glib::RefPtr<Gdk::Pixbuf> loadIconFromNameOrFile(const std::string& name, bool log_failure);
static Glib::RefPtr<Gdk::Pixbuf> overlayPixbufs(const Glib::RefPtr<Gdk::Pixbuf>&,
const Glib::RefPtr<Gdk::Pixbuf>&);
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size); Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
double getScaledIconSize(); double getScaledIconSize();
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer); static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
@@ -86,8 +101,13 @@ class Item : public sigc::trackable {
gdouble distance_scrolled_y_ = 0; gdouble distance_scrolled_y_ = 0;
// visibility of items with Status == Passive // visibility of items with Status == Passive
bool show_passive_ = false; bool show_passive_ = false;
bool ready_ = false;
Glib::ustring status_ = "active";
const Bar& bar_; const Bar& bar_;
const std::function<void(Item&)> on_ready_;
const std::function<void(Item&)> on_invalidate_;
const std::function<void()> on_updated_;
Glib::RefPtr<Gio::DBus::Proxy> proxy_; Glib::RefPtr<Gio::DBus::Proxy> proxy_;
Glib::RefPtr<Gio::Cancellable> cancellable_; Glib::RefPtr<Gio::Cancellable> cancellable_;
+4 -1
View File
@@ -19,11 +19,14 @@ class Tray : public AModule {
private: private:
void onAdd(std::unique_ptr<Item>& item); void onAdd(std::unique_ptr<Item>& item);
void onRemove(std::unique_ptr<Item>& item); void onRemove(std::unique_ptr<Item>& item);
void checkIgnoreList(std::unique_ptr<Item>* item);
std::vector<std::string> parseIgnoreList(const Json::Value& config);
void queueUpdate();
static inline std::size_t nb_hosts_ = 0; static inline std::size_t nb_hosts_ = 0;
bool show_passive_ = false;
Gtk::Box box_; Gtk::Box box_;
SNI::Watcher::singleton watcher_; SNI::Watcher::singleton watcher_;
std::vector<std::string> ignore_list_;
SNI::Host host_; SNI::Host host_;
}; };
+1 -1
View File
@@ -37,7 +37,7 @@ class BarIpcClient {
void onModeUpdate(bool visible_by_modifier); void onModeUpdate(bool visible_by_modifier);
void onUrgencyUpdate(bool visible_by_urgency); void onUrgencyUpdate(bool visible_by_urgency);
void update(); void update();
bool isModuleEnabled(std::string name); bool isModuleEnabled(const std::string& name);
Bar& bar_; Bar& bar_;
util::JsonParser parser_; util::JsonParser parser_;
+11 -12
View File
@@ -1,17 +1,15 @@
#pragma once #pragma once
#include <sigc++/sigc++.h> #include <sigc++/sigc++.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <cstring> #include <cstdint>
#include <memory> #include <functional>
#include <mutex> #include <mutex>
#include <stdexcept>
#include <string> #include <string>
#include "ipc.hpp" #include "ipc.hpp"
#include "util/SafeSignal.hpp"
#include "util/scoped_fd.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules::sway { namespace waybar::modules::sway {
@@ -27,8 +25,8 @@ class Ipc {
std::string payload; std::string payload;
}; };
sigc::signal<void, const struct ipc_response &> signal_event; ::waybar::SafeSignal<const struct ipc_response&> signal_event;
sigc::signal<void, const struct ipc_response &> signal_cmd; ::waybar::SafeSignal<const struct ipc_response&> signal_cmd;
void sendCmd(uint32_t type, const std::string& payload = ""); void sendCmd(uint32_t type, const std::string& payload = "");
void subscribe(const std::string& payload); void subscribe(const std::string& payload);
@@ -39,13 +37,14 @@ class Ipc {
static inline const std::string ipc_magic_ = "i3-ipc"; static inline const std::string ipc_magic_ = "i3-ipc";
static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8; static inline const size_t ipc_header_size_ = ipc_magic_.size() + 8;
const std::string getSocketPath() const; static std::string getSocketPath();
int open(const std::string &) const; static int open(const std::string&);
struct ipc_response send(int fd, uint32_t type, const std::string& payload = ""); struct ipc_response send(int fd, uint32_t type, const std::string& payload = "");
struct ipc_response recv(int fd); struct ipc_response recv(int fd);
int fd_; util::ScopedFd fd_;
int fd_event_; util::ScopedFd fd_event_;
std::mutex mutex_; std::mutex mutex_;
util::SleeperThread thread_; util::SleeperThread thread_;
}; };
+1 -1
View File
@@ -47,7 +47,7 @@ class Language : public ALabel, public sigc::trackable {
void onEvent(const struct Ipc::ipc_response&); void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&); void onCmd(const struct Ipc::ipc_response&);
auto set_current_layout(std::string current_layout) -> void; auto set_current_layout(const std::string& current_layout) -> void;
auto init_layouts_map(const std::vector<std::string>& used_layouts) -> void; auto init_layouts_map(const std::vector<std::string>& used_layouts) -> void;
const static std::string XKB_LAYOUT_NAMES_KEY; const static std::string XKB_LAYOUT_NAMES_KEY;
+6 -2
View File
@@ -24,12 +24,15 @@ class Workspaces : public AModule, public sigc::trackable {
private: private:
static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\""; static constexpr std::string_view workspace_switch_cmd_ = "workspace {} \"{}\"";
static constexpr std::string_view workspace_switch_number_cmd_ = "workspace {} number {}";
static constexpr std::string_view persistent_workspace_switch_cmd_ = static constexpr std::string_view persistent_workspace_switch_cmd_ =
R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")"; R"(workspace {} "{}"; move workspace to output "{}"; workspace {} "{}")";
static int convertWorkspaceNameToNum(std::string name); static int convertWorkspaceNameToNum(const std::string& name);
static int windowRewritePriorityFunction(std::string const& window_rule); static int windowRewritePriorityFunction(std::string const& window_rule);
auto populateIgnoreWorkspacesConfig(const Json::Value& config) -> void;
bool isWorkspaceIgnored(std::string const& name);
void onCmd(const struct Ipc::ipc_response&); void onCmd(const struct Ipc::ipc_response&);
void onEvent(const struct Ipc::ipc_response&); void onEvent(const struct Ipc::ipc_response&);
bool filterButtons(); bool filterButtons();
@@ -40,7 +43,7 @@ class Workspaces : public AModule, public sigc::trackable {
std::string getIcon(const std::string&, const Json::Value&); std::string getIcon(const std::string&, const Json::Value&);
std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const; std::string getCycleWorkspace(std::vector<Json::Value>::iterator, bool prev) const;
uint16_t getWorkspaceIndex(const std::string& name) const; uint16_t getWorkspaceIndex(const std::string& name) const;
static std::string trimWorkspaceName(std::string); static std::string trimWorkspaceName(const std::string&);
bool handleScroll(GdkEventScroll* /*unused*/) override; bool handleScroll(GdkEventScroll* /*unused*/) override;
const Bar& bar_; const Bar& bar_;
@@ -49,6 +52,7 @@ class Workspaces : public AModule, public sigc::trackable {
std::vector<std::string> workspaces_order_; std::vector<std::string> workspaces_order_;
Gtk::Box box_; Gtk::Box box_;
std::string m_formatWindowSeparator; std::string m_formatWindowSeparator;
std::vector<std::regex> m_ignoreWorkspaces;
util::RegexCollection m_windowRewriteRules; util::RegexCollection m_windowRewriteRules;
util::JsonParser parser_; util::JsonParser parser_;
std::unordered_map<std::string, Gtk::Button> buttons_; std::unordered_map<std::string, Gtk::Button> buttons_;
+28 -8
View File
@@ -3,6 +3,7 @@
#include <giomm/dbusproxy.h> #include <giomm/dbusproxy.h>
#include <string> #include <string>
#include <vector>
#include "ALabel.hpp" #include "ALabel.hpp"
@@ -11,23 +12,42 @@ namespace waybar::modules {
class SystemdFailedUnits : public ALabel { class SystemdFailedUnits : public ALabel {
public: public:
SystemdFailedUnits(const std::string&, const Json::Value&); SystemdFailedUnits(const std::string&, const Json::Value&);
virtual ~SystemdFailedUnits(); virtual ~SystemdFailedUnits() = default;
auto update() -> void override; auto update() -> void override;
private: private:
bool hide_on_ok; struct FailedUnit {
std::string format_ok; std::string name;
std::string description;
std::string load_state;
std::string active_state;
std::string sub_state;
std::string scope;
};
bool update_pending; bool hide_on_ok_;
std::string system_state, user_state, overall_state; std::string format_ok_;
uint32_t nr_failed_system, nr_failed_user, nr_failed; std::string tooltip_format_;
std::string last_status; std::string tooltip_format_ok_;
Glib::RefPtr<Gio::DBus::Proxy> system_proxy, user_proxy; std::string tooltip_unit_format_;
bool update_pending_;
std::string system_state_, user_state_, overall_state_;
uint32_t nr_failed_system_, nr_failed_user_, nr_failed_;
std::string last_status_;
Glib::RefPtr<Gio::DBus::Proxy> system_props_proxy_, user_props_proxy_;
Glib::RefPtr<Gio::DBus::Proxy> system_manager_proxy_, user_manager_proxy_;
std::vector<FailedUnit> failed_units_;
void notify_cb(const Glib::ustring& sender_name, const Glib::ustring& signal_name, void notify_cb(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& arguments); const Glib::VariantContainerBase& arguments);
void RequestFailedUnits(); void RequestFailedUnits();
void RequestFailedUnitsList();
void RequestSystemState(); void RequestSystemState();
std::vector<FailedUnit> LoadFailedUnitsList(const char* kind,
Glib::RefPtr<Gio::DBus::Proxy>& proxy,
const std::string& scope);
std::string BuildTooltipFailedList() const;
void updateData(); void updateData();
}; };
+2
View File
@@ -14,6 +14,8 @@ class Temperature : public ALabel {
Temperature(const std::string&, const Json::Value&); Temperature(const std::string&, const Json::Value&);
virtual ~Temperature() = default; virtual ~Temperature() = default;
auto update() -> void override; auto update() -> void override;
void suspend() override;
void resume() override;
private: private:
float getTemperature(); float getTemperature();
+5 -19
View File
@@ -12,6 +12,8 @@
#include <unordered_map> #include <unordered_map>
#include <utility> #include <utility>
#include "util/scoped_fd.hpp"
namespace waybar::modules::wayfire { namespace waybar::modules::wayfire {
using EventHandler = std::function<void(const std::string& event)>; using EventHandler = std::function<void(const std::string& event)>;
@@ -71,25 +73,9 @@ struct State {
auto update_view(const Json::Value& view) -> void; auto update_view(const Json::Value& view) -> void;
}; };
struct Sock { using Sock = util::ScopedFd;
int fd;
Sock(int fd) : fd{fd} {} class IPC : public std::enable_shared_from_this<IPC> {
~Sock() { close(fd); }
Sock(const Sock&) = delete;
auto operator=(const Sock&) = delete;
Sock(Sock&& rhs) noexcept {
fd = rhs.fd;
rhs.fd = -1;
}
auto& operator=(Sock&& rhs) noexcept {
fd = rhs.fd;
rhs.fd = -1;
return *this;
}
};
class IPC {
static std::weak_ptr<IPC> instance; static std::weak_ptr<IPC> instance;
Json::CharReaderBuilder reader_builder; Json::CharReaderBuilder reader_builder;
Json::StreamWriterBuilder writer_builder; Json::StreamWriterBuilder writer_builder;
@@ -98,7 +84,7 @@ class IPC {
State state; State state;
std::mutex state_mutex; std::mutex state_mutex;
IPC() { start(); } IPC() = default;
static auto connect() -> Sock; static auto connect() -> Sock;
auto receive(Sock& sock) -> Json::Value; auto receive(Sock& sock) -> Json::Value;
+2
View File
@@ -33,6 +33,7 @@ class Wireplumber : public ALabel {
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self); static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
bool handleScroll(GdkEventScroll* e) override; bool handleScroll(GdkEventScroll* e) override;
std::vector<std::string> getWPIcon();
static std::list<waybar::modules::Wireplumber*> modules; static std::list<waybar::modules::Wireplumber*> modules;
@@ -54,6 +55,7 @@ class Wireplumber : public ALabel {
bool source_muted_; bool source_muted_;
double source_volume_; double source_volume_;
gchar* default_source_name_; gchar* default_source_name_;
std::string form_factor_;
}; };
} // namespace waybar::modules } // namespace waybar::modules
+29 -2
View File
@@ -18,6 +18,7 @@
#include "AModule.hpp" #include "AModule.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "ext-workspace-v1-client-protocol.h"
#include "giomm/desktopappinfo.h" #include "giomm/desktopappinfo.h"
#include "util/icon_loader.hpp" #include "util/icon_loader.hpp"
#include "util/json.hpp" #include "util/json.hpp"
@@ -33,8 +34,8 @@ class Taskbar;
class Task { class Task {
public: public:
Task(const waybar::Bar &, const Json::Value &, Taskbar *, Task(const waybar::Bar&, const Json::Value&, Taskbar*, struct zwlr_foreign_toplevel_handle_v1*,
struct zwlr_foreign_toplevel_handle_v1 *, struct wl_seat *); struct wl_seat*);
~Task(); ~Task();
public: public:
@@ -80,6 +81,7 @@ class Task {
std::string title_; std::string title_;
std::string app_id_; std::string app_id_;
uint32_t state_ = 0; uint32_t state_ = 0;
struct ext_workspace_handle_v1* workspace_ = nullptr;
int32_t drag_start_x; int32_t drag_start_x;
int32_t drag_start_y; int32_t drag_start_y;
@@ -102,6 +104,9 @@ class Task {
bool minimized() const { return state_ & MINIMIZED; } bool minimized() const { return state_ & MINIMIZED; }
bool active() const { return state_ & ACTIVE; } bool active() const { return state_ & ACTIVE; }
bool fullscreen() const { return state_ & FULLSCREEN; } bool fullscreen() const { return state_ & FULLSCREEN; }
bool visible() const { return button_visible_; }
struct ext_workspace_handle_v1* workspace() const { return workspace_; }
void set_workspace(struct ext_workspace_handle_v1* workspace) { workspace_ = workspace; }
public: public:
/* Callbacks for the wlr protocol */ /* Callbacks for the wlr protocol */
@@ -142,6 +147,12 @@ using TaskPtr = std::unique_ptr<Task>;
class Taskbar : public waybar::AModule { class Taskbar : public waybar::AModule {
public: public:
struct WorkspaceState {
Taskbar* taskbar;
struct ext_workspace_handle_v1* handle;
uint32_t state = 0;
};
Taskbar(const std::string&, const waybar::Bar&, const Json::Value&); Taskbar(const std::string&, const waybar::Bar&, const Json::Value&);
~Taskbar(); ~Taskbar();
void update(); void update();
@@ -156,22 +167,35 @@ class Taskbar : public waybar::AModule {
std::map<std::string, std::string> app_ids_replace_map_; std::map<std::string, std::string> app_ids_replace_map_;
struct zwlr_foreign_toplevel_manager_v1* manager_; struct zwlr_foreign_toplevel_manager_v1* manager_;
struct ext_workspace_manager_v1* workspace_manager_;
struct wl_seat* seat_; struct wl_seat* seat_;
std::vector<struct ext_workspace_group_handle_v1*> workspace_groups_;
std::vector<std::unique_ptr<WorkspaceState>> workspaces_;
struct ext_workspace_handle_v1* current_workspace_ = nullptr;
public: public:
/* Callbacks for global registration */ /* Callbacks for global registration */
void register_manager(struct wl_registry*, uint32_t name, uint32_t version); void register_manager(struct wl_registry*, uint32_t name, uint32_t version);
void register_workspace_manager(struct wl_registry*, uint32_t name, uint32_t version);
void register_seat(struct wl_registry*, uint32_t name, uint32_t version); void register_seat(struct wl_registry*, uint32_t name, uint32_t version);
/* Callbacks for the wlr protocol */ /* Callbacks for the wlr protocol */
void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1*); void handle_toplevel_create(struct zwlr_foreign_toplevel_handle_v1*);
void handle_finished(); void handle_finished();
void handle_workspace_group_create(struct ext_workspace_group_handle_v1*);
void handle_workspace_group_removed(struct ext_workspace_group_handle_v1*);
void handle_workspace_create(struct ext_workspace_handle_v1*);
void handle_workspace_done();
void handle_workspace_finished();
void handle_workspace_removed(struct ext_workspace_handle_v1*);
public: public:
void add_button(Gtk::Button&); void add_button(Gtk::Button&);
void move_button(Gtk::Button&, int); void move_button(Gtk::Button&, int);
void remove_button(Gtk::Button&); void remove_button(Gtk::Button&);
void remove_task(uint32_t); void remove_task(uint32_t);
void assign_current_workspace(Task&);
void update_bar_css_classes();
bool show_output(struct wl_output*) const; bool show_output(struct wl_output*) const;
bool all_outputs() const; bool all_outputs() const;
@@ -179,6 +203,9 @@ class Taskbar : public waybar::AModule {
const IconLoader& icon_loader() const; const IconLoader& icon_loader() const;
const std::unordered_set<std::string>& ignore_list() const; const std::unordered_set<std::string>& ignore_list() const;
const std::map<std::string, std::string>& app_ids_replace_map() const; const std::map<std::string, std::string>& app_ids_replace_map() const;
private:
void set_bar_css_class(const std::string&, bool);
}; };
} /* namespace waybar::modules::wlr */ } /* namespace waybar::modules::wlr */
+20 -5
View File
@@ -3,6 +3,7 @@
#include <glibmm/dispatcher.h> #include <glibmm/dispatcher.h>
#include <sigc++/signal.h> #include <sigc++/signal.h>
#include <cstddef>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
@@ -11,11 +12,6 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#ifdef __OpenBSD__
#define SIGRTMIN SIGUSR1 - 1
#define SIGRTMAX SIGUSR1 + 1
#endif
namespace waybar { namespace waybar {
/** /**
@@ -27,6 +23,12 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
public: public:
SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); } SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); }
void set_max_queued_events(std::size_t max_queued_events) {
std::unique_lock lock(mutex_);
max_queued_events_ = max_queued_events;
trim_queue_locked();
}
template <typename... EmitArgs> template <typename... EmitArgs>
void emit(EmitArgs&&... args) { void emit(EmitArgs&&... args) {
if (main_tid_ == std::this_thread::get_id()) { if (main_tid_ == std::this_thread::get_id()) {
@@ -41,6 +43,9 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
} else { } else {
{ {
std::unique_lock lock(mutex_); std::unique_lock lock(mutex_);
if (max_queued_events_ != 0 && queue_.size() >= max_queued_events_) {
queue_.pop();
}
queue_.emplace(std::forward<EmitArgs>(args)...); queue_.emplace(std::forward<EmitArgs>(args)...);
} }
dp_.emit(); dp_.emit();
@@ -60,6 +65,15 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
using signal_t::emit_reverse; using signal_t::emit_reverse;
using signal_t::make_slot; using signal_t::make_slot;
void trim_queue_locked() {
if (max_queued_events_ == 0) {
return;
}
while (queue_.size() > max_queued_events_) {
queue_.pop();
}
}
void handle_event() { void handle_event() {
for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) { for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) {
auto args = queue_.front(); auto args = queue_.front();
@@ -72,6 +86,7 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
Glib::Dispatcher dp_; Glib::Dispatcher dp_;
std::mutex mutex_; std::mutex mutex_;
std::queue<arg_tuple_t> queue_; std::queue<arg_tuple_t> queue_;
std::size_t max_queued_events_ = 4096;
const std::thread::id main_tid_ = std::this_thread::get_id(); const std::thread::id main_tid_ = std::this_thread::get_id();
// cache functor for signal emission to avoid recreating it on each event // cache functor for signal emission to avoid recreating it on each event
const slot_t cached_fn_ = make_slot(); const slot_t cached_fn_ = make_slot();
+17 -2
View File
@@ -14,6 +14,11 @@
namespace waybar::util { namespace waybar::util {
enum class PulseaudioTarget {
Sink,
Source,
};
class AudioBackend { class AudioBackend {
private: private:
static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*); static void subscribeCb(pa_context*, pa_subscription_event_type_t, uint32_t, void*);
@@ -22,12 +27,14 @@ class AudioBackend {
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data); static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
static void serverInfoCb(pa_context*, const pa_server_info*, void*); static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*); static void volumeModifyCb(pa_context*, int, void*);
static void sourceVolumeModifyCb(pa_context*, int, void*);
void connectContext(); void connectContext();
pa_threaded_mainloop* mainloop_; pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_; pa_mainloop_api* mainloop_api_;
pa_context* context_; pa_context* context_;
pa_cvolume pa_volume_; pa_cvolume pa_volume_;
pa_cvolume pa_source_volume_;
// SINK // SINK
uint32_t sink_idx_{0}; uint32_t sink_idx_{0};
@@ -50,6 +57,7 @@ class AudioBackend {
std::string default_source_name_; std::string default_source_name_;
std::vector<std::string> ignored_sinks_; std::vector<std::string> ignored_sinks_;
std::map<std::string, std::string> sink_mapping_;
std::function<void()> on_updated_cb_ = NOOP; std::function<void()> on_updated_cb_ = NOOP;
@@ -67,10 +75,13 @@ class AudioBackend {
AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag); AudioBackend(std::function<void()> on_updated_cb, private_constructor_tag tag);
~AudioBackend(); ~AudioBackend();
void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100); void changeVolume(uint16_t volume, uint16_t min_volume = 0, uint16_t max_volume = 100,
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100); PulseaudioTarget target = PulseaudioTarget::Sink);
void changeVolume(ChangeType change_type, double step = 1, uint16_t max_volume = 100,
PulseaudioTarget target = PulseaudioTarget::Sink);
void setIgnoredSinks(const Json::Value& config); void setIgnoredSinks(const Json::Value& config);
void setSinkMapping(const Json::Value& config);
std::string getSinkPortName() const { return port_name_; } std::string getSinkPortName() const { return port_name_; }
std::string getFormFactor() const { return form_factor_; } std::string getFormFactor() const { return form_factor_; }
@@ -92,6 +103,10 @@ class AudioBackend {
void toggleSourceMute(); void toggleSourceMute();
void toggleSourceMute(bool); void toggleSourceMute(bool);
uint16_t getVolume(PulseaudioTarget) const;
bool getMuted(PulseaudioTarget) const;
void unmute(PulseaudioTarget);
bool isBluetooth(); bool isBluetooth();
}; };
+16 -4
View File
@@ -20,6 +20,8 @@ extern std::list<pid_t> reap;
namespace waybar::util::command { namespace waybar::util::command {
constexpr int kExecFailureExitCode = 127;
struct res { struct res {
int exit_code; int exit_code;
std::string out; std::string out;
@@ -59,6 +61,7 @@ inline int close(FILE* fp, pid_t pid) {
spdlog::debug("Cmd continued"); spdlog::debug("Cmd continued");
} else if (ret == -1) { } else if (ret == -1) {
spdlog::debug("waitpid failed: {}", strerror(errno)); spdlog::debug("waitpid failed: {}", strerror(errno));
break;
} else { } else {
break; break;
} }
@@ -109,11 +112,13 @@ inline FILE* open(const std::string& cmd, int& pid, const std::string& output_na
::close(fd[0]); ::close(fd[0]);
dup2(fd[1], 1); dup2(fd[1], 1);
setpgid(child_pid, child_pid); setpgid(child_pid, child_pid);
if (output_name != "") { if (!output_name.empty()) {
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1); setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
} }
execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); execlp("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0); const int saved_errno = errno;
spdlog::error("execlp(/bin/sh) failed in open: {}", strerror(saved_errno));
_exit(kExecFailureExitCode);
} else { } else {
::close(fd[1]); ::close(fd[1]);
} }
@@ -138,7 +143,7 @@ inline struct res execNoRead(const std::string& cmd) {
return {WEXITSTATUS(stat), ""}; return {WEXITSTATUS(stat), ""};
} }
inline int32_t forkExec(const std::string& cmd) { inline int32_t forkExec(const std::string& cmd, const std::string& output_name) {
if (cmd == "") return -1; if (cmd == "") return -1;
pid_t pid = fork(); pid_t pid = fork();
@@ -157,8 +162,13 @@ inline int32_t forkExec(const std::string& cmd) {
err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr); err = pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);
if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err)); if (err != 0) spdlog::error("pthread_sigmask in forkExec failed: {}", strerror(err));
setpgid(pid, pid); setpgid(pid, pid);
if (!output_name.empty()) {
setenv("WAYBAR_OUTPUT_NAME", output_name.c_str(), 1);
}
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0); const int saved_errno = errno;
spdlog::error("execl(/bin/sh) failed in forkExec: {}", strerror(saved_errno));
_exit(kExecFailureExitCode);
} else { } else {
reap_mtx.lock(); reap_mtx.lock();
reap.push_back(pid); reap.push_back(pid);
@@ -169,4 +179,6 @@ inline int32_t forkExec(const std::string& cmd) {
return pid; return pid;
} }
inline int32_t forkExec(const std::string& cmd) { return forkExec(cmd, ""); }
} // namespace waybar::util::command } // namespace waybar::util::command
+4 -2
View File
@@ -14,12 +14,14 @@ struct pollfd;
namespace waybar { namespace waybar {
class CssReloadHelper { class CssReloadHelper {
public: public:
CssReloadHelper(std::string cssFile, std::function<void()> callback); CssReloadHelper(std::string cssFile, std::function<void(const std::string&)> callback);
virtual ~CssReloadHelper() = default; virtual ~CssReloadHelper() = default;
virtual void monitorChanges(); virtual void monitorChanges();
virtual void changeCssFile(const std::string& newCssFile);
protected: protected:
std::vector<std::string> parseImports(const std::string& cssFile); std::vector<std::string> parseImports(const std::string& cssFile);
@@ -42,7 +44,7 @@ class CssReloadHelper {
private: private:
std::string m_cssFile; std::string m_cssFile;
std::function<void()> m_callback; std::function<void(const std::string&)> m_callback;
std::vector<std::tuple<Glib::RefPtr<Gio::FileMonitor>>> m_fileMonitors; std::vector<std::tuple<Glib::RefPtr<Gio::FileMonitor>>> m_fileMonitors;
}; };
+5 -3
View File
@@ -5,12 +5,13 @@
class pow_format { class pow_format {
public: public:
pow_format(long long val, std::string&& unit, bool binary = false) pow_format(long long val, std::string&& unit, bool binary = false, int min_pow_for_decimal = 0)
: val_(val), unit_(unit), binary_(binary) {}; : val_(val), unit_(unit), binary_(binary), min_pow_for_decimal_(min_pow_for_decimal) {};
long long val_; long long val_;
std::string unit_; std::string unit_;
bool binary_; bool binary_;
int min_pow_for_decimal_;
}; };
namespace fmt { namespace fmt {
@@ -74,7 +75,8 @@ struct formatter<pow_format> {
break; break;
case 0: case 0:
default: default:
format = "{coefficient:.1f}{prefix}{unit}"; format = pow < s.min_pow_for_decimal_ ? "{coefficient:.0f}{prefix}{unit}"
: "{coefficient:.1f}{prefix}{unit}";
break; break;
} }
return fmt::format_to( return fmt::format_to(
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <string>
/**
* Result of transforming 8-bit hex codes to rgba().
*/
struct TransformResult {
std::string css;
bool was_transformed;
};
/**
* Reads a CSS file, searches for 8-bit hex codes (#RRGGBBAA),
* and transforms them into GTK-compatible rgba() syntax.
*/
TransformResult transform_8bit_to_hex(const std::string& file_path);
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <json/value.h>
namespace waybar::util {
bool valid_host(const Json::Value& config);
} // namespace waybar::util
+12 -5
View File
@@ -7,6 +7,7 @@
#include <codecvt> #include <codecvt>
#include <iostream> #include <iostream>
#include <locale> #include <locale>
#include <memory>
#include <regex> #include <regex>
#if (FMT_VERSION >= 90000) #if (FMT_VERSION >= 90000)
@@ -26,19 +27,25 @@ class JsonParser {
Json::Value root; Json::Value root;
// replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences // replace all occurrences of "\x" with "\u00", because JSON doesn't allow "\x" escape sequences
std::string modifiedJsonStr = replaceHexadecimalEscape(jsonStr); std::string modifiedJsonStr;
const std::string* json = &jsonStr;
if (jsonStr.find("\\x") != std::string::npos) {
modifiedJsonStr = replaceHexadecimalEscape(jsonStr);
json = &modifiedJsonStr;
}
std::istringstream jsonStream(modifiedJsonStr);
std::string errs; std::string errs;
if (!Json::parseFromStream(m_readerBuilder, jsonStream, &root, &errs)) { // Use local CharReaderBuilder for thread safety - the IPC singleton's
// parser can be called concurrently from multiple module threads
Json::CharReaderBuilder readerBuilder;
auto reader = std::unique_ptr<Json::CharReader>(readerBuilder.newCharReader());
if (!reader->parse(json->data(), json->data() + json->size(), &root, &errs)) {
throw std::runtime_error("Error parsing JSON: " + errs); throw std::runtime_error("Error parsing JSON: " + errs);
} }
return root; return root;
} }
private: private:
Json::CharReaderBuilder m_readerBuilder;
static std::string replaceHexadecimalEscape(const std::string& str) { static std::string replaceHexadecimalEscape(const std::string& str) {
static std::regex re("\\\\x"); static std::regex re("\\\\x");
return std::regex_replace(str, re, "\\u00"); return std::regex_replace(str, re, "\\u00");
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <unistd.h>
namespace waybar::util {
class ScopedFd {
public:
explicit ScopedFd(int fd = -1) : fd_(fd) {}
~ScopedFd() {
if (fd_ != -1) {
close(fd_);
}
}
// ScopedFd is non-copyable
ScopedFd(const ScopedFd&) = delete;
ScopedFd& operator=(const ScopedFd&) = delete;
// ScopedFd is moveable
ScopedFd(ScopedFd&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
ScopedFd& operator=(ScopedFd&& other) noexcept {
if (this != &other) {
if (fd_ != -1) {
close(fd_);
}
fd_ = other.fd_;
other.fd_ = -1;
}
return *this;
}
int get() const { return fd_; }
operator int() const { return fd_; }
void reset(int fd = -1) {
if (fd_ != -1) {
close(fd_);
}
fd_ = fd;
}
int release() {
int fd = fd_;
fd_ = -1;
return fd;
}
private:
int fd_;
};
} // namespace waybar::util
+54 -14
View File
@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <atomic>
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include <ctime> #include <ctime>
@@ -31,8 +32,8 @@ class SleeperThread {
SleeperThread(std::function<void()> func) SleeperThread(std::function<void()> func)
: thread_{[this, func] { : thread_{[this, func] {
while (do_run_) { while (do_run_.load(std::memory_order_relaxed)) {
signal_ = false; signal_.store(false, std::memory_order_relaxed);
func(); func();
} }
}} { }} {
@@ -42,9 +43,18 @@ class SleeperThread {
} }
SleeperThread& operator=(std::function<void()> func) { SleeperThread& operator=(std::function<void()> func) {
if (thread_.joinable()) {
stop();
thread_.join();
}
{
std::lock_guard<std::mutex> lck(mutex_);
do_run_.store(true, std::memory_order_relaxed);
signal_.store(false, std::memory_order_relaxed);
}
thread_ = std::thread([this, func] { thread_ = std::thread([this, func] {
while (do_run_) { while (do_run_.load(std::memory_order_relaxed)) {
signal_ = false; signal_.store(false, std::memory_order_relaxed);
func(); func();
} }
}); });
@@ -56,24 +66,34 @@ class SleeperThread {
return *this; return *this;
} }
bool isRunning() const { return do_run_; } bool isRunning() const { return do_run_.load(std::memory_order_relaxed); }
auto sleep() { auto sleep() {
std::unique_lock lk(mutex_); std::unique_lock lk(mutex_);
CancellationGuard cancel_lock; CancellationGuard cancel_lock;
return condvar_.wait(lk, [this] { return signal_ || !do_run_; }); return condvar_.wait(lk, [this] {
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
});
} }
auto sleep_for(std::chrono::system_clock::duration dur) { auto sleep_for(std::chrono::system_clock::duration dur) {
std::unique_lock lk(mutex_); std::unique_lock lk(mutex_);
CancellationGuard cancel_lock; CancellationGuard cancel_lock;
condvar_.wait(lk, [this] {
return !is_paused_ || signal_.load(std::memory_order_relaxed) ||
!do_run_.load(std::memory_order_relaxed);
});
constexpr auto max_time_point = std::chrono::steady_clock::time_point::max(); constexpr auto max_time_point = std::chrono::steady_clock::time_point::max();
auto wait_end = max_time_point; auto wait_end = max_time_point;
auto now = std::chrono::steady_clock::now(); auto now = std::chrono::steady_clock::now();
if (now < max_time_point - dur) { if (now < max_time_point - dur) {
wait_end = now + dur; wait_end = now + dur;
} }
return condvar_.wait_until(lk, wait_end, [this] { return signal_ || !do_run_; }); return condvar_.wait_until(lk, wait_end, [this] {
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
});
} }
auto sleep_until( auto sleep_until(
@@ -81,22 +101,30 @@ class SleeperThread {
time_point) { time_point) {
std::unique_lock lk(mutex_); std::unique_lock lk(mutex_);
CancellationGuard cancel_lock; CancellationGuard cancel_lock;
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
condvar_.wait(lk, [this] {
return !is_paused_ || signal_.load(std::memory_order_relaxed) ||
!do_run_.load(std::memory_order_relaxed);
});
return condvar_.wait_until(lk, time_point, [this] {
return signal_.load(std::memory_order_relaxed) || !do_run_.load(std::memory_order_relaxed);
});
} }
void wake_up() { void wake_up() {
{ {
std::lock_guard<std::mutex> lck(mutex_); std::lock_guard<std::mutex> lck(mutex_);
signal_ = true; signal_.store(true, std::memory_order_relaxed);
} }
condvar_.notify_all(); condvar_.notify_all();
} }
auto stop() { void stop() {
{ {
std::lock_guard<std::mutex> lck(mutex_); std::lock_guard<std::mutex> lck(mutex_);
signal_ = true; signal_.store(true, std::memory_order_relaxed);
do_run_ = false; do_run_.store(false, std::memory_order_relaxed);
} }
condvar_.notify_all(); condvar_.notify_all();
auto handle = thread_.native_handle(); auto handle = thread_.native_handle();
@@ -106,6 +134,17 @@ class SleeperThread {
} }
} }
void pause() {
std::lock_guard<std::mutex> lock(mutex_);
is_paused_ = true;
}
void resume() {
std::lock_guard<std::mutex> lock(mutex_);
is_paused_ = false;
condvar_.notify_all();
}
~SleeperThread() { ~SleeperThread() {
connection_.disconnect(); connection_.disconnect();
stop(); stop();
@@ -118,9 +157,10 @@ class SleeperThread {
std::thread thread_; std::thread thread_;
std::condition_variable condvar_; std::condition_variable condvar_;
std::mutex mutex_; std::mutex mutex_;
bool do_run_ = true; std::atomic<bool> do_run_ = true;
bool signal_ = false; std::atomic<bool> signal_ = false;
sigc::connection connection_; sigc::connection connection_;
bool is_paused_{false};
}; };
} // namespace waybar::util } // namespace waybar::util
+21
View File
@@ -0,0 +1,21 @@
#pragma once
#include <libudev.h>
namespace waybar::util {
struct UdevDeleter {
void operator()(udev* ptr) const { udev_unref(ptr); }
};
struct UdevDeviceDeleter {
void operator()(udev_device* ptr) const { udev_device_unref(ptr); }
};
struct UdevEnumerateDeleter {
void operator()(udev_enumerate* ptr) const { udev_enumerate_unref(ptr); }
};
struct UdevMonitorDeleter {
void operator()(udev_monitor* ptr) const { udev_monitor_unref(ptr); }
};
} // namespace waybar::util
+7
View File
@@ -0,0 +1,7 @@
#pragma once
#include <string>
namespace waybar::util {
size_t utf8_width(const std::string& str);
void utf8_truncate(std::string& s, const std::string& ellipsis, size_t max_len);
} // namespace waybar::util
+14 -1
View File
@@ -27,6 +27,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
default: false ++ default: false ++
Option to use the battery design capacity instead of its current maximal capacity. Option to use the battery design capacity instead of its current maximal capacity.
*full-at-plugged*: ++
typeof: bool ++
default: false ++
When enabled, a battery that is *Full* while the adapter is online is reported with the *Plugged* status instead of *Full* (so you can style/format it separately). Disabled by default to preserve the existing *Full* behaviour.
*interval*: ++ *interval*: ++
typeof: integer ++ typeof: integer ++
default: 60 ++ default: 60 ++
@@ -91,6 +96,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y
typeof: string ++ typeof: string ++
Command to execute when scrolling up on the module. Command to execute when scrolling up on the module.
*weighted-average*: ++
typeof: bool ++
default: true ++
Option to combine multiple batteries with different capacities.
*on-scroll-down*: ++ *on-scroll-down*: ++
typeof: string ++ typeof: string ++
Command to execute when scrolling down on the module. Command to execute when scrolling down on the module.
@@ -177,6 +187,7 @@ Every entry in the *events* object consists of a *<event-name>* (typeof: *string
- *on-<status>-<state>* - *on-<status>-<state>*
- *on-<status>-<capacity>* - *on-<status>-<capacity>*
- *on-<status>*
Where: Where:
@@ -198,7 +209,9 @@ Where:
"events": { "events": {
"on-discharging-warning": "notify-send -u normal 'Low Battery'", "on-discharging-warning": "notify-send -u normal 'Low Battery'",
"on-discharging-critical": "notify-send -u critical 'Very Low Battery'", "on-discharging-critical": "notify-send -u critical 'Very Low Battery'",
"on-charging-100": "notify-send -u normal 'Battery Full!'" "on-charging-100": "notify-send -u normal 'Battery Full!'",
"on-discharging": "notify-send -u normal 'Power Switch' Discharging",
"on-charging": "notify-send -u normal 'Power Switch' Charging'"
}, },
"format": "{capacity}% {icon}", "format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""], "format-icons": ["", "", "", "", ""],
+14
View File
@@ -178,6 +178,9 @@ At the time of writing, the experimental features of BlueZ need to be turned on,
*{device_battery_percentage}*: Battery percentage of the displayed device if available. Use only in the config options defined below. *{device_battery_percentage}*: Battery percentage of the displayed device if available. Use only in the config options defined below.
*{device_battery_percentage_peripheral}*: Battery percentage of the peripheral half of a split keyboard (e.g., ZMK keyboards with separate central and peripheral batteries). ++
This is read from GATT Battery Service characteristics that have a User Description descriptor. Use only in the config options defined below.
## CONFIGURATION ## CONFIGURATION
*format-connected-battery*: ++ *format-connected-battery*: ++
@@ -220,6 +223,17 @@ At the time of writing, the experimental features of BlueZ need to be turned on,
} }
``` ```
Split keyboard with separate central/peripheral batteries (e.g., ZMK):
```
"bluetooth": {
"format-device-preference": [ "Keyball44" ],
"format": "",
"format-connected-battery": " {device_battery_percentage}%|{device_battery_percentage_peripheral}%",
"tooltip-format-connected": "{device_alias}\\nCentral: {device_battery_percentage}%\\nPeripheral: {device_battery_percentage_peripheral}%"
}
```
# STYLE # STYLE
- *#bluetooth* - *#bluetooth*
+508 -7
View File
@@ -8,6 +8,8 @@ waybar - cava module
*cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava. *cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava.
Module supports two different frontends starting from the 0.15.0 release. The frontend that
will be used is managed by the method parameter in the [output] section of the cava configuration file.
# FILES # FILES
@@ -32,6 +34,10 @@ libcava lives in:
:[ string :[ string
:[ :[
:< Path where cava configuration file is placed to :< Path where cava configuration file is placed to
|[ *method* \[output\]
:[ string
:[
:< Manages which frontend Waybar cava module should use. Values: raw, sdl_glsl
|[ *framerate* |[ *framerate*
:[ integer :[ integer
:[ 30 :[ 30
@@ -43,7 +49,7 @@ libcava lives in:
|[ *sensitivity* |[ *sensitivity*
:[ integer :[ integer
:[ 100 :[ 100
:[ Manual sensitivity in %. It's recommended to be omitted when *autosens* = 1 :[ Manual sensitivity in %. If autosens is enabled, this will only be the initial value. 200 means double height. Accepts only non-negative values
|[ *bars* |[ *bars*
:[ integer :[ integer
:[ 12 :[ 12
@@ -68,7 +74,7 @@ libcava lives in:
:[ string :[ string
:[ :[
:[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false) :[ Widget's text after sleep_timer elapsed (hide_on_silence has to be false)
|[ *method* |[ *method* \[input\]
:[ string :[ string
:[ pulse :[ pulse
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem :[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
@@ -105,9 +111,9 @@ libcava lives in:
:[ false :[ false
:[ Disables or enables the so-called "Monstercat smoothing" with or without "waves" :[ Disables or enables the so-called "Monstercat smoothing" with or without "waves"
|[ *noise_reduction* |[ *noise_reduction*
:[ double :[ integer
:[ 0.77 :[ 77
:[ Range between 0 - 1. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 1 - will be very slow and smooth, 0 - will be fast but noisy :[ Range between 0 - 100. The raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth. 100 will be very slow and smooth, 0 will be fast but noisy
|[ *input_delay* |[ *input_delay*
:[ integer :[ integer
:[ 2 :[ 2
@@ -119,11 +125,11 @@ libcava lives in:
|[ *data_format* |[ *data_format*
:[ string :[ string
:[ asci :[ asci
:[ It's impossible to set it. Waybar sets it to = asci for internal needs :[ Raw data format. Can be 'binary' or 'ascii'
|[ *raw_target* |[ *raw_target*
:[ string :[ string
:[ /dev/stdout :[ /dev/stdout
:[ It's impossible to set it. Waybar sets it to = /dev/stdout for internal needs :[ Raw output target. A fifo will be created if target does not exist
|[ *menu* |[ *menu*
:[ string :[ string
:[ :[
@@ -136,6 +142,50 @@ libcava lives in:
:[ array :[ array
:[ :[
:[ The actions corresponding to the buttons of the menu. :[ The actions corresponding to the buttons of the menu.
|[ *bar_spacing*
:[ integer
:[
:[ Bars' space between bars in number of characters
|[ *bar_width*
:[ integer
:[
:[ Bars' width between bars in number of characters
|[ *bar_height*
:[ integer
:[
:[ Useless. bar_height is only used for output in "noritake" format
|[ *background*
:[ string
:[
:[ GLSL actual. Support hex code colors only. Must be within ''
|[ *foreground*
:[ string
:[
:[ GLSL actual. Support hex code colors only. Must be within ''
|[ *gradient*
:[ integer
:[ 0
:[ GLSL actual. Gradient mode(0/1 - on/off)
|[ *gradient_count*
:[ integer
:[ 0
:[ GLSL actual. The count of colors for the gradient
|[ *gradient_color_N*
:[ string
:[
:[ GLSL actual. N - the number of the gradient color between 1 and 8. Only hex defined colors are supported. Must be within ''
|[ *sdl_width*
:[ integer
:[
:[ GLSL actual. Manages the width of the waybar cava GLSL frontend module
|[ *sdl_height*
:[ integer
:[
:[ GLSL actual. Manages the height of the waybar cava GLSL frontend module
|[ *continuous_rendering*
:[ integer
:[ 0
:[ GLSL actual. Keep rendering even if no audio. Recommended to set to 1
Configuration can be provided as: Configuration can be provided as:
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped - The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
@@ -153,6 +203,7 @@ Configuration can be provided as:
- iniparser - iniparser
- fftw3 - fftw3
- epoxy (GLSL frontend only)
# SOLVING ISSUES # SOLVING ISSUES
@@ -205,3 +256,453 @@ In case when cava releases new version and you're wanna get it, it should be rai
- *#cava* - *#cava*
- *#cava.silent* Applied after no sound has been detected for sleep_timer seconds - *#cava.silent* Applied after no sound has been detected for sleep_timer seconds
- *#cava.updated* Applied when a new frame is shown - *#cava.updated* Applied when a new frame is shown
# FRONTENDS
## RAW
The cava raw frontend uses ASCII characters to visualize incoming audio data. Each ASCII symbol position corresponds to the value of the audio power pulse.
Under the hood:
```
. Incoming audio power pulse list is : 12684
. Configured array of ASCII codes is: ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ]. See `format-icons` https://github.com/Alexays/Waybar/wiki/Module:-Cava#example
```
As a result cava frontend will give ▁▂▆█▄
Examples:
waybar config
```
"cava": {
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_raw.conf",
"input_delay": 2,
"format-icons" : ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ],
"actions": {
"on-click-right": "mode"
}
},
```
waybar_raw.conf
```
## Configuration file for CAVA.
# Remove the ; to change parameters.
[general]
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
# Accepts only non-negative values.
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
# new as of 0.6.0 autosens of low values (dynamic range)
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
# Manual sensitivity in %. If autosens is enabled, this will only be the initial value.
# 200 means double height. Accepts only non-negative values.
# The number of bars (0-512). 0 sets it to auto (fill up console).
# Bars' width and space between bars in number of characters.
bars = 12
# bar_height is only used for output in "noritake" format
# For SDL width and space between bars is in pixels, defaults are:
# sdl_glsl have these default values, they are only used to calculate max number of bars.
# Lower and higher cutoff frequencies for lowest and highest bars
# the bandwidth of the visualizer.
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
# Cava will automatically increase the higher cutoff if a too low band is specified.
# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and
# only check for input once per second. Cava will wake up once input is detected. 0 = disable.
sleep_timer = 5
[input]
# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with.
# On Mac it defaults to 'portaudio' or 'fifo'
# On windows this is automatic and no input settings are needed.
#
# All input methods uses the same config variable 'source'
# to define where it should get the audio.
#
# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
#
# For pipewire 'source' will be the object name or object.serial of the device to capture from.
# Both input and output devices are supported.
#
# For alsa 'source' will be the capture device.
# For fifo 'source' will be the path to fifo-file.
# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
#
# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
# README.md contains further information on how to setup CAVA for sndio.
#
# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device.
# README.md contains further information on how to setup CAVA for OSS on FreeBSD.
#
# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'.
# README.md contains further information on how to setup CAVA for JACK.
#
# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods:
# sample_rate: fifo, pipewire, sndio, oss
# sample_bits: fifo, pipewire, sndio, oss
# channels: sndio, oss, jack
# autoconnect: jack
# Other methods ignore these settings.
#
# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported
# by the chosen audio device, the device will use other supported values instead.
# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it
# will use 44100, 16 and 1.
#
[output]
# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl'
# or 'sdl_glsl'.
# 'noncurses' (default) uses a buffer and cursor movements to only print
# changes from frame to frame in the terminal. Uses less resources and is less
# prone to tearing (vsync issues) than 'ncurses'.
#
# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data
# stream of the bar heights that can be used to send to other applications.
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
#
# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display
# in graphic mode. It only support the 3000 series graphical VFDs for now.
#
# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context.
# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or
# use one of the predefined ones.
method = raw
# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or
# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl
# and ncruses output. 'horizontal' (bars go up and down from center) is only supported
# on noncurses output.
# Note: many fonts have weird or missing glyphs for characters used in orientations
# other than 'bottom', which can make output not look right.
# Visual channels. Can be 'stereo' or 'mono'.
# 'stereo' mirrors both channels with low frequencies in center.
# 'mono' outputs left to right lowest to highest frequencies.
# 'mono_option' set mono to either take input from 'left', 'right' or 'average'.
# set 'reverse' to 1 to display frequencies the other way around.
# Raw output target. A fifo will be created if target does not exist.
raw_target = /dev/stdout
# Raw data format. Can be 'binary' or 'ascii'.
data_format = ascii
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
bar_delimiter = 0
# sdl window size and position. -1,-1 is centered.
# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none'
# 'frequency' displays the lower cut off frequency of the bar above.
# Only supported on ncurses and noncurses output.
# enable synchronized sync. 1 = on, 0 = off
# removes flickering in alacritty terminal emulator.
# defaults to off since the behaviour in other terminal emulators is unknown
# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders
; for glsl output mode, keep rendering even if no audio
# disable console blank (screen saver) in tty
# (Not supported on FreeBSD)
# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off
# show waveform instead of frequency spectrum, 1 = on, 0 = off
[color]
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires
# a terminal that can change color definitions such as Gnome-terminal or rxvt.
# default is to keep current terminal color
# SDL and sdl_glsl only support hex code colors, these are the default:
# Gradient mode, only hex defined colors are supported,
# background must also be defined in hex or remain commented out. 1 = on, 0 = off.
# You can define as many as 8 different colors. They range from bottom to top of screen
[smoothing]
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
# Noise reduction, int 0 - 100. default 77
# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth
# 100 will be very slow and smooth, 0 will be fast but noisy.
[eq]
# This one is tricky. You can have as much keys as you want.
# Remember to uncomment more than one key! More keys = more precision.
# Look at readme.md on github for further explanations and examples.
```
## GLSL
The Cava GLSL frontend delegates the visualization of incoming audio data to the GPU via OpenGL.
There are some mandatory dependencies that need to be satisfied in order for Cava GLSL to be built and function properly:
. epoxy library must be installed on the system
. Vertex and fragment shaders from the original project must be used. They should be downloaded, and the file paths must be configured correctly in the Waybar Cava configuration:
1. cava shaders [cava shaders](https://github.com/karlstav/cava/tree/master/output/shaders)
2. libcava shaders [libcava shaders](https://github.com/LukashonakV/cava/tree/master/output/shaders)
. It is highly recommended to have a separate cava configuration for the Waybar Cava GLSL module and to use this as the cava_config in the Waybar configuration.
. It is common for cava configurations to be placed in the XDG_CONFIG_HOME directory, including shaders as well. Consider keeping them in the $XDG_CONFIG_HOME/cava/shaders folder.
Key configuration options:
. bars. The more values the parameter has, the more interesting the visualization becomes.
. method in output section must be set to sdl_glsl
. sdl_width and sdl_height manage the size of the module. Adjust them according to your needs.
. Shaders for sdl_glsl, located in $HOME/.config/cava/shaders. Example: "vertex_shader" = "pass_through.vert" "fragment_shader" = "spectrogram.frag"
. Set continuous_rendering to 1 to enable smooth rendering; set it to 0 otherwise. It is recommended to keep it set to 1.
. background, foreground, and gradient_color_N (where N is a number between 1 and 8) must be defined using hex code
Example:
waybar config
```
"cava": {
"cava_config": "$XDG_CONFIG_HOME/cava/waybar_cava#3.conf",
"input_delay": 2,
"actions": {
"on-click-right": "mode"
}
},
```
waybar_raw.conf
```
## Configuration file for CAVA.
# Remove the ; to change parameters.
[general]
# Smoothing mode. Can be 'normal', 'scientific' or 'waves'. DEPRECATED as of 0.6.0
# Accepts only non-negative values.
# 'autosens' will attempt to decrease sensitivity if the bars peak. 1 = on, 0 = off
# new as of 0.6.0 autosens of low values (dynamic range)
# 'overshoot' allows bars to overshoot (in % of terminal height) without initiating autosens. DEPRECATED as of 0.6.0
# Manual sensitivity in %. If autosens is enabled, this will only be the initial value.
# 200 means double height. Accepts only non-negative values.
# The number of bars (0-512). 0 sets it to auto (fill up console).
# Bars' width and space between bars in number of characters.
bars = 50
# bar_height is only used for output in "noritake" format
# For SDL width and space between bars is in pixels, defaults are:
# sdl_glsl have these default values, they are only used to calculate max number of bars.
# Lower and higher cutoff frequencies for lowest and highest bars
# the bandwidth of the visualizer.
# Note: there is a minimum total bandwidth of 43Mhz x number of bars.
# Cava will automatically increase the higher cutoff if a too low band is specified.
# Seconds with no input before cava goes to sleep mode. Cava will not perform FFT or drawing and
# only check for input once per second. Cava will wake up once input is detected. 0 = disable.
sleep_timer = 5
[input]
# Audio capturing method. Possible methods are: 'fifo', 'portaudio', 'pipewire', 'alsa', 'pulse', 'sndio', 'oss', 'jack' or 'shmem'
# Defaults to 'oss', 'pipewire', 'sndio', 'jack', 'pulse', 'alsa', 'portaudio' or 'fifo', in that order, dependent on what support cava was built with.
# On Mac it defaults to 'portaudio' or 'fifo'
# On windows this is automatic and no input settings are needed.
#
# All input methods uses the same config variable 'source'
# to define where it should get the audio.
#
# For pulseaudio and pipewire 'source' will be the source. Default: 'auto', which uses the monitor source of the default sink
# (all pulseaudio sinks(outputs) have 'monitor' sources(inputs) associated with them).
#
# For pipewire 'source' will be the object name or object.serial of the device to capture from.
# Both input and output devices are supported.
#
# For alsa 'source' will be the capture device.
# For fifo 'source' will be the path to fifo-file.
# For shmem 'source' will be /squeezelite-AA:BB:CC:DD:EE:FF where 'AA:BB:CC:DD:EE:FF' will be squeezelite's MAC address
#
# For sndio 'source' will be a raw recording audio descriptor or a monitoring sub-device, e.g. 'rsnd/2' or 'snd/1'. Default: 'default'.
# README.md contains further information on how to setup CAVA for sndio.
#
# For oss 'source' will be the path to a audio device, e.g. '/dev/dsp2'. Default: '/dev/dsp', i.e. the default audio device.
# README.md contains further information on how to setup CAVA for OSS on FreeBSD.
#
# For jack 'source' will be the name of the JACK server to connect to, e.g. 'foobar'. Default: 'default'.
# README.md contains further information on how to setup CAVA for JACK.
#
# The options 'sample_rate', 'sample_bits', 'channels' and 'autoconnect' can be configured for some input methods:
# sample_rate: fifo, pipewire, sndio, oss
# sample_bits: fifo, pipewire, sndio, oss
# channels: sndio, oss, jack
# autoconnect: jack
# Other methods ignore these settings.
#
# For 'sndio' and 'oss' they are only preferred values, i.e. if the values are not supported
# by the chosen audio device, the device will use other supported values instead.
# Example: 48000, 32 and 2, but the device only supports 44100, 16 and 1, then it
# will use 44100, 16 and 1.
#
[output]
# Output method. Can be 'ncurses', 'noncurses', 'raw', 'noritake', 'sdl'
# or 'sdl_glsl'.
# 'noncurses' (default) uses a buffer and cursor movements to only print
# changes from frame to frame in the terminal. Uses less resources and is less
# prone to tearing (vsync issues) than 'ncurses'.
#
# 'raw' is an 8 or 16 bit (configurable via the 'bit_format' option) data
# stream of the bar heights that can be used to send to other applications.
# 'raw' defaults to 200 bars, which can be adjusted in the 'bars' option above.
#
# 'noritake' outputs a bitmap in the format expected by a Noritake VFD display
# in graphic mode. It only support the 3000 series graphical VFDs for now.
#
# 'sdl' uses the Simple DirectMedia Layer to render in a graphical context.
# 'sdl_glsl' uses SDL to create an OpenGL context. Write your own shaders or
# use one of the predefined ones.
method = sdl_glsl
# Orientation of the visualization. Can be 'bottom', 'top', 'left', 'right' or
# 'horizontal'. Default is 'bottom'. 'left and 'right' are only supported on sdl
# and ncruses output. 'horizontal' (bars go up and down from center) is only supported
# on noncurses output.
# Note: many fonts have weird or missing glyphs for characters used in orientations
# other than 'bottom', which can make output not look right.
# Visual channels. Can be 'stereo' or 'mono'.
# 'stereo' mirrors both channels with low frequencies in center.
# 'mono' outputs left to right lowest to highest frequencies.
# 'mono_option' set mono to either take input from 'left', 'right' or 'average'.
# set 'reverse' to 1 to display frequencies the other way around.
# Raw output target. A fifo will be created if target does not exist.
# Raw data format. Can be 'binary' or 'ascii'.
# Binary bit format, can be '8bit' (0-255) or '16bit' (0-65530).
# Ascii max value. In 'ascii' mode range will run from 0 to value specified here
# Ascii delimiters. In ascii format each bar and frame is separated by a delimiters.
# Use decimal value in ascii table (i.e. 59 = ';' and 10 = '\n' (line feed)).
bar_delimiter = 0
# sdl window size and position. -1,-1 is centered.
sdl_width = 150
sdl_height = 39
# set label on bars on the x-axis. Can be 'frequency' or 'none'. Default: 'none'
# 'frequency' displays the lower cut off frequency of the bar above.
# Only supported on ncurses and noncurses output.
# enable synchronized sync. 1 = on, 0 = off
# removes flickering in alacritty terminal emulator.
# defaults to off since the behaviour in other terminal emulators is unknown
# Shaders for sdl_glsl, located in $HOME/.config/cava/shaders
vertex_shader = pass_through.vert
fragment_shader = bar_spectrum.frag
; for glsl output mode, keep rendering even if no audio
continuous_rendering = 1;
# disable console blank (screen saver) in tty
# (Not supported on FreeBSD)
# show a flat bar at the bottom of the screen when idle, 1 = on, 0 = off
# show waveform instead of frequency spectrum, 1 = on, 0 = off
[color]
# Colors can be one of seven predefined: black, blue, cyan, green, magenta, red, white, yellow.
# Or defined by hex code '#xxxxxx' (hex code must be within ''). User defined colors requires
# a terminal that can change color definitions such as Gnome-terminal or rxvt.
# default is to keep current terminal color
# SDL and sdl_glsl only support hex code colors, these are the default:
background = '#282C34'
# Gradient mode, only hex defined colors are supported,
# background must also be defined in hex or remain commented out. 1 = on, 0 = off.
# You can define as many as 8 different colors. They range from bottom to top of screen
gradient = 1
gradient_count = 2
gradient_color_1 = '#282C34'
gradient_color_2 = '#45475A'
; gradient_color_1 = '#59cc33'
; gradient_color_2 = '#80cc33'
gradient_color_3 = '#a6cc33'
gradient_color_4 = '#cccc33'
gradient_color_5 = '#cca633'
gradient_color_6 = '#cc8033'
gradient_color_7 = '#cc5933'
gradient_color_8 = '#cc3333'
[smoothing]
# Percentage value for integral smoothing. Takes values from 0 - 100.
# Higher values means smoother, but less precise. 0 to disable.
# DEPRECATED as of 0.8.0, use noise_reduction instead
# Disables or enables the so-called "Monstercat smoothing" with or without "waves". Set to 0 to disable.
# Set gravity percentage for "drop off". Higher values means bars will drop faster.
# Accepts only non-negative values. 50 means half gravity, 200 means double. Set to 0 to disable "drop off".
# DEPRECATED as of 0.8.0, use noise_reduction instead
# In bar height, bars that would have been lower that this will not be drawn.
# DEPRECATED as of 0.8.0
# Noise reduction, int 0 - 100. default 77
# the raw visualization is very noisy, this factor adjusts the integral and gravity filters to keep the signal smooth
# 100 will be very slow and smooth, 0 will be fast but noisy.
[eq]
# This one is tricky. You can have as much keys as you want.
# Remember to uncomment more than one key! More keys = more precision.
# Look at readme.md on github for further explanations and examples.
```
Different waybar_cava#N.conf see at [cava GLSL](https://github.com/Alexays/Waybar/wiki/Module:-Cava:-GLSL)
+22 -2
View File
@@ -138,6 +138,11 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
:[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on :[ When enabled, the calendar follows the ISO 8601 standard: weeks begin on
Monday, and the first week of the year is numbered 1. The default week format is Monday, and the first week of the year is numbered 1. The default week format is
'{:%V}'. '{:%V}'.
|[ *first-day-of-week*
:[ integer
:[
:[ The first day of the week, where 0 is Sunday and 6 is Saturday.
When not set, the first day of the week is determined by the locale settings.
3. Addressed by *clock: calendar: format* 3. Addressed by *clock: calendar: format*
[- *Option* [- *Option*
@@ -180,6 +185,8 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
:[ Switch to the next calendar month/year :[ Switch to the next calendar month/year
|[ *shift_down* |[ *shift_down*
:[ Switch to the previous calendar month/year :[ Switch to the previous calendar month/year
|[ *exec <cmd>*
:[ Execute the specified command
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
@@ -204,12 +211,13 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
``` ```
"clock": { "clock": {
"format": "{:%H:%M}  ", "format": "{:%H:%M}  ",
"format-alt": "{:%A, %B %d, %Y (%R)} ", "format-alt": "{:%A, %B %d, %Y (%R)} 󰃰 ",
"tooltip-format": "<tt><small>{calendar}</small></tt>", "tooltip-format": "<tt><small>{calendar}</small></tt>",
"calendar": { "calendar": {
"mode" : "year", "mode" : "year",
"mode-mon-col" : 3, "mode-mon-col" : 3,
"weeks-pos" : "right", "weeks-pos" : "right",
"first-day-of-week": 1,
"on-scroll" : 1, "on-scroll" : 1,
"on-click-right" : "mode", "on-click-right" : "mode",
"format": { "format": {
@@ -259,7 +267,19 @@ View all valid format options in *strftime(3)* or have a look https://en.cpprefe
"tooltip-format": "{tz_list}" "tooltip-format": "{tz_list}"
} }
``` ```
5. Simple calendar tooltip
```
"clock": {
"format": "{:%H:%M}",
"tooltip-format": "<tt>{calendar}</tt>",
"calendar": {
"format": {
"today": "<span color='#ffcc66'><b>{}</b></span>"
}
}
}
```
# STYLE # STYLE
- *#clock* - *#clock*
@@ -287,7 +307,7 @@ Example of working config
``` ```
"clock": { "clock": {
"format": "{:%H:%M}  ", "format": "{:%H:%M}  ",
"format-alt": "{:%A, %B %d, %Y (%R)} ", "format-alt": "{:%A, %B %d, %Y (%R)} 󰃰 ",
"tooltip-format": "\n<span size='9pt' font='WenQuanYi Zen Hei Mono'>{calendar}</span>", "tooltip-format": "\n<span size='9pt' font='WenQuanYi Zen Hei Mono'>{calendar}</span>",
"calendar": { "calendar": {
"mode" : "year", "mode" : "year",
+80
View File
@@ -0,0 +1,80 @@
waybar-cpu-graph(5)
# NAME
waybar - cpu graph module
# DESCRIPTION
The *cpu graph* module displays a line graph with the CPU utilization.
# CONFIGURATION
*interval*: ++
typeof: integer ++
default: 10 ++
The interval in which the information gets polled.
*width*: ++
typeof: integer ++
The length in pixels the module should display.
*datapoints*: ++
typeof: integer ++
How many data points to show.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-middle*: ++
typeof: string ++
Command to execute when middle-clicked on the module using mousewheel.
*on-click-right*: ++
typeof: string ++
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
Command to execute when the module is updated.
*on-scroll-up*: ++
typeof: string ++
Command to execute when scrolling up on the module.
*on-scroll-down*: ++
typeof: string ++
Command to execute when scrolling down on the module.
*smooth-scrolling-threshold*: ++
typeof: double ++
Threshold to be used when scrolling.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
*expand*: ++
typeof: bool ++
default: false ++
Enables this module to consume all left over space dynamically.
# EXAMPLES
Basic configuration:
```
"cpu_graph": {
"interval": 2,
"width": 10
}
```
# STYLE
- *#cpu_graph*
- *.cpu-intensive*
- *.cpu-high*
- *.cpu-moderate*
+30
View File
@@ -83,6 +83,18 @@ The *cpu* module displays the current CPU utilization.
default: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
The format of the tooltip shown on hover. Supports the same replacements as *format*.
*format-<state>*: ++
typeof: string ++
The format to use when the given *state* (see *states*) is active. Supports the same replacements as *format*.
*tooltip-format-<state>*: ++
typeof: string ++
The tooltip format to use when the given *state* (see *states*) is active. Takes precedence over *tooltip-format*.
*expand*: ++ *expand*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@@ -92,6 +104,12 @@ The *cpu* module displays the current CPU utilization.
*{load}*: Current CPU load. *{load}*: Current CPU load.
*{load1}*: CPU load average over the last minute.
*{load5}*: CPU load average over the last 5 minutes.
*{load15}*: CPU load average over the last 15 minutes.
*{usage}*: Current overall 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}. *{usage*{n}*}*: Current CPU core n usage. Cores are numbered from zero, so first core will be {usage0} and 4th will be {usage3}.
@@ -106,6 +124,8 @@ The *cpu* module displays the current CPU utilization.
*{icon*{n}*}*: Icon for CPU core n usage. Use like {icon0}. *{icon*{n}*}*: Icon for CPU core n usage. Use like {icon0}.
*{icon0}{icon1}{icon2}{icon3}*: All per-core icons concatenated. Equivalent to {icon0}{icon1}...{icon*N*} but adapts to the number of cores automatically.
# EXAMPLES # EXAMPLES
Basic configuration: Basic configuration:
@@ -128,6 +148,16 @@ CPU usage per core rendered as icons:
}, },
``` ```
Automatically determine number of icons according to number of logical cores:
```
"cpu": {
"interval": 1,
"format": "{icons} {usage:>2}% ",
"format-icons": ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"],
},
```
# STYLE # STYLE
- *#cpu* - *#cpu*
+189
View File
@@ -0,0 +1,189 @@
waybar-custom-graph(5)
# NAME
waybar - custom graph module
# DESCRIPTION
The *custom-graph* module displays a graph with the percentage output of a script.
# CONFIGURATION
Addressed by *custom-graph/<name>*
*exec*: ++
typeof: string ++
The path to the script, which should be executed.
*exec-if*: ++
typeof: string ++
The path to a script, which determines if the script in *exec* should be executed. ++
*exec* will be executed if the exit code of *exec-if* equals 0.
*exec-on-event*: ++
typeof: bool ++
default: true ++
If an event command is set (e.g. *on-click* or *on-scroll-up*) then re-execute the script after executing the event command.
*return-type*: ++
typeof: string ++
See *return-type*
*interval*: ++
typeof: integer or float ++
The interval (in seconds) in which the information gets polled. ++
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
Use *once* if you want to execute the module only on startup. ++
You can update it manually with a signal. If no *interval* or *signal* is defined, it is assumed that the out script loops itself. ++
If a *signal* is defined then the script will run once on startup and will only update with a signal.
*restart-interval*: ++
typeof: integer or float ++
The restart interval (in seconds). ++
Minimum value is 0.001 (1ms). Values smaller than 1ms will be set to 1ms. ++
Can't be used with the *interval* option, so only with continuous scripts. ++
Once the script exits, it'll be re-executed after the *restart-interval*.
*signal*: ++
typeof: integer ++
The signal number used to update the module. ++
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. ++
If no interval is defined then a signal will be the only way to update the module.
*format*: ++
typeof: string ++
default: {text} ++
The format, how information should be displayed. On {text} data gets inserted.
*format-icons*: ++
typeof: array ++
Based on the set percentage, the corresponding icon gets selected. The order is *low* to *high*.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label (in 90 degree increments).
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-middle*: ++
typeof: string ++
Command to execute when middle-clicked on the module using mousewheel.
*on-click-right*: ++
typeof: string ++
Command to execute when you right-click on the module.
*on-update*: ++
typeof: string ++
Command to execute when the module is updated.
*on-scroll-up*: ++
typeof: string ++
Command to execute when scrolling up on the module.
*on-scroll-down*: ++
typeof: string ++
Command to execute when scrolling down on the module.
*smooth-scrolling-threshold*: ++
typeof: double ++
Threshold to be used when scrolling.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
The tooltip format. If specified, overrides any tooltip output from the script in *exec*. ++
Uses the same format replacements as *format*.
*escape*: ++
typeof: bool ++
default: false ++
Option to enable escaping of script output.
*menu*: ++
typeof: string ++
Action that popups the menu.
*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type
GtkMenu with id *menu*
*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.
*expand*: ++
typeof: bool ++
default: false ++
Enables this module to consume all left over space dynamically.
# RETURN-TYPE
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.
This should look like this:
```
{"text": "$text", "tooltip": "$tooltip", "class": "$class", "percentage": $percentage }
```
The *class* parameter also accepts an array of strings.
If nothing or an invalid option is specified, Waybar expects i3blocks style output. Values are *newline* separated.
This should look like this:
```
$text\\n$tooltip\\n$class*
```
*class* is a CSS class, to apply different styles in *style.css*
# FORMAT REPLACEMENTS
*{text}*: Output of the script.
*{percentage}* Percentage which can be set via a json return type.
*{icon}*: An icon from 'format-icons' according to percentage.
# EXAMPLES
## Memory:
```
"custom-graph/memory": {
"interval": 60,
"graph_type": "gauge",
"width": 52,
"exec": "/path/mem.sh",
"signal": 8,
"return-type": "json"
},
```
mem.sh:
```
#!/bin/bash
mem_info=$(cat /proc/meminfo)
mem_total=$(echo "$mem_info" | grep '^MemTotal:' | awk '{print $2}')
mem_available=$(echo "$mem_info" | grep '^MemAvailable:' | awk '{print $2}')
mem_used=$((mem_total - mem_available))
mem_percent=$((mem_used * 100 / mem_total))
echo "{\"text\": \"${mem_percent}%\", \"percentage\": ${mem_percent},\"tooltip\": \"Memory: ${mem_used}KB used / ${mem_total}KB total\"}'"
```
# STYLE
- *#custom-graph-<name>*
- *#custom-graph-<name>.<class>*
- *<class>* can be set by the script. For more information see *return-type*
+1 -2
View File
@@ -234,7 +234,6 @@ $text\\n$tooltip\\n$class*
``` ```
"custom/pacman": { "custom/pacman": {
"format": "{text} ", "format": "{text} ",
"interval": 3600, // every hour
"exec": "checkupdates | wc -l", // # of updates "exec": "checkupdates | wc -l", // # of updates
"exec-if": "exit 0", // always run; consider advanced run conditions "exec-if": "exit 0", // always run; consider advanced run conditions
"on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system "on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system
@@ -242,7 +241,7 @@ $text\\n$tooltip\\n$class*
} }
``` ```
You can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*. Under the premise that interval is not defined, you can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
# STYLE # STYLE
+36 -9
View File
@@ -6,17 +6,12 @@ waybar - disk module
# DESCRIPTION # DESCRIPTION
The *disk* module displays the current disk space used. The *disk* module displays information of multiple disks.
# CONFIGURATION # CONFIGURATION
Addressed by *disk* Addressed by *disk*
*path*: ++
typeof: string ++
default: "/" ++
Any path residing in the filesystem or mountpoint for which the information should be displayed.
*interval*: ++ *interval*: ++
typeof: integer++ typeof: integer++
default: 30 ++ default: 30 ++
@@ -25,7 +20,7 @@ Addressed by *disk*
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: "{percentage_used}%" ++ default: "{percentage_used}%" ++
The format, how information should be displayed. The format, how information for each disk should be displayed.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
@@ -75,6 +70,26 @@ Addressed by *disk*
typeof: string ++ typeof: string ++
Command to execute when scrolling down on the module. Command to execute when scrolling down on the module.
*path*: ++
typeof: string ++
default: "/" ++
Deprecated path of filesystem or mountpoint to monitor.
*paths*: ++
typeof: array ++
default: ["/"] ++
Array of paths residing in the filesystem or mountpoint for which the information should be displayed.
*header*: ++
typeof: string ++
default: "" ++
Text to appear before the disk information defined in the format.
*separator*: ++
typeof: string ++
default: " " ++
Separator string between multiple disk information.
*smooth-scrolling-threshold*: ++ *smooth-scrolling-threshold*: ++
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
@@ -123,7 +138,7 @@ Addressed by *disk*
*{free}*: Amount of available disk space for normal users. Automatically selects unit based on size remaining. *{free}*: Amount of available disk space for normal users. Automatically selects unit based on size remaining.
*{path}*: The path specified in the configuration. *{path}*: The path for each disk specified in the configuration.
*{specific_total}*: Total amount of space on the disk, partition, or mountpoint in a specific unit. Defaults to bytes. *{specific_total}*: Total amount of space on the disk, partition, or mountpoint in a specific unit. Defaults to bytes.
@@ -143,10 +158,22 @@ Addressed by *disk*
``` ```
"disk": { "disk": {
"interval": 30, "interval": 30,
"format": "{percentage_free}% free on {path}",
"header": "Disks: ",
"paths": ["/", "/home"],
"separator": " ",
}
```
```
"disk": {
"interval": 30,
"paths": ["/"],
"format": "{specific_free:0.2f} GB out of {specific_total:0.2f} GB available. Alternatively {free} out of {total} available", "format": "{specific_free:0.2f} GB out of {specific_total:0.2f} GB available. Alternatively {free} out of {total} available",
"unit": "GB" "unit": "GB"
// 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available.
} }
// 1434.25 GB out of 2000.00 GB available. Alternatively 1.4TiB out of 1.9TiB available.
``` ```
# STYLE # STYLE
+8 -1
View File
@@ -21,6 +21,11 @@ Addressed by *dwl/tags*
typeof: array ++ typeof: array ++
The label to display for each tag. The label to display for each tag.
*hide-vacant*: ++
typeof: bool ++
default: false ++
If set to true, tags without clients and that are not active will be hidden.
*disable-click*: ++ *disable-click*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@@ -43,10 +48,12 @@ Addressed by *dwl/tags*
- *#tags button* - *#tags button*
- *#tags button.occupied* - *#tags button.occupied*
- *#tags button.empty*
- *#tags button.focused* - *#tags button.focused*
- *#tags button.urgent* - *#tags button.urgent*
- *#tags button.output*
Note that occupied/focused/urgent status may overlap. That is, a tag may be Note that occupied/focused/urgent/output status may overlap. That is, a tag may be
both occupied and focused at the same time. both occupied and focused at the same time.
# SEE ALSO # SEE ALSO
+14
View File
@@ -17,6 +17,16 @@ Addressed by *dwl/window*
default: {title} ++ default: {title} ++
The format, how information should be displayed. The format, how information should be displayed.
*hide-empty*: ++
typeof: bool ++
default: false ++
Option to hide the module when the content would be empty.
*hide-inactive*: ++
typeof: bool ++
default: false ++
Option to hide the module when the window is unfocused.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label (in 90 degree increments). Positive value to rotate the text label (in 90 degree increments).
@@ -109,6 +119,10 @@ If no expression matches, the format output is left unchanged.
Invalid expressions (e.g., mismatched parentheses) are skipped. Invalid expressions (e.g., mismatched parentheses) are skipped.
# STYLE
- *#window.active*
# EXAMPLES # EXAMPLES
``` ```
+2 -2
View File
@@ -43,7 +43,7 @@ Feral Gamemode optimizations.
*glyph*: ++ *glyph*: ++
typeof: string ++ typeof: string ++
default: ++ default: 󰊴 ++
The string icon to display. Only visible if *use-icon* is set to false. The string icon to display. Only visible if *use-icon* is set to false.
*icon-name*: ++ *icon-name*: ++
@@ -82,7 +82,7 @@ Feral Gamemode optimizations.
"gamemode": { "gamemode": {
"format": "{glyph}", "format": "{glyph}",
"format-alt": "{glyph} {count}", "format-alt": "{glyph} {count}",
"glyph": "", "glyph": "󰊴",
"hide-not-running": true, "hide-not-running": true,
"use-icon": true, "use-icon": true,
"icon-name": "input-gaming-symbolic", "icon-name": "input-gaming-symbolic",
+44
View File
@@ -21,6 +21,10 @@ Addressed by *hyprland/language*
typeof: string++ typeof: string++
Provide an alternative name to display per language where <lang> is the language of your choosing. Can be passed multiple times with multiple languages as shown by the example below. Provide an alternative name to display per language where <lang> is the language of your choosing. Can be passed multiple times with multiple languages as shown by the example below.
*format-<lang>-<variant>* ++
typeof: string ++
Like *format-<lang>* but also matches the layout variant, taking precedence over *format-<lang>* when both the language and variant match.
*keyboard-name*: ++ *keyboard-name*: ++
typeof: string ++ typeof: string ++
Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "at-translated-set..." is recommended. Specifies which keyboard to use from hyprctl devices output. Using the option that begins with "at-translated-set..." is recommended.
@@ -38,6 +42,24 @@ Addressed by *hyprland/language*
typeof: array ++ typeof: array ++
The actions corresponding to the buttons of the menu. The actions corresponding to the buttons of the menu.
*tooltip*: ++
typeof: boolean ++
default: true ++
Enables or disables the tooltip for the language module. By default, the tooltip is enabled. Set to *false* to disable.
*tooltip-format*: ++
typeof: string ++
default: {long} ++
Specifies the format of the tooltip when it is enabled. It follows the same format replacement rules as the *format* key.
*tooltip-format-<lang>*: ++
typeof: string ++
Allows specifying a different tooltip format for each language. The *<lang>* should be replaced with the language code. This can be used to provide a custom tooltip for each language.
*tooltip-format-<lang>-<variant>*: ++
typeof: string ++
Like *tooltip-format-<lang>* but also matches the layout variant, taking precedence over *tooltip-format-<lang>* when both the language and variant match.
*expand*: ++ *expand*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@@ -66,6 +88,28 @@ Addressed by *hyprland/language*
} }
``` ```
```
"hyprland/language": {
"format": "{}",
"format-en": "US",
"format-es": "ES",
"tooltip": true,
"tooltip-format": "{long}"
}
```
```
"hyprland/language": {
"format": "{}",
"format-en": "US",
"format-es": "ES",
"tooltip": true,
"tooltip-format": "{}",
"tooltip-format-es": "{Español}",
"tooltip-format-en": "{English (american)}"
}
```
# STYLE # STYLE
- *#language* - *#language*
+9
View File
@@ -25,6 +25,15 @@ Addressed by *hyprland/window*
typeof: bool ++ typeof: bool ++
Show the active window of the monitor the bar belongs to, instead of the focused window. Show the active window of the monitor the bar belongs to, instead of the focused window.
*fallback*: ++
typeof: string ++
Text to display when the focused window title is empty (for example when no window is focused).
*tooltip-format*: ++
typeof: string ++
default: {title} ++
The format of the tooltip shown on hover. Supports the same replacements as *format*. Requires *tooltip* to be enabled.
*icon*: ++ *icon*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
+41
View File
@@ -41,6 +41,19 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
The separator to be used between windows in a workspace. ++ The separator to be used between windows in a workspace. ++
This setting is ignored if *workspace-taskbar.enable* is set to true. This setting is ignored if *workspace-taskbar.enable* is set to true.
*window-rewrite-group-threshold*: ++
typeof: int ++
default: 0 ++
When a workspace contains at least this many windows with the same rewrite result, they are collapsed into a single one using *window-rewrite-group-format*. ++
Set to 0 to disable grouping. ++
This setting is ignored if *workspace-taskbar.enable* is set to true.
*window-rewrite-group-format*: ++
typeof: string ++
default: "{icon}×{count}" ++
The format used to represent a group of collapsed windows. Available placeholders are {icon} (the icon being grouped) and {count} (how many windows share it). ++
This setting is ignored if *workspace-taskbar.enable* is set to true.
*workspace-taskbar*: ++ *workspace-taskbar*: ++
typeof: object ++ typeof: object ++
Contains settings for the workspace taskbar, an alternative mode for the workspaces module which displays the window icons as images instead of text. Contains settings for the workspace taskbar, an alternative mode for the workspaces module which displays the window icons as images instead of text.
@@ -98,6 +111,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
- {button} Pressed button number, see https://api.gtkd.org/gdk.c.types.GdkEventButton.button.html. ++ - {button} Pressed button number, see https://api.gtkd.org/gdk.c.types.GdkEventButton.button.html. ++
See https://github.com/Alexays/Waybar/wiki/Module:-Hyprland#workspace-taskbars-example for a full example. See https://github.com/Alexays/Waybar/wiki/Module:-Hyprland#workspace-taskbars-example for a full example.
*max-windows*: ++
typeof: int ++
default: 0 (unlimited) ++
Maximum number of windows to show per workspace. When set, newest windows beyond the limit are not shown. Set to 0 for unlimited windows.
*show-special*: ++ *show-special*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@@ -113,6 +131,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
default: false ++ default: false ++
If set to true, only persistent workspaces will be shown on bar. If set to true, only persistent workspaces will be shown on bar.
*persistent-workspaces*: ++
typeof: object ++
default: empty ++
Lists workspaces that should always be shown, even when they do not exist. Keys are workspace names and values are arrays of output names on which the workspace should be shown (an empty array means all outputs). See the examples below.
*all-outputs*: ++ *all-outputs*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@@ -123,6 +146,11 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
default: false ++ default: false ++
If set to true, only the active workspace will be shown. If set to true, only the active workspace will be shown.
*hide-active*: ++
typeof: bool ++
default: false ++
If set to true, the active workspace will be hidden. Unless a workspace is persistent or special.
*move-to-monitor*: ++ *move-to-monitor*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
@@ -130,6 +158,19 @@ This setting is ignored if *workspace-taskbar.enable* is set to true.
Otherwise, the workspace will open on the monitor where it was previously assigned. Otherwise, the workspace will open on the monitor where it was previously assigned.
Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland. Analog to using `focusworkspaceoncurrentmonitor` dispatcher instead of `workspace` in Hyprland.
*enable-bar-scroll*: ++
typeof: bool ++
default: false ++
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
*on-scroll-up*: ++
typeof: string ++
Command to execute when scrolling up on the module. This replaces the default behaviour of workspace cycling.
*on-scroll-down*: ++
typeof: string ++
Command to execute when scrolling down on the module. This replaces the default behaviour of workspace cycling.
*ignore-workspaces*: ++ *ignore-workspaces*: ++
typeof: array ++ typeof: array ++
default: [] ++ default: [] ++
+42 -2
View File
@@ -76,6 +76,17 @@ screensaver, also known as "presentation mode".
typeof: double ++ typeof: double ++
The number of minutes the inhibition should last. The number of minutes the inhibition should last.
*wait-for-activity*: ++
typeof: bool ++
default: *false* ++
When enabled, the idle inhibitor remains active as long as there is keyboard or mouse activity on the bar. If there is no activity for the duration specified in *timeout*, the inhibitor will automatically toggle off. This option requires *timeout* to be set.
*signal*: ++
typeof: integer ++
The signal number used to toggle the idle inhibitor externally. ++
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. ++
Use `pkill -SIGRTMIN+N waybar` to toggle the idle inhibitor from scripts or keybindings.
*tooltip*: ++ *tooltip*: ++
typeof: bool ++ typeof: bool ++
default: true ++ default: true ++
@@ -115,17 +126,46 @@ screensaver, also known as "presentation mode".
# EXAMPLES # EXAMPLES
Basic usage with timeout:
``` ```
"idle_inhibitor": { "idle_inhibitor": {
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"activated": "", "activated": "",
"deactivated": "" "deactivated": ""
}, },
"timeout": 30.5 "timeout": 30.5
} }
``` ```
With external control via signals (can be toggled with `pkill -SIGRTMIN+8 waybar`):
```
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
},
"signal": 8
}
```
With wait-for-activity feature:
```
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
},
"timeout": 5.0,
"wait-for-activity": true
}
```
# STYLE # STYLE
- *#idle_inhibitor* - *#idle_inhibitor*

Some files were not shown because too many files have changed in this diff Show More