Compare commits

..

No commits in common. "master" and "0.9.20" have entirely different histories.

68 changed files with 809 additions and 1472 deletions

View File

@ -13,7 +13,7 @@ jobs:
- fedora - fedora
- opensuse - opensuse
- gentoo - gentoo
cpp_std: [c++20] cpp_std: [c++17]
include: include:
- distro: fedora - distro: fedora
cpp_std: c++20 cpp_std: c++20

View File

@ -1,7 +1,7 @@
# Waybar [![Licence](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Paypal Donate](https://img.shields.io/badge/Donate-Paypal-2244dd.svg)](https://paypal.me/ARouillard)<br>![Waybar](https://raw.githubusercontent.com/alexays/waybar/master/preview-2.png) # Waybar [![Licence](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Paypal Donate](https://img.shields.io/badge/Donate-Paypal-2244dd.svg)](https://paypal.me/ARouillard)<br>![Waybar](https://raw.githubusercontent.com/alexays/waybar/master/preview-2.png)
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br> > Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
> Available in Arch [extra](https://www.archlinux.org/packages/extra/x86_64/waybar/) or > Available in Arch [community](https://www.archlinux.org/packages/extra/x86_64/waybar/) or
[AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar).<br> [AUR](https://aur.archlinux.org/packages/waybar-git/), [Gentoo](https://packages.gentoo.org/packages/gui-apps/waybar), [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar), and [Alpine Linux](https://pkgs.alpinelinux.org/packages?name=waybar).<br>
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)* > *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*

78
flake.lock generated
View File

@ -2,15 +2,15 @@
"nodes": { "nodes": {
"devshell": { "devshell": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "flake-utils": "flake-utils",
"systems": "systems" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1692523566, "lastModified": 1676293499,
"narHash": "sha256-VDJDihK6jNebVw9y3qKCVD6+6QaC/x8kxZzL4MaIPPY=", "narHash": "sha256-uIOTlTxvrXxpKeTvwBI1JGDGtCxMXE3BI0LFwoQMhiQ=",
"owner": "numtide", "owner": "numtide",
"repo": "devshell", "repo": "devshell",
"rev": "d208c58e2f7afef838add5f18a9936b12a71d695", "rev": "71e3022e3ab20bbf1342640547ef5bc14fb43bf4",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -36,15 +36,27 @@
} }
}, },
"flake-utils": { "flake-utils": {
"inputs": {
"systems": "systems_2"
},
"locked": { "locked": {
"lastModified": 1689068808, "lastModified": 1642700792,
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", "narHash": "sha256-XqHrk7hFb+zBvRg6Ghl+AZDq03ov6OshJLiSWOoX5es=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", "rev": "846b2ae0fc4cc943637d3d1def4454213e203cba",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1676283394,
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -55,11 +67,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1677383253, "lastModified": 1643381941,
"narHash": "sha256-UfpzWfSxkfXHnb4boXZNaKsAcUrZT9Hw+tao1oZxd08=", "narHash": "sha256-pHTwvnN4tTsEKkWlXQ8JMY423epos8wUOhthpwJjtpc=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9952d6bc395f5841262b006fbace8dd7e143b634", "rev": "5efc8ca954272c4376ac929f4c5ffefcc20551d5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -71,11 +83,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1692638711, "lastModified": 1676300157,
"narHash": "sha256-J0LgSFgJVGCC1+j5R2QndadWI1oumusg6hCtYAzLID4=", "narHash": "sha256-1HjRzfp6LOLfcj/HJHdVKWAkX9QRAouoh6AjzJiIerU=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "91a22f76cd1716f9d0149e8a5c68424bb691de15", "rev": "545c7a31e5dedea4a6d372712a18e00ce097d462",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -89,39 +101,9 @@
"inputs": { "inputs": {
"devshell": "devshell", "devshell": "devshell",
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-utils": "flake-utils", "flake-utils": "flake-utils_2",
"nixpkgs": "nixpkgs_2" "nixpkgs": "nixpkgs_2"
} }
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
} }
}, },
"root": "root", "root": "root",

View File

@ -30,14 +30,14 @@
]); ]);
in in
{ {
overlays.default = final: prev: { overlays.default = _: prev: {
waybar = final.callPackage ./nix/default.nix { waybar = prev.callPackage ./nix/default.nix {
version = prev.waybar.version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); version = prev.waybar.version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
}; };
}; };
packages = genSystems packages = genSystems
(system: (system:
(self.overlays.default pkgsFor.${system} pkgsFor.${system}) (self.overlays.default null pkgsFor.${system})
// { // {
default = self.packages.${system}.waybar; default = self.packages.${system}.waybar;
}); });
@ -47,12 +47,17 @@
let pkgs = import nixpkgs { let pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ devshell.overlays.default ]; overlays = [ devshell.overlay ];
}; };
in in
pkgs.devshell.mkShell { pkgs.devshell.mkShell {
imports = [ "${pkgs.devshell.extraModulesDir}/language/c.nix" ]; imports = [ "${pkgs.devshell.extraModulesDir}/language/c.nix" ];
commands = [
{
package = pkgs.devshell.cli;
help = "Per project developer environments";
}
];
devshell.packages = with pkgs; [ devshell.packages = with pkgs; [
clang-tools clang-tools
gdb gdb
@ -74,7 +79,6 @@
at-spi2-atk atkmm cairo cairomm catch2 fmt_8 fontconfig at-spi2-atk atkmm cairo cairomm catch2 fmt_8 fontconfig
gdk-pixbuf glibmm gtk3 harfbuzz pango pangomm wayland-protocols gdk-pixbuf glibmm gtk3 harfbuzz pango pangomm wayland-protocols
]); ]);
env = with pkgs; [ env = with pkgs; [
{ name = "CPLUS_INCLUDE_PATH"; prefix = "$DEVSHELL_DIR/include"; } { name = "CPLUS_INCLUDE_PATH"; prefix = "$DEVSHELL_DIR/include"; }
{ name = "PKG_CONFIG_PATH"; prefix = "$DEVSHELL_DIR/lib/pkgconfig"; } { name = "PKG_CONFIG_PATH"; prefix = "$DEVSHELL_DIR/lib/pkgconfig"; }

View File

@ -59,8 +59,7 @@ class Bluetooth : public ALabel {
auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool; auto getDeviceProperties(GDBusObject*, DeviceInfo&) -> bool;
auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool; auto getControllerProperties(GDBusObject*, ControllerInfo&) -> bool;
// Returns std::nullopt if no controller could be found auto findCurController(ControllerInfo&) -> bool;
auto findCurController() -> std::optional<ControllerInfo>;
auto findConnectedDevices(const std::string&, std::vector<DeviceInfo>&) -> void; auto findConnectedDevices(const std::string&, std::vector<DeviceInfo>&) -> void;
#ifdef WANT_RFKILL #ifdef WANT_RFKILL
@ -69,7 +68,7 @@ class Bluetooth : public ALabel {
const std::unique_ptr<GDBusObjectManager, void (*)(GDBusObjectManager*)> manager_; const std::unique_ptr<GDBusObjectManager, void (*)(GDBusObjectManager*)> manager_;
std::string state_; std::string state_;
std::optional<ControllerInfo> cur_controller_; ControllerInfo cur_controller_;
std::vector<DeviceInfo> connected_devices_; std::vector<DeviceInfo> connected_devices_;
DeviceInfo cur_focussed_device_; DeviceInfo cur_focussed_device_;
std::string device_enumerate_; std::string device_enumerate_;

View File

@ -34,18 +34,11 @@ class Clock final : public ALabel {
auto first_day_of_week() -> date::weekday; auto first_day_of_week() -> date::weekday;
const date::time_zone* current_timezone(); const date::time_zone* current_timezone();
auto timezones_text(std::chrono::system_clock::time_point now) -> std::string; bool is_timezone_fixed();
auto timezones_text(std::chrono::system_clock::time_point* now) -> std::string;
/*Calendar properties*/ /*Calendar properties*/
WeeksSide cldWPos_{WeeksSide::HIDDEN}; WeeksSide cldWPos_{WeeksSide::HIDDEN};
/*
0 - calendar.format.months
1 - calendar.format.weekdays
2 - calendar.format.days
3 - calendar.format.today
4 - calendar.format.weeks
5 - tooltip-format
*/
std::map<int, std::string const> fmtMap_; std::map<int, std::string const> fmtMap_;
CldMode cldMode_{CldMode::MONTH}; CldMode cldMode_{CldMode::MONTH};
uint cldMonCols_{3}; // Count of the month in the row uint cldMonCols_{3}; // Count of the month in the row
@ -59,8 +52,8 @@ class Clock final : public ALabel {
std::string cldMonCached_{}; std::string cldMonCached_{};
date::day cldBaseDay_{0}; date::day cldBaseDay_{0};
/*Calendar functions*/ /*Calendar functions*/
auto get_calendar(const date::year_month_day& today, const date::year_month_day& ymd, auto get_calendar(const date::zoned_seconds& now, const date::zoned_seconds& wtime)
const date::time_zone* tz) -> const std::string; -> std::string;
/*Clock actions*/ /*Clock actions*/
void cldModeSwitch(); void cldModeSwitch();
void cldShift_up(); void cldShift_up();

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/args.h>
#include <csignal> #include <csignal>
#include <string> #include <string>
@ -35,7 +34,6 @@ class Custom : public ALabel {
std::string alt_; std::string alt_;
std::string tooltip_; std::string tooltip_;
std::vector<std::string> class_; std::vector<std::string> class_;
fmt::dynamic_format_arg_store<fmt::format_context> fields_;
int percentage_; int percentage_;
FILE* fp_; FILE* fp_;
int pid_; int pid_;

View File

@ -9,38 +9,27 @@
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
struct WorkspaceDto {
int id;
static WorkspaceDto parse(const Json::Value& value);
};
class Workspace { class Workspace {
public: public:
Workspace(const Json::Value& workspace_data); Workspace(int id);
std::string& select_icon(std::map<std::string, std::string>& icons_map); Workspace(WorkspaceDto dto);
Gtk::Button& button() { return button_; };
int id() const { return id_; }; int id() const { return id_; };
std::string name() const { return name_; }; int active() const { return active_; };
std::string output() const { return output_; }; std::string& select_icon(std::map<std::string, std::string>& icons_map);
bool active() const { return active_; };
bool is_special() const { return is_special_; };
bool is_persistent() const { return is_persistent_; };
bool is_empty() const { return windows_ == 0; };
bool is_urgent() const { return is_urgent_; };
auto handle_clicked(GdkEventButton* bt) -> bool;
void set_active(bool value = true) { active_ = value; }; void set_active(bool value = true) { active_ = value; };
void set_persistent(bool value = true) { is_persistent_ = value; }; Gtk::Button& button() { return button_; };
void set_urgent(bool value = true) { is_urgent_ = value; };
void set_windows(uint value) { windows_ = value; };
void update(const std::string& format, const std::string& icon); void update(const std::string& format, const std::string& icon);
private: private:
int id_; int id_;
std::string name_; bool active_;
std::string output_;
uint windows_;
bool active_ = false;
bool is_special_ = false;
bool is_persistent_ = false;
bool is_urgent_ = false;
Gtk::Button button_; Gtk::Button button_;
Gtk::Box content_; Gtk::Box content_;
@ -50,39 +39,23 @@ class Workspace {
class Workspaces : public AModule, public EventHandler { class Workspaces : public AModule, public EventHandler {
public: public:
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&); Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
~Workspaces() override; virtual ~Workspaces();
void update() override; void update() override;
void init(); void init();
auto all_outputs() const -> bool { return all_outputs_; }
auto show_special() const -> bool { return show_special_; }
auto get_bar_output() const -> std::string { return bar_.output->name; }
private: private:
void onEvent(const std::string&) override; void onEvent(const std::string&) override;
void update_window_count();
void sort_workspaces(); void sort_workspaces();
void create_workspace(Json::Value& value); void create_workspace(int id);
void remove_workspace(std::string name); void remove_workspace(int id);
void set_urgent_workspace(std::string windowaddress);
bool all_outputs_ = false;
bool show_special_ = false;
void fill_persistent_workspaces();
void create_persistent_workspaces();
std::vector<std::string> persistent_workspaces_to_create_;
bool persistent_created_ = false;
std::string format_; std::string format_;
std::map<std::string, std::string> icons_map_; std::map<std::string, std::string> icons_map_;
bool with_icon_; bool with_icon_;
uint64_t monitor_id_; int active_workspace_id;
std::string active_workspace_name_;
std::vector<std::unique_ptr<Workspace>> workspaces_; std::vector<std::unique_ptr<Workspace>> workspaces_;
std::vector<Json::Value> workspaces_to_create_; std::vector<int> workspaces_to_create_;
std::vector<std::string> workspaces_to_remove_; std::vector<int> workspaces_to_remove_;
std::mutex mutex_; std::mutex mutex_;
const Bar& bar_; const Bar& bar_;
Gtk::Box box_; Gtk::Box box_;

View File

@ -3,7 +3,6 @@
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <gtkmm/label.h> #include <gtkmm/label.h>
#include <set>
#include <unordered_map> #include <unordered_map>
#include "AModule.hpp" #include "AModule.hpp"
@ -41,7 +40,6 @@ class KeyboardState : public AModule {
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::set<int> binding_keys;
util::SleeperThread libinput_thread_, hotplug_thread_; util::SleeperThread libinput_thread_, hotplug_thread_;
}; };

View File

@ -41,7 +41,6 @@ class Workspaces : public AModule, public sigc::trackable {
const Bar& bar_; const Bar& bar_;
std::vector<Json::Value> workspaces_; std::vector<Json::Value> workspaces_;
std::vector<std::string> high_priority_named_;
std::vector<std::string> workspaces_order_; std::vector<std::string> workspaces_order_;
Gtk::Box box_; Gtk::Box box_;
util::JsonParser parser_; util::JsonParser parser_;

View File

@ -93,7 +93,7 @@ template <>
struct formatter<Glib::ustring> : formatter<std::string> { struct formatter<Glib::ustring> : formatter<std::string> {
template <typename FormatContext> template <typename FormatContext>
auto format(const Glib::ustring& value, FormatContext& ctx) { auto format(const Glib::ustring& value, FormatContext& ctx) {
return formatter<std::string>::format(static_cast<std::string>(value), ctx); return formatter<std::string>::format(value, ctx);
} }
}; };
} // namespace fmt } // namespace fmt

View File

@ -25,12 +25,12 @@ The *backlight* module displays the current backlight level.
The maximum length in characters the module should display. The maximum length in characters the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
@ -81,9 +81,9 @@ The *backlight* module displays the current backlight level.
``` ```
"backlight": { "backlight": {
"device": "intel_backlight", "device": "intel_backlight",
"format": "{percent}% {icon}", "format": "{percent}% {icon}",
"format-icons": ["", ""] "format-icons": ["", ""]
} }
``` ```

View File

@ -23,9 +23,9 @@ The *battery* module displays the current capacity and state (eg. charging) of y
Define the max percentage of the battery, for when you've set the battery to stop charging at a lower level to save it. For example, if you've set the battery to stop at 80% that will become the new 100%. Define the max percentage of the battery, for when you've set the battery to stop charging at a lower level to save it. For example, if you've set the battery to stop at 80% that will become the new 100%.
*design-capacity*: ++ *design-capacity*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
Option to use the battery design capacity instead of it's current maximal capacity. Option to use the battery design capacity instead of it's current maximal capacity.
*interval*: ++ *interval*: ++
typeof: integer ++ typeof: integer ++
@ -56,12 +56,12 @@ The *battery* module displays the current capacity and state (eg. charging) of y
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer++ typeof: integer++
@ -132,8 +132,8 @@ The *battery* module allows one to define custom formats based on up to two fact
# STATES # STATES
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*). - Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal or below the configured *<value>*. - The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal or below the configured *<value>*.
- Also each state can have its own *format*. Those con be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*. - Also each state can have its own *format*. Those con be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*.
@ -141,15 +141,15 @@ The *battery* module allows one to define custom formats based on up to two fact
``` ```
"battery": { "battery": {
"bat": "BAT2", "bat": "BAT2",
"interval": 60, "interval": 60,
"states": { "states": {
"warning": 30, "warning": 30,
"critical": 15 "critical": 15
}, },
"format": "{capacity}% {icon}", "format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""], "format-icons": ["", "", "", "", ""],
"max-length": 25 "max-length": 25
} }
``` ```

View File

@ -42,10 +42,6 @@ Addressed by *bluetooth*
typeof: string ++ typeof: string ++
This format is used when the displayed controller is connected to at least 1 device. This format is used when the displayed controller is connected to at least 1 device.
*format-no-controller*: ++
typeof: string ++
This format is used when no bluetooth controller could be found
*format-icons*: ++ *format-icons*: ++
typeof: array/object ++ typeof: array/object ++
Based on the current battery percentage (see section *EXPERIMENTAL BATTERY PERCENTAGE FEATURE*), the corresponding icon gets selected. ++ Based on the current battery percentage (see section *EXPERIMENTAL BATTERY PERCENTAGE FEATURE*), the corresponding icon gets selected. ++
@ -61,12 +57,12 @@ Addressed by *bluetooth*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -117,10 +113,6 @@ Addressed by *bluetooth*
typeof: string ++ typeof: string ++
This format is used when the displayed controller is connected to at least 1 device. This format is used when the displayed controller is connected to at least 1 device.
*tooltip-format-no-controller*: ++
typeof: string ++
This format is used when no bluetooth controller could be found
*tooltip-format-enumerate-connected*: ++ *tooltip-format-enumerate-connected*: ++
typeof: string ++ typeof: string ++
This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu. This format is used to define how each connected device should be displayed within the *device_enumerate* format replacement in the tooltip menu.

View File

@ -1,182 +0,0 @@
waybar-cava(5) "waybar-cava" "User Manual"
# NAME
waybar - cava module
# DESCRIPTION
*cava* module for karlstav/cava project. See it on github: https://github.com/karlstav/cava.
# FILES
$XDG_CONFIG_HOME/waybar/config ++
Per user configuration file
# ADDITIONAL FILES
libcava lives in:
. /usr/lib/libcava.so or /usr/lib64/libcava.so
. /usr/lib/pkgconfig/cava.pc or /usr/lib64/pkgconfig/cava.pc
. /usr/include/cava
# CONFIGURATION
[- *Option*
:- *Typeof*
:- *Default*
:- *Description*
|[ *cava_config*
:[ string
:[
:< Path where cava configuration file is placed to
|[ *framerate*
:[ integer
:[ 30
:[ rames per second. Is used as a replacement for *interval*
|[ *autosens*
:[ integer
:[ 1
:[ Will attempt to decrease sensitivity if the bars peak
|[ *sensitivity*
:[ integer
:[ 100
:[ Manual sensitivity in %. It's recommended to be omitted when *autosens* = 1
|[ *bars*
:[ integer
:[ 12
:[ The number of bars
|[ *lower_cutoff_freq*
:[ long integer
:[ 50
:[ Lower cutoff frequencies for lowest bars the bandwidth of the visualizer
|[ *higher_cutoff_freq*
:[ long integer
:[ 10000
:[ Higher cutoff frequencies for highest bars the bandwidth of the visualizer
|[ *sleep_timer*
:[ integer
:[ 5
:[ Seconds with no input before cava main thread goes to sleep mode
|[ *method*
:[ string
:[ pulse
:[ Audio capturing method. Possible methods are: pipewire, pulse, alsa, fifo, sndio or shmem
|[ *source*
:[ string
:[ auto
:[ See cava configuration
|[ *sample_rate*
:[ long integer
:[ 44100
:[ See cava configuration
|[ *sample_bits*
:[ integer
:[ 16
:[ See cava configuration
|[ *stereo*
:[ bool
:[ true
:[ Visual channels
|[ *reverse*
:[ bool
:[ false
:[ Displays frequencies the other way around
|[ *bar_delimiter*
:[ integer
:[ 0
:[ Each bar is separated by a delimiter. Use decimal value in ascii table(i.e. 59 = ";"). 0 means no delimiter
|[ *monstercat*
:[ bool
:[ false
:[ Disables or enables the so-called "Monstercat smoothing" with of without "waves"
|[ *waves*
:[ bool
:[ false
:[ Disables or enables the so-called "Monstercat smoothing" with of without "waves"
|[ *noise_reduction*
:[ double
:[ 0.77
:[ Range between 0 - 1. The raw visualization is very noisy, this factor adjust the integral and gravity filters to keep the signal smooth. 1 - will be very slow and smooth, 0 - will be fast but noisy
|[ *input_delay*
:[ integer
:[ 2
:[ Sets the delay before fetching audio source thread start working. On author machine Waybar starts much faster then pipewire audio server, and without a little delay cava module fails due to pipewire is not ready
|[ *ascii_max_range*
:[ integer
:[ 7
:[ It's impossible to set it directly. The value is dictated by the number of icons in the array *format-icons*
|[ *data_format*
:[ string
:[ asci
:[ It's impossible to set it. Waybar sets it to = asci for internal needs
|[ *raw_target*
:[ string
:[ /dev/stdout
:[ It's impossible to set it. Waybar sets it to = /dev/stdout for internal needs
Configuration can be provided as:
- The only cava configuration file which is provided through *cava_config*. The rest configuration can be skipped
- Without cava configuration file. In such case cava should be configured through provided list of the configuration option
- Mix. When provided both And cava configuration file And configuration options. In such case waybar applies configuration file first then overrides particular options by the provided list of configuration options
# ACTIONS
[- *String*
:- *Action*
|[ *mode*
:< Switch main cava thread and fetching audio source thread from/to pause/resume
# DEPENDENCIES
- iniparser
- fftw3
# SOLVING ISSUES
. On start Waybar throws an exception "error while loading shared libraries: libcava.so: cannot open shared object file: No such file or directory".
It might happen when libcava for some reason hasn't been registered in the system. sudo ldconfig should help
. Waybar is starting but cava module doesn't react on the music
1. In such case for at first need to make sure usual cava application is working as well
2. If so, need to comment all configuration options. Uncomment cava_config and provide the path to the working cava config
3. You might set too huge or too small input_delay. Try to setup to 4 seconds, restart waybar and check again 4 seconds past. Usual even on weak machines it should be enough
4. You might accidentally switched action mode to pause mode
# RISING ISSUES
For clear understanding: this module is a cava API's consumer. So for any bugs related to cava engine you should contact to Cava upstream(https://github.com/karlstav/cava) ++
with the one Exception. Cava upstream doesn't provide cava as a shared library. For that this module author made a fork libcava(https://github.com/LukashonakV/cava). ++
So the order is:
. cava upstream
. libcava upstream.
In case when cava releases new version and you're wanna get it, it should be raised an issue to libcava(https://github.com/LukashonakV/cava) with title ++
\[Bump\]x.x.x where x.x.x is cava release version.
# EXAMPLES
```
"cava": {
//"cava_config": "$XDG_CONFIG_HOME/cava/cava.conf",
"framerate": 30,
"autosens": 1,
//"sensitivity": 100,
"bars": 14,
"lower_cutoff_freq": 50,
"higher_cutoff_freq": 10000,
"method": "pulse",
"source": "auto",
"stereo": true,
"reverse": false,
"bar_delimiter": 0,
"monstercat": false,
"waves": false,
"noise_reduction": 0.77,
"input_delay": 2,
"format-icons" : ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ],
"actions": {
"on-click-right": "mode"
}
},
```

View File

@ -2,7 +2,7 @@ waybar-clock(5) "waybar-clock" "User Manual"
# NAME # NAME
waybar - clock module clock
# DESCRIPTION # DESCRIPTION
@ -11,7 +11,7 @@ waybar - clock module
# FILES # FILES
$XDG_CONFIG_HOME/waybar/config ++ $XDG_CONFIG_HOME/waybar/config ++
Per user configuration file Per user configuration file
# CONFIGURATION # CONFIGURATION
@ -37,13 +37,13 @@ $XDG_CONFIG_HOME/waybar/config ++
:[ list of strings :[ list of strings
:[ :[
:[ A list of timezones (as in *timezone*) to use for time display, changed using :[ A list of timezones (as in *timezone*) to use for time display, changed using
the scroll wheel. Do not specify *timezone* option when *timezones* is specified. the scroll wheel. Do not specify *timezone* option when *timezones* is specified.
"" represents the system's local timezone "" represents the system's local timezone
|[ *locale* |[ *locale*
:[ string :[ string
:[ :[
:[ A locale to be used to display the time. Intended to render times in custom :[ A locale to be used to display the time. Intended to render times in custom
timezones with the proper language and format timezones with the proper language and format
|[ *max-length* |[ *max-length*
:[ integer :[ integer
:[ :[
@ -104,14 +104,14 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
:[ integer :[ integer
:[ :[
:[ The position where week numbers should be displayed. Disabled when is empty. :[ The position where week numbers should be displayed. Disabled when is empty.
Possible values: left|right Possible values: left|right
|[ *on-scroll* |[ *on-scroll*
:[ integer :[ integer
:[ 1 :[ 1
:[ Value to scroll months/years forward/backward. Can be negative. Is :[ Value to scroll months/years forward/backward. Can be negative. Is
configured under *on-scroll* option configured under *on-scroll* option
3. Addressed by *clock: calendar: format* 3. Adressed by *clock: calendar: format*
[- *Option* [- *Option*
:- *Typeof* :- *Typeof*
:- *Default* :- *Default*
@ -164,9 +164,9 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
``` ```
"clock": { "clock": {
"interval": 60, "interval": 60,
"format": "{:%H:%M}", "format": "{:%H:%M}",
"max-length": 25 "max-length": 25
} }
``` ```
@ -174,30 +174,30 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
``` ```
"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",
"on-scroll" : 1, "on-scroll" : 1,
"on-click-right": "mode", "on-click-right": "mode",
"format": { "format": {
"months": "<span color='#ffead3'><b>{}</b></span>", "months": "<span color='#ffead3'><b>{}</b></span>",
"days": "<span color='#ecc6d9'><b>{}</b></span>", "days": "<span color='#ecc6d9'><b>{}</b></span>",
"weeks": "<span color='#99ffdd'><b>W{}</b></span>", "weeks": "<span color='#99ffdd'><b>W{}</b></span>",
"weekdays": "<span color='#ffcc66'><b>{}</b></span>", "weekdays": "<span color='#ffcc66'><b>{}</b></span>",
"today": "<span color='#ff6699'><b><u>{}</u></b></span>" "today": "<span color='#ff6699'><b><u>{}</u></b></span>"
} }
}, },
"actions": { "actions": {
"on-click-right": "mode", "on-click-right": "mode",
"on-click-forward": "tz_up", "on-click-forward": "tz_up",
"on-click-backward": "tz_down", "on-click-backward": "tz_down",
"on-scroll-up": "shift_up", "on-scroll-up": "shift_up",
"on-scroll-down": "shift_down" "on-scroll-down": "shift_down"
} }
}, },
``` ```
@ -205,10 +205,10 @@ View all valid format options in *strftime(3)* or have a look <https://fmt.dev/l
``` ```
"clock": { "clock": {
"interval": 60, "interval": 60,
"tooltip": true, "tooltip": true,
"format": "{:%H.%M}", "format": "{:%H.%M}",
"tooltip-format": "{:%Y-%m-%d}", "tooltip-format": "{:%Y-%m-%d}",
} }
``` ```
@ -238,31 +238,31 @@ 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",
"mode-mon-col" : 3, "mode-mon-col" : 3,
"weeks-pos" : "right", "weeks-pos" : "right",
"on-scroll" : 1, "on-scroll" : 1,
"on-click-right": "mode", "on-click-right": "mode",
"format": { "format": {
"months": "<span color='#ffead3'><b>{}</b></span>", "months": "<span color='#ffead3'><b>{}</b></span>",
"days": "<span color='#ecc6d9'><b>{}</b></span>", "days": "<span color='#ecc6d9'><b>{}</b></span>",
"weeks": "<span color='#99ffdd'><b>W{}</b></span>", "weeks": "<span color='#99ffdd'><b>W{}</b></span>",
"weekdays": "<span color='#ffcc66'><b>{}</b></span>", "weekdays": "<span color='#ffcc66'><b>{}</b></span>",
"today": "<span color='#ff6699'><b><u>{}</u></b></span>" "today": "<span color='#ff6699'><b><u>{}</u></b></span>"
} }
}, },
"actions": { "actions": {
"on-click-right": "mode", "on-click-right": "mode",
"on-click-forward": "tz_up", "on-click-forward": "tz_up",
"on-click-backward": "tz_down", "on-click-backward": "tz_down",
"on-scroll-up": "shift_up", "on-scroll-up": "shift_up",
"on-scroll-down": "shift_down" "on-scroll-down": "shift_down"
} }
}, },
``` ```
# AUTHOR # AUTHOR

View File

@ -30,12 +30,12 @@ The *cpu* module displays the current cpu utilization.
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++

View File

@ -1,4 +1,5 @@
waybar-custom(5) waybar-custom(5)
# NAME # NAME
waybar - custom module waybar - custom module
@ -18,13 +19,14 @@ Addressed by *custom/<name>*
*exec-if*: ++ *exec-if*: ++
typeof: string ++ typeof: string ++
The path to a script, which determines if the script in *exec* should be executed. ++ 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* will be executed if the exit code of *exec-if* equals 0.
*exec-on-event*: ++ *exec-on-event*: ++
typeof: bool ++ typeof: bool ++
default: true ++ 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. 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*: ++ *return-type*: ++
typeof: string ++ typeof: string ++
@ -32,19 +34,20 @@ Addressed by *custom/<name>*
*interval*: ++ *interval*: ++
typeof: integer ++ typeof: integer ++
The interval (in seconds) in which the information gets polled. ++ The interval (in seconds) in which the information gets polled.
Use *once* if you want to execute the module only on startup. ++ Use *once* if you want to execute the module only on startup.
You can update it manually with a signal. If no *interval* is defined, it is assumed that the out script loops it self. You can update it manually with a signal. If no *interval* is defined,
it is assumed that the out script loops it self.
*restart-interval*: ++ *restart-interval*: ++
typeof: integer ++ typeof: integer ++
The restart interval (in seconds). ++ The restart interval (in seconds).
Can't be used with the *interval* option, so only with continuous scripts. ++ Can't be used with the *interval* option, so only with continuous scripts.
Once the script exit, it'll be re-executed after the *restart-interval*. Once the script exit, it'll be re-executed after the *restart-interval*.
*signal*: ++ *signal*: ++
typeof: integer ++ typeof: integer ++
The signal number used to update the module. ++ The signal number used to update the module.
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*.
*format*: ++ *format*: ++
@ -65,12 +68,12 @@ Addressed by *custom/<name>*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++

View File

@ -40,12 +40,12 @@ Addressed by *disk*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++

View File

@ -13,24 +13,24 @@ The *tags* module displays the current state of tags in dwl.
Addressed by *dwl/tags* Addressed by *dwl/tags*
*num-tags*: ++ *num-tags*: ++
typeof: uint ++ typeof: uint ++
default: 9 ++ default: 9 ++
The number of tags that should be displayed. Max 32. The number of tags that should be displayed. Max 32.
*tag-labels*: ++ *tag-labels*: ++
typeof: array ++ typeof: array ++
The label to display for each tag. The label to display for each tag.
*disable-click*: ++ *disable-click*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled. If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled.
# EXAMPLE # EXAMPLE
``` ```
"dwl/tags": { "dwl/tags": {
"num-tags": 5 "num-tags": 5
} }
``` ```

View File

@ -18,12 +18,12 @@ Addressed by *hyprland/language*
The format, how information should be displayed. The format, how information should be displayed.
*format-<lang>* ++ *format-<lang>* ++
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.
*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.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
@ -41,10 +41,10 @@ Addressed by *hyprland/language*
``` ```
"hyprland/language": { "hyprland/language": {
"format": "Lang: {long}" "format": "Lang: {long}"
"format-en": "AMERICA, HELL YEAH!" "format-en": "AMERICA, HELL YEAH!"
"format-tr": "As bayrakları" "format-tr": "As bayrakları"
"keyboard-name": "at-translated-set-2-keyboard" "keyboard-name": "at-translated-set-2-keyboard"
} }
``` ```

View File

@ -26,12 +26,12 @@ Addressed by *hyprland/submap*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -71,9 +71,9 @@ Addressed by *hyprland/submap*
``` ```
"hyprland/submap": { "hyprland/submap": {
"format": "✌️ {}", "format": "✌️ {}",
"max-length": 8, "max-length": 8,
"tooltip": false "tooltip": false
} }
``` ```

View File

@ -25,16 +25,6 @@ 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.
*icon*: ++
typeof: bool ++
default: false ++
Option to hide the application icon.
*icon-size*: ++
typeof: integer ++
default: 24 ++
Option to change the size of the application icon.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
See the output of "hyprctl clients" for examples See the output of "hyprctl clients" for examples
@ -62,11 +52,11 @@ Invalid expressions (e.g., mismatched parentheses) are skipped.
``` ```
"hyprland/window": { "hyprland/window": {
"format": "{}", "format": "{}",
"rewrite": { "rewrite": {
"(.*) - Mozilla Firefox": "🌎 $1", "(.*) - Mozilla Firefox": "🌎 $1",
"(.*) - zsh": "> [$1]" "(.*) - zsh": "> [$1]"
} }
} }
``` ```

View File

@ -1,4 +1,4 @@
waybar-hyprland-workspaces(5) waybar-wlr-workspaces(5)
# NAME # NAME
@ -21,22 +21,10 @@ Addressed by *hyprland/workspaces*
typeof: array ++ typeof: array ++
Based on the workspace id and state, the corresponding icon gets selected. See *icons*. Based on the workspace id and state, the corresponding icon gets selected. See *icons*.
*show-special*: ++
typeof: bool ++
default: false ++
If set to true special workspaces will be shown.
*all-outputs*: ++
typeof: bool ++
default: false ++
If set to false workspaces group will be shown only in assigned output. Otherwise all workspace groups are shown.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{id}*: id of workspace assigned by compositor *{id}*: id of workspace assigned by compositor
*{name}*: workspace name assigned by compositor
*{icon}*: Icon, as defined in *format-icons*. *{icon}*: Icon, as defined in *format-icons*.
# ICONS # ICONS
@ -45,13 +33,11 @@ Additional to workspace name matching, the following *format-icons* can be set.
- *default*: Will be shown, when no string match is found. - *default*: Will be shown, when no string match is found.
- *active*: Will be shown, when workspace is active - *active*: Will be shown, when workspace is active
- *special*: Will be shown on non-active special workspaces
- *persistent*: Will be shown on non-active persistent workspaces
# EXAMPLES # EXAMPLES
``` ```
"hyprland/workspaces": { "wlr/workspaces": {
"format": "{name}: {icon}", "format": "{name}: {icon}",
"format-icons": { "format-icons": {
"1": "", "1": "",
@ -62,10 +48,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
"active": "", "active": "",
"default": "" "default": ""
}, },
"persistent_workspaces": { "sort-by-number": true
"*": 5, // 5 workspaces by default on every monitor
"HDMI-A-1": 3 // but only three on HDMI-A-1
}
} }
``` ```
@ -74,6 +57,3 @@ Additional to workspace name matching, the following *format-icons* can be set.
- *#workspaces* - *#workspaces*
- *#workspaces button* - *#workspaces button*
- *#workspaces button.active* - *#workspaces button.active*
- *#workspaces button.persistent*
- *#workspaces button.special*
- *#workspaces button.urgent*

View File

@ -28,12 +28,12 @@ screensaving, also known as "presentation mode".
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -64,9 +64,9 @@ screensaving, also known as "presentation mode".
Threshold to be used when scrolling. Threshold to be used when scrolling.
*start-activated*: ++ *start-activated*: ++
typeof: bool ++ typeof: bool ++
default: *false* ++ default: *false* ++
Whether the inhibit should be activated when starting waybar. Whether the inhibit should be activated when starting waybar.
*timeout*: ++ *timeout*: ++
typeof: double ++ typeof: double ++
@ -97,8 +97,8 @@ screensaving, also known as "presentation mode".
"idle_inhibitor": { "idle_inhibitor": {
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"activated": "", "activated": "",
"deactivated": "" "deactivated": ""
}, },
"timeout": 30.5 "timeout": 30.5
} }

View File

@ -13,26 +13,24 @@ The *image* module displays an image from a path.
*path*: ++ *path*: ++
typeof: string ++ typeof: string ++
The path to the image. The path to the image.
*exec*: ++ *exec*: ++
typeof: string ++ typeof: string ++
The path to the script, which should return image path file. ++ The path to the script, which should return image path file
It will only execute if the path is not set it will only execute if the path is not set
*size*: ++ *size*: ++
typeof: integer ++ typeof: integer ++
The width/height to render the image. The width/height to render the image.
*interval*: ++ *interval*: ++
typeof: integer ++ typeof: integer ++
The interval (in seconds) to re-render the image. ++ The interval (in seconds) to re-render the image.
This is useful if the contents of *path* changes. ++ This is useful if the contents of *path* changes.
If no *interval* is defined, the image will only be rendered once. If no *interval* is defined, the image will only be rendered once.
*signal*: ++ *signal*: ++
typeof: integer ++ typeof: integer ++
The signal number used to update the module. ++ The signal number used to update the module.
This can be used instead of *interval* if the file changes irregularly. ++ This can be used instead of *interval* if the file changes irregularly.
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*. The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*.
*on-click*: ++ *on-click*: ++

View File

@ -85,8 +85,8 @@ See *systemd-inhibit*(1) for more information.
"what": "handle-lid-switch", "what": "handle-lid-switch",
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"activated": "", "activated": "",
"deactivated": "" "deactivated": ""
} }
} }
``` ```

View File

@ -13,73 +13,73 @@ The *jack* module displays the current state of the JACK server.
Addressed by *jack* Addressed by *jack*
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: *{load}%* ++ default: *{load}%* ++
The format, how information should be displayed. This format is used when other formats aren't specified. The format, how information should be displayed. This format is used when other formats aren't specified.
*format-connected*: ++ *format-connected*: ++
typeof: string ++ typeof: string ++
This format is used when the module is connected to the JACK server. This format is used when the module is connected to the JACK server.
*format-disconnected*: ++ *format-disconnected*: ++
typeof: string ++ typeof: string ++
This format is used when the module is not connected to the JACK server. This format is used when the module is not connected to the JACK server.
*format-xrun*: ++ *format-xrun*: ++
typeof: string ++ typeof: string ++
This format is used for one polling interval, when the JACK server reports an xrun. This format is used for one polling interval, when the JACK server reports an xrun.
*realtime*: ++ *realtime*: ++
typeof: bool ++ typeof: bool ++
default: *true* ++ default: *true* ++
Option to drop real-time privileges for the JACK client opened by Waybar. Option to drop real-time privileges for the JACK client opened by Waybar.
*tooltip*: ++ *tooltip*: ++
typeof: bool ++ typeof: bool ++
default: *true* ++ default: *true* ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*tooltip-format*: ++ *tooltip-format*: ++
typeof: string ++ typeof: string ++
default: *{bufsize}/{samplerate} {latency}ms* ++ default: *{bufsize}/{samplerate} {latency}ms* ++
The format of information displayed in the tooltip. The format of information displayed in the tooltip.
*interval*: ++ *interval*: ++
typeof: integer ++ typeof: integer ++
default: 1 ++ default: 1 ++
The interval in which the information gets polled. The interval in which the information gets polled.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label. Positive value to rotate the text label.
*max-length*: ++ *max-length*: ++
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.
*on-click-middle*: ++ *on-click-middle*: ++
typeof: string ++ typeof: string ++
Command to execute when middle-clicked on the module using mousewheel. Command to execute when middle-clicked on the module using mousewheel.
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right clicked on the module.
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++
Command to execute when the module is updated. Command to execute when the module is updated.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
@ -97,10 +97,10 @@ Addressed by *jack*
``` ```
"jack": { "jack": {
"format": "DSP {}%", "format": "DSP {}%",
"format-xrun": "{xruns} xruns", "format-xrun": "{xruns} xruns",
"format-disconnected": "DSP off", "format-disconnected": "DSP off",
"realtime": true "realtime": true
} }
``` ```

View File

@ -48,11 +48,6 @@ You must be a member of the input group to use this module.
default: chooses first valid input device ++ default: chooses first valid input device ++
Which libevdev input device to show the state of. Libevdev devices can be found in /dev/input. The device should support number lock, caps lock, and scroll lock events. Which libevdev input device to show the state of. Libevdev devices can be found in /dev/input. The device should support number lock, caps lock, and scroll lock events.
*binding-keys*: ++
typeof: array ++
default: [58, 69, 70] ++
Customize the key to trigger this module, the key number can be find in /usr/include/linux/input-event-codes.h or running sudo libinput debug-events --show-keycodes.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
*{name}*: Caps, Num, or Scroll. *{name}*: Caps, Num, or Scroll.
@ -70,13 +65,13 @@ The following *format-icons* can be set.
``` ```
"keyboard-state": { "keyboard-state": {
"numlock": true, "numlock": true,
"capslock": true, "capslock": true,
"format": "{name} {icon}", "format": "{name} {icon}",
"format-icons": { "format-icons": {
"locked": "", "locked": "",
"unlocked": "" "unlocked": ""
} }
} }
``` ```

View File

@ -40,12 +40,12 @@ Addressed by *memory*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++

View File

@ -13,7 +13,8 @@ The *mpris* module displays currently playing media via libplayerctl.
*player*: ++ *player*: ++
typeof: string ++ typeof: string ++
default: playerctld ++ default: playerctld ++
Name of the MPRIS player to attach to. Using the default value always follows the currenly active player. Name of the MPRIS player to attach to. Using the default value always
follows the currenly active player.
*ignored-players*: ++ *ignored-players*: ++
typeof: []string ++ typeof: []string ++
@ -48,15 +49,18 @@ The *mpris* module displays currently playing media via libplayerctl.
*artist-len*: ++ *artist-len*: ++
typeof: integer ++ typeof: integer ++
Maximum length of the Artist tag (Wide/Fullwidth Unicode characters count as two). Set to zero to hide the artist in `{dynamic}` tag. Maximum length of the Artist tag (Wide/Fullwidth Unicode characters
count as two). Set to zero to hide the artist in `{dynamic}` tag.
*album-len*: ++ *album-len*: ++
typeof: integer ++ typeof: integer ++
Maximum length of the Album tag (Wide/Fullwidth Unicode characters count as two). Set to zero to hide the album in `{dynamic}` tag. Maximum length of the Album tag (Wide/Fullwidth Unicode characters count
as two). Set to zero to hide the album in `{dynamic}` tag.
*title-len*: ++ *title-len*: ++
typeof: integer ++ typeof: integer ++
Maximum length of the Title tag (Wide/Fullwidth Unicode characters count as two). Set to zero to hide the title in `{dynamic}` tag. Maximum length of the Title tag (Wide/Fullwidth Unicode characters count
as two). Set to zero to hide the title in `{dynamic}` tag.
*dynamic-len*: ++ *dynamic-len*: ++
typeof: integer ++ typeof: integer ++
@ -97,12 +101,14 @@ The *mpris* module displays currently playing media via libplayerctl.
*enable-tooltip-len-limits*: ++ *enable-tooltip-len-limits*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
Option to enable the length limits for the tooltip as well. By default the tooltip ignores all length limits. Option to enable the length limits for the tooltip as well. By default
the tooltip ignores all length limits.
*ellipsis*: ++ *ellipsis*: ++
typeof: string ++ typeof: string ++
default: "…" ++ default: "…" ++
This character will be used when any of the tags exceed their maximum length. If you don't want to use an ellipsis, set this to empty string. This character will be used when any of the tags exceed their maximum
length. If you don't want to use an ellipsis, set this to empty string.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
@ -118,7 +124,7 @@ The *mpris* module displays currently playing media via libplayerctl.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. ++ The alignment of the text, where 0 is left-aligned and 1 is right-aligned.
If the module is rotated, it will follow the flow of the text. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
@ -142,7 +148,8 @@ The *mpris* module displays currently playing media via libplayerctl.
*status-icons*: ++ *status-icons*: ++
typeof: map[string]string ++ typeof: map[string]string ++
Allows setting _{status-icon}_ based on player status (playing, paused, stopped). Allows setting _{status-icon}_ based on player status (playing, paused,
stopped).
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
@ -160,7 +167,7 @@ The *mpris* module displays currently playing media via libplayerctl.
*{length}*: Length of the track, formatted as HH:MM:SS *{length}*: Length of the track, formatted as HH:MM:SS
*{dynamic}*: Use _{artist}_, _{album}_, _{title}_ and _{length}_, automatically omit++ *{dynamic}*: Use _{artist}_, _{album}_, _{title}_ and _{length}_, automatically omit++
empty values empty values
*{player_icon}*: Chooses an icon from _player-icons_ based on _{player}_ *{player_icon}*: Chooses an icon from _player-icons_ based on _{player}_

View File

@ -65,12 +65,12 @@ Addressed by *network*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++

View File

@ -15,45 +15,45 @@ It may not be set until a layout is first applied.
Addressed by *river/layout* Addressed by *river/layout*
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: {} ++ default: {} ++
The format, how information should be displayed. On {} data gets inserted. The format, how information should be displayed. On {} data gets inserted.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label. Positive value to rotate the text label.
*max-length*: ++ *max-length*: ++
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.
*on-click-middle*: ++ *on-click-middle*: ++
typeof: string ++ typeof: string ++
Command to execute when middle-clicked on the module using mousewheel. Command to execute when middle-clicked on the module using mousewheel.
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right clicked on the module.
# EXAMPLE # EXAMPLE
``` ```
"river/layout": { "river/layout": {
"format": "{}", "format": "{}",
"min-length": 4, "min-length": 4,
"align": "right" "align": "right"
} }
``` ```

View File

@ -13,59 +13,59 @@ The *mode* module displays the current mapping mode of river.
Addressed by *river/mode* Addressed by *river/mode*
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: {} ++ default: {} ++
The format, how information should be displayed. On {} data gets inserted. The format, how information should be displayed. On {} data gets inserted.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label. Positive value to rotate the text label.
*max-length*: ++ *max-length*: ++
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.
*on-click-middle*: ++ *on-click-middle*: ++
typeof: string ++ typeof: string ++
Command to execute when middle-clicked on the module using mousewheel. Command to execute when middle-clicked on the module using mousewheel.
*on-click-right*: ++ *on-click-right*: ++
typeof: string ++ typeof: string ++
Command to execute when you right clicked on the module. Command to execute when you right clicked on the module.
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++
Command to execute when the module is updated. Command to execute when the module is updated.
*on-scroll-up*: ++ *on-scroll-up*: ++
typeof: string ++ typeof: string ++
Command to execute when scrolling up on the module. Command to execute when scrolling up on the module.
*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.
*smooth-scrolling-threshold*: ++ *smooth-scrolling-threshold*: ++
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
# EXAMPLES # EXAMPLES
``` ```
"river/mode": { "river/mode": {
"format": " {}" "format": " {}"
} }
``` ```

View File

@ -13,24 +13,24 @@ The *tags* module displays the current state of tags in river.
Addressed by *river/tags* Addressed by *river/tags*
*num-tags*: ++ *num-tags*: ++
typeof: uint ++ typeof: uint ++
default: 9 ++ default: 9 ++
The number of tags that should be displayed. Max 32. The number of tags that should be displayed. Max 32.
*tag-labels*: ++ *tag-labels*: ++
typeof: array ++ typeof: array ++
The label to display for each tag. The label to display for each tag.
*disable-click*: ++ *disable-click*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled. If set to false, you can left click to set focused tag. Right click to toggle tag focus. If set to true this behaviour is disabled.
# EXAMPLE # EXAMPLE
``` ```
"river/tags": { "river/tags": {
"num-tags": 5 "num-tags": 5
} }
``` ```

View File

@ -26,12 +26,12 @@ Addressed by *river/window*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -49,7 +49,7 @@ Addressed by *river/window*
``` ```
"river/window": { "river/window": {
"format": "{}" "format": "{}"
} }
``` ```

View File

@ -27,12 +27,12 @@ cursor is over the module, and clicking on the module toggles mute.
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*scroll-step*: ++ *scroll-step*: ++
typeof: int ++ typeof: int ++
@ -58,12 +58,12 @@ cursor is over the module, and clicking on the module toggles mute.
*on-scroll-up*: ++ *on-scroll-up*: ++
typeof: string ++ typeof: string ++
Command to execute when scrolling up on the module. ++ Command to execute when scrolling up on the module.
This replaces the default behaviour of volume control. This replaces the default behaviour of volume control.
*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.
This replaces the default behaviour of volume control. This replaces the default behaviour of volume control.
*smooth-scrolling-threshold*: ++ *smooth-scrolling-threshold*: ++
@ -80,8 +80,8 @@ cursor is over the module, and clicking on the module toggles mute.
``` ```
"sndio": { "sndio": {
"format": "{raw_value} 🎜", "format": "{raw_value} 🎜",
"scroll-step": 3 "scroll-step": 3
} }
``` ```

View File

@ -1,9 +1,5 @@
waybar-states(5) waybar-states(5)
# NAME
waybar - states property
# OVERVIEW # OVERVIEW
Some modules support 'states' which allows percentage values to be used as styling triggers to Some modules support 'states' which allows percentage values to be used as styling triggers to

View File

@ -43,11 +43,11 @@ Addressed by *sway/language*
``` ```
"sway/language": { "sway/language": {
"format": "{}", "format": "{}",
}, },
"sway/language": { "sway/language": {
"format": "{short} {variant}", "format": "{short} {variant}",
} }
``` ```

View File

@ -26,12 +26,12 @@ Addressed by *sway/mode*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -70,8 +70,8 @@ Addressed by *sway/mode*
``` ```
"sway/mode": { "sway/mode": {
"format": " {}", "format": " {}",
"max-length": 50 "max-length": 50
} }
``` ```

View File

@ -50,11 +50,11 @@ Addressed by *sway/scratchpad*
``` ```
"sway/scratchpad": { "sway/scratchpad": {
"format": "{icon} {count}", "format": "{icon} {count}",
"show-empty": false, "show-empty": false,
"format-icons": ["", ""], "format-icons": ["", ""],
"tooltip": true, "tooltip": true,
"tooltip-format": "{app}: {title}" "tooltip-format": "{app}: {title}"
} }
``` ```

View File

@ -26,12 +26,12 @@ Addressed by *sway/window*
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
@ -124,12 +124,12 @@ Invalid expressions (e.g., mismatched parentheses) are skipped.
``` ```
"sway/window": { "sway/window": {
"format": "{}", "format": "{}",
"max-length": 50, "max-length": 50,
"rewrite": { "rewrite": {
"(.*) - Mozilla Firefox": "🌎 $1", "(.*) - Mozilla Firefox": "🌎 $1",
"(.*) - zsh": "> [$1]" "(.*) - zsh": "> [$1]"
} }
} }
``` ```

View File

@ -13,74 +13,74 @@ The *workspaces* module displays the currently used workspaces in Sway.
Addressed by *sway/workspaces* Addressed by *sway/workspaces*
*all-outputs*: ++ *all-outputs*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false, workspaces will only be shown on the output they are on. If set to true all workspaces will be shown on every output. If set to false, workspaces will only be shown on the output they are on. If set to true all workspaces will be shown on every output.
*format*: ++ *format*: ++
typeof: string ++ typeof: string ++
default: {value} ++ default: {value} ++
The format, how information should be displayed. The format, how information should be displayed.
*format-icons*: ++ *format-icons*: ++
typeof: array ++ typeof: array ++
Based on the workspace name and state, the corresponding icon gets selected. See *icons*. Based on the workspace name and state, the corresponding icon gets selected. See *icons*.
*disable-scroll*: ++ *disable-scroll*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false, you can scroll to cycle through workspaces. If set to true this behaviour is disabled. If set to false, you can scroll to cycle through workspaces. If set to true this behaviour is disabled.
*disable-click*: ++ *disable-click*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false, you can click to change workspace. If set to true this behaviour is disabled. If set to false, you can click to change workspace. If set to true this behaviour is disabled.
*smooth-scrolling-threshold*: ++ *smooth-scrolling-threshold*: ++
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
*disable-scroll-wraparound*: ++ *disable-scroll-wraparound*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to false, scrolling on the workspace indicator will wrap around to the first workspace when reading the end, and vice versa. If set to true this behavior is disabled. If set to false, scrolling on the workspace indicator will wrap around to the first workspace when reading the end, and vice versa. If set to true this behavior is disabled.
*enable-bar-scroll*: ++ *enable-bar-scroll*: ++
typeof: bool ++ typeof: bool ++
default: false ++ 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. If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
*disable-markup*: ++ *disable-markup*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to true, button label will escape pango markup. If set to true, button label will escape pango markup.
*current-only*: ++ *current-only*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
If set to true. Only focused workspaces will be shown. If set to true. Only focused workspaces will be shown.
*persistent_workspaces*: ++ *persistent_workspaces*: ++
typeof: json (see below) ++ typeof: json (see below) ++
default: empty ++ default: empty ++
Lists workspaces that should always be shown, even when non existent Lists workspaces that should always be shown, even when non existent
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++
Command to execute when the module is updated. Command to execute when the module is updated.
*disable-auto-back-and-forth*: ++ *disable-auto-back-and-forth*: ++
typeof: bool ++ typeof: bool ++
Whether to disable *workspace_auto_back_and_forth* when clicking on workspaces. If this is set to *true*, clicking on a workspace you are already on won't do anything, even if *workspace_auto_back_and_forth* is enabled in the Sway configuration. Whether to disable *workspace_auto_back_and_forth* when clicking on workspaces. If this is set to *true*, clicking on a workspace you are already on won't do anything, even if *workspace_auto_back_and_forth* is enabled in the Sway configuration.
*alphabetical_sort*: ++ *alphabetical_sort*: ++
typeof: bool ++ typeof: bool ++
Whether to sort workspaces alphabetically. Please note this can make "swaymsg workspace prev/next" move to workspaces inconsistent with the ordering shown in Waybar. Whether to sort workspaces alphabetically. Please note this can make "swaymsg workspace prev/next" move to workspaces inconsistent with the ordering shown in Waybar.
warp-on-scroll: ++ warp-on-scroll: ++
typeof: bool ++ typeof: bool ++
default: true ++ default: true ++
If set to false, you can scroll to cycle through workspaces without mouse warping being enabled. If set to true this behaviour is disabled. If set to false, you can scroll to cycle through workspaces without mouse warping being enabled. If set to true this behaviour is disabled.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS
@ -102,7 +102,6 @@ Additional to workspace name matching, the following *format-icons* can be set.
- *urgent*: Will be shown, when workspace is flagged as urgent - *urgent*: Will be shown, when workspace is flagged as urgent
- *focused*: Will be shown, when workspace is focused - *focused*: Will be shown, when workspace is focused
- *persistent*: Will be shown, when workspace is persistent one. - *persistent*: Will be shown, when workspace is persistent one.
- *high-priority-named*: Icons by names will be shown always for that workspaces, independent by state.
# PERSISTENT WORKSPACES # PERSISTENT WORKSPACES
@ -112,11 +111,11 @@ an empty list denoting all outputs.
``` ```
"sway/workspaces": { "sway/workspaces": {
"persistent_workspaces": { "persistent_workspaces": {
"3": [], // Always show a workspace with name '3', on all outputs if it does not exists "3": [], // Always show a workspace with name '3', on all outputs if it does not exists
"4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exists "4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exists
"5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exists "5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exists
} }
} }
``` ```
@ -126,20 +125,19 @@ n.b.: the list of outputs can be obtained from command line using *swaymsg -t ge
``` ```
"sway/workspaces": { "sway/workspaces": {
"disable-scroll": true, "disable-scroll": true,
"all-outputs": true, "all-outputs": true,
"format": "{name}: {icon}", "format": "{name}: {icon}",
"format-icons": { "format-icons": {
"1": "", "1": "",
"2": "", "2": "",
"3": "", "3": "",
"4": "", "4": "",
"5": "", "5": "",
"high-priority-named": [ "1", "2" ], "urgent": "",
"urgent": "", "focused": "",
"focused": "", "default": ""
"default": "" }
}
} }
``` ```

View File

@ -66,12 +66,12 @@ Addressed by *temperature*
The maximum length in characters the module should display. The maximum length in characters the module should display.
*min-length*: ++ *min-length*: ++
typeof: integer ++ typeof: integer ++
The minimum length in characters the module should take up. The minimum length in characters the module should take up.
*align*: ++ *align*: ++
typeof: float ++ typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text. The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++

View File

@ -6,32 +6,32 @@ waybar - tray module
# DESCRIPTION # DESCRIPTION
_WARNING_ *tray* is still in beta. There may be bugs. Breaking changes may occur. _WARNING_ *tray* is still in beta. There may me bugs. Breaking changes may occur.
# CONFIGURATION # CONFIGURATION
Addressed by *tray* Addressed by *tray*
*icon-size*: ++ *icon-size*: ++
typeof: integer ++ typeof: integer ++
Defines the size of the tray icons. Defines the size of the tray icons.
*show-passive-items*: ++ *show-passive-items*: ++
typeof: bool ++ typeof: bool ++
default: false ++ default: false ++
Defines visibility of the tray icons with *Passive* status. Defines visibility of the tray icons with *Passive* status.
*smooth-scrolling-threshold*: ++ *smooth-scrolling-threshold*: ++
typeof: double ++ typeof: double ++
Threshold to be used when scrolling. Threshold to be used when scrolling.
*spacing*: ++ *spacing*: ++
typeof: integer ++ typeof: integer ++
Defines the spacing between the tray icons. Defines the spacing between the tray icons.
*reverse-direction*: ++ *reverse-direction*: ++
typeof: bool ++ typeof: bool ++
Defines if new app icons should be added in a reverse order Defines if new app icons should be added in a reverse order
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++
@ -41,8 +41,8 @@ Addressed by *tray*
``` ```
"tray": { "tray": {
"icon-size": 21, "icon-size": 21,
"spacing": 10 "spacing": 10
} }
``` ```

View File

@ -12,10 +12,10 @@ compatible devices in the tooltip.
# CONFIGURATION # CONFIGURATION
*native-path*: ++ *native-path*: ++
typeof: string ++ typeof: string ++
default: ++ default: ++
The battery to monitor. Refer to the https://upower.freedesktop.org/docs/UpDevice.html#UpDevice--native-path ++ The battery to monitor. Refer to the https://upower.freedesktop.org/docs/UpDevice.html#UpDevice--native-path ++
Can be obtained using `upower --dump` Can be obtained using `upower --dump`
*icon-size*: ++ *icon-size*: ++
typeof: integer ++ typeof: integer ++

View File

@ -93,9 +93,9 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
``` ```
"wireplumber": { "wireplumber": {
"format": "{volume}%", "format": "{volume}%",
"format-muted": "", "format-muted": "",
"on-click": "helvum" "on-click": "helvum"
} }
``` ```

View File

@ -2,7 +2,7 @@ waybar-wlr-taskbar(5)
# NAME # NAME
waybar - wlr taskbar module wlroots - Taskbar module
# DESCRIPTION # DESCRIPTION

View File

@ -29,8 +29,9 @@ Addressed by *wlr/workspaces*
*sort-by-coordinates*: ++ *sort-by-coordinates*: ++
typeof: bool ++ typeof: bool ++
default: true ++ default: true ++
Should workspaces be sorted by coordinates. ++ Should workspaces be sorted by coordinates.
Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first. If both are false - sort by id will be performed. Note that if both *sort-by-name* and *sort-by-coordinates* are true sort by name will be first.
If both are false - sort by id will be performed.
*sort-by-number*: ++ *sort-by-number*: ++
typeof: bool ++ typeof: bool ++

View File

@ -268,7 +268,6 @@ Valid options for the (optional) "orientation" property are: "horizontal", "vert
- *waybar-backlight(5)* - *waybar-backlight(5)*
- *waybar-battery(5)* - *waybar-battery(5)*
- *waybar-bluetooth(5)* - *waybar-bluetooth(5)*
- *waybar-cava(5)*
- *waybar-clock(5)* - *waybar-clock(5)*
- *waybar-cpu(5)* - *waybar-cpu(5)*
- *waybar-custom(5)* - *waybar-custom(5)*

View File

@ -1,10 +1,10 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.9.22', version: '0.9.20',
license: 'MIT', license: 'MIT',
meson_version: '>= 0.50.0', meson_version: '>= 0.50.0',
default_options : [ default_options : [
'cpp_std=c++20', 'cpp_std=c++17',
'buildtype=release', 'buildtype=release',
'default_library=static' 'default_library=static'
], ],
@ -346,7 +346,7 @@ if get_option('experimental')
endif endif
cava = dependency('cava', cava = dependency('cava',
version : '>=0.8.5', version : '>=0.8.4',
required: get_option('cava'), required: get_option('cava'),
fallback : ['cava', 'cava_dep'], fallback : ['cava', 'cava_dep'],
not_found_message: 'cava is not found. Building waybar without cava') not_found_message: 'cava is not found. Building waybar without cava')
@ -423,7 +423,6 @@ if scdoc.found()
main_manpage_path, main_manpage_path,
'waybar-backlight.5.scd', 'waybar-backlight.5.scd',
'waybar-battery.5.scd', 'waybar-battery.5.scd',
'waybar-cava.5.scd',
'waybar-clock.5.scd', 'waybar-clock.5.scd',
'waybar-cpu.5.scd', 'waybar-cpu.5.scd',
'waybar-custom.5.scd', 'waybar-custom.5.scd',

View File

@ -1,158 +1,89 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import gi
gi.require_version("Playerctl", "2.0")
from gi.repository import Playerctl, GLib
from gi.repository.Playerctl import Player
import argparse import argparse
import logging import logging
import sys import sys
import signal import signal
import gi import gi
import json import json
import os gi.require_version('Playerctl', '2.0')
from typing import List from gi.repository import Playerctl, GLib
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def write_output(text, player):
logger.info('Writing output')
output = {'text': text,
'class': 'custom-' + player.props.player_name,
'alt': player.props.player_name}
sys.stdout.write(json.dumps(output) + '\n')
sys.stdout.flush()
def on_play(player, status, manager):
logger.info('Received new playback status')
on_metadata(player, player.props.metadata, manager)
def on_metadata(player, metadata, manager):
logger.info('Received new metadata')
track_info = ''
if player.props.player_name == 'spotify' and \
'mpris:trackid' in metadata.keys() and \
':ad:' in player.props.metadata['mpris:trackid']:
track_info = 'AD PLAYING'
elif player.get_artist() != '' and player.get_title() != '':
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
title=player.get_title())
else:
track_info = player.get_title()
if player.props.status != 'Playing' and track_info:
track_info = '' + track_info
write_output(track_info, player)
def on_player_appeared(manager, player, selected_player=None):
if player is not None and (selected_player is None or player.name == selected_player):
init_player(manager, player)
else:
logger.debug("New player appeared, but it's not the selected player, skipping")
def on_player_vanished(manager, player):
logger.info('Player has vanished')
sys.stdout.write('\n')
sys.stdout.flush()
def init_player(manager, name):
logger.debug('Initialize player: {player}'.format(player=name.name))
player = Playerctl.Player.new_from_name(name)
player.connect('playback-status', on_play, manager)
player.connect('metadata', on_metadata, manager)
manager.manage_player(player)
on_metadata(player, player.props.metadata, manager)
def signal_handler(sig, frame): def signal_handler(sig, frame):
logger.info("Received signal to stop, exiting") logger.debug('Received signal to stop, exiting')
sys.stdout.write("\n") sys.stdout.write('\n')
sys.stdout.flush() sys.stdout.flush()
# loop.quit() # loop.quit()
sys.exit(0) sys.exit(0)
class PlayerManager:
def __init__(self, selected_player=None):
self.manager = Playerctl.PlayerManager()
self.loop = GLib.MainLoop()
self.manager.connect(
"name-appeared", lambda *args: self.on_player_appeared(*args))
self.manager.connect(
"player-vanished", lambda *args: self.on_player_vanished(*args))
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
self.selected_player = selected_player
self.init_players()
def init_players(self):
for player in self.manager.props.player_names:
if self.selected_player is not None and self.selected_player != player.name:
logger.debug(f"{player.name} is not the filtered player, skipping it")
continue
self.init_player(player)
def run(self):
logger.info("Starting main loop")
self.loop.run()
def init_player(self, player):
logger.info(f"Initialize new player: {player.name}")
player = Playerctl.Player.new_from_name(player)
player.connect("playback-status",
self.on_playback_status_changed, None)
player.connect("metadata", self.on_metadata_changed, None)
self.manager.manage_player(player)
self.on_metadata_changed(player, player.props.metadata)
def get_players(self) -> List[Player]:
return self.manager.props.players
def write_output(self, text, player):
logger.debug(f"Writing output: {text}")
output = {"text": text,
"class": "custom-" + player.props.player_name,
"alt": player.props.player_name}
sys.stdout.write(json.dumps(output) + "\n")
sys.stdout.flush()
def clear_output(self):
sys.stdout.write("\n")
sys.stdout.flush()
def on_playback_status_changed(self, player, status, _=None):
logger.debug(f"Playback status changed for player {player.props.player_name}: {status}")
self.on_metadata_changed(player, player.props.metadata)
def get_first_playing_player(self):
players = self.get_players()
logger.debug(f"Getting first playing player from {len(players)} players")
if len(players) > 0:
# if any are playing, show the first one that is playing
# reverse order, so that the most recently added ones are preferred
for player in players[::-1]:
if player.props.status == "Playing":
return player
# if none are playing, show the first one
return players[0]
else:
logger.debug("No players found")
return None
def show_most_important_player(self):
logger.debug("Showing most important player")
# show the currently playing player
# or else show the first paused player
# or else show nothing
current_player = self.get_first_playing_player()
if current_player is not None:
self.on_metadata_changed(current_player, current_player.props.metadata)
else:
self.clear_output()
def on_metadata_changed(self, player, metadata, _=None):
logger.debug(f"Metadata changed for player {player.props.player_name}")
player_name = player.props.player_name
artist = player.get_artist()
title = player.get_title()
track_info = ""
if player_name == "spotify" and "mpris:trackid" in metadata.keys() and ":ad:" in player.props.metadata["mpris:trackid"]:
track_info = "Advertisement"
elif artist is not None and title is not None:
track_info = f"{artist} - {title}"
else:
track_info = title
if track_info:
if player.props.status == "Playing":
track_info = "" + track_info
else:
track_info = "" + track_info
# only print output if no other player is playing
current_playing = self.get_first_playing_player()
if current_playing is None or current_playing.props.player_name == player.props.player_name:
self.write_output(track_info, player)
else:
logger.debug(f"Other player {current_playing.props.player_name} is playing, skipping")
def on_player_appeared(self, _, player):
logger.info(f"Player has appeared: {player.name}")
if player is not None and (self.selected_player is None or player.name == self.selected_player):
self.init_player(player)
else:
logger.debug(
"New player appeared, but it's not the selected player, skipping")
def on_player_vanished(self, _, player):
logger.info(f"Player {player.props.player_name} has vanished")
self.show_most_important_player()
def parse_arguments(): def parse_arguments():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
# Increase verbosity with every occurrence of -v # Increase verbosity with every occurrence of -v
parser.add_argument("-v", "--verbose", action="count", default=0) parser.add_argument('-v', '--verbose', action='count', default=0)
# Define for which player we"re listening # Define for which player we're listening
parser.add_argument("--player") parser.add_argument('--player')
parser.add_argument("--enable-logging", action="store_true")
return parser.parse_args() return parser.parse_args()
@ -161,22 +92,37 @@ def main():
arguments = parse_arguments() arguments = parse_arguments()
# Initialize logging # Initialize logging
if arguments.enable_logging: logging.basicConfig(stream=sys.stderr, level=logging.DEBUG,
logfile = os.path.join(os.path.dirname( format='%(name)s %(levelname)s %(message)s')
os.path.realpath(__file__)), "media-player.log")
logging.basicConfig(filename=logfile, level=logging.DEBUG,
format="%(asctime)s %(name)s %(levelname)s:%(lineno)d %(message)s")
# Logging is set by default to WARN and higher. # Logging is set by default to WARN and higher.
# With every occurrence of -v it's lowered by one # With every occurrence of -v it's lowered by one
logger.setLevel(max((3 - arguments.verbose) * 10, 0)) logger.setLevel(max((3 - arguments.verbose) * 10, 0))
logger.info("Creating player manager") # Log the sent command line arguments
if arguments.player: logger.debug('Arguments received {}'.format(vars(arguments)))
logger.info(f"Filtering for player: {arguments.player}")
player = PlayerManager(arguments.player) manager = Playerctl.PlayerManager()
player.run() loop = GLib.MainLoop()
manager.connect('name-appeared', lambda *args: on_player_appeared(*args, arguments.player))
manager.connect('player-vanished', on_player_vanished)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
for player in manager.props.player_names:
if arguments.player is not None and arguments.player != player.name:
logger.debug('{player} is not the filtered player, skipping it'
.format(player=player.name)
)
continue
init_player(manager, player)
loop.run()
if __name__ == "__main__": if __name__ == '__main__':
main() main()

View File

@ -92,30 +92,28 @@ waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value&
std::back_inserter(device_preference_), [](auto x) { return x.asString(); }); std::back_inserter(device_preference_), [](auto x) { return x.asString(); });
} }
// NOTE: assumption made that the controller that is selected stays unchanged // NOTE: assumption made that the controller that is selcected stays unchanged
// for duration of the module // for duration of the module
if (cur_controller_ = findCurController(); !cur_controller_) { if (!findCurController(cur_controller_)) {
if (config_["controller-alias"].isString()) { if (config_["controller-alias"].isString()) {
spdlog::error("findCurController() failed: no bluetooth controller found with alias '{}'", spdlog::error("findCurController() failed: no bluetooth controller found with alias '{}'",
config_["controller-alias"].asString()); config_["controller-alias"].asString());
} else { } else {
spdlog::error("findCurController() failed: no bluetooth controller found"); spdlog::error("findCurController() failed: no bluetooth controller found");
} }
update(); event_box_.hide();
} else { return;
// These calls only make sense if a controller could be found
findConnectedDevices(cur_controller_->path, connected_devices_);
g_signal_connect(manager_.get(), "interface-proxy-properties-changed",
G_CALLBACK(onInterfaceProxyPropertiesChanged), this);
g_signal_connect(manager_.get(), "interface-added", G_CALLBACK(onInterfaceAddedOrRemoved),
this);
g_signal_connect(manager_.get(), "interface-removed", G_CALLBACK(onInterfaceAddedOrRemoved),
this);
#ifdef WANT_RFKILL
rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update)));
#endif
} }
findConnectedDevices(cur_controller_.path, connected_devices_);
g_signal_connect(manager_.get(), "interface-proxy-properties-changed",
G_CALLBACK(onInterfaceProxyPropertiesChanged), this);
g_signal_connect(manager_.get(), "interface-added", G_CALLBACK(onInterfaceAddedOrRemoved), this);
g_signal_connect(manager_.get(), "interface-removed", G_CALLBACK(onInterfaceAddedOrRemoved),
this);
#ifdef WANT_RFKILL
rfkill_.on_update.connect(sigc::hide(sigc::mem_fun(*this, &Bluetooth::update)));
#endif
dp.emit(); dp.emit();
} }
@ -146,16 +144,12 @@ auto waybar::modules::Bluetooth::update() -> void {
std::string state; std::string state;
std::string tooltip_format; std::string tooltip_format;
if (cur_controller_) { if (!cur_controller_.powered)
if (!cur_controller_->powered) state = "off";
state = "off"; else if (!connected_devices_.empty())
else if (!connected_devices_.empty()) state = "connected";
state = "connected"; else
else state = "on";
state = "on";
} else {
state = "no-controller";
}
#ifdef WANT_RFKILL #ifdef WANT_RFKILL
if (rfkill_.getState()) state = "disabled"; if (rfkill_.getState()) state = "disabled";
#endif #endif
@ -193,6 +187,8 @@ auto waybar::modules::Bluetooth::update() -> void {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
format_.empty() ? event_box_.hide() : event_box_.show();
auto update_style_context = [this](const std::string& style_class, bool in_next_state) { auto update_style_context = [this](const std::string& style_class, bool in_next_state) {
if (in_next_state && !label_.get_style_context()->has_class(style_class)) { if (in_next_state && !label_.get_style_context()->has_class(style_class)) {
label_.get_style_context()->add_class(style_class); label_.get_style_context()->add_class(style_class);
@ -200,32 +196,25 @@ auto waybar::modules::Bluetooth::update() -> void {
label_.get_style_context()->remove_class(style_class); label_.get_style_context()->remove_class(style_class);
} }
}; };
update_style_context("discoverable", cur_controller_ ? cur_controller_->discoverable : false); update_style_context("discoverable", cur_controller_.discoverable);
update_style_context("discovering", cur_controller_ ? cur_controller_->discovering : false); update_style_context("discovering", cur_controller_.discovering);
update_style_context("pairable", cur_controller_ ? cur_controller_->pairable : false); update_style_context("pairable", cur_controller_.pairable);
if (!state_.empty()) { if (!state_.empty()) {
update_style_context(state_, false); update_style_context(state_, false);
} }
update_style_context(state, true); update_style_context(state, true);
state_ = state; state_ = state;
if (format_.empty()) { label_.set_markup(fmt::format(
event_box_.hide(); fmt::runtime(format_), fmt::arg("status", state_),
} else { fmt::arg("num_connections", connected_devices_.size()),
event_box_.show(); fmt::arg("controller_address", cur_controller_.address),
label_.set_markup(fmt::format( fmt::arg("controller_address_type", cur_controller_.address_type),
fmt::runtime(format_), fmt::arg("status", state_), fmt::arg("controller_alias", cur_controller_.alias),
fmt::arg("num_connections", connected_devices_.size()), fmt::arg("device_address", cur_focussed_device_.address),
fmt::arg("controller_address", cur_controller_ ? cur_controller_->address : "null"), fmt::arg("device_address_type", cur_focussed_device_.address_type),
fmt::arg("controller_address_type", fmt::arg("device_alias", cur_focussed_device_.alias), fmt::arg("icon", icon_label),
cur_controller_ ? cur_controller_->address_type : "null"), fmt::arg("device_battery_percentage", cur_focussed_device_.battery_percentage.value_or(0))));
fmt::arg("controller_alias", cur_controller_ ? cur_controller_->alias : "null"),
fmt::arg("device_address", cur_focussed_device_.address),
fmt::arg("device_address_type", cur_focussed_device_.address_type),
fmt::arg("device_alias", cur_focussed_device_.alias), fmt::arg("icon", icon_label),
fmt::arg("device_battery_percentage",
cur_focussed_device_.battery_percentage.value_or(0))));
}
if (tooltipEnabled()) { if (tooltipEnabled()) {
bool tooltip_enumerate_connections_ = config_["tooltip-format-enumerate-connected"].isString(); bool tooltip_enumerate_connections_ = config_["tooltip-format-enumerate-connected"].isString();
@ -261,10 +250,9 @@ auto waybar::modules::Bluetooth::update() -> void {
label_.set_tooltip_text(fmt::format( label_.set_tooltip_text(fmt::format(
fmt::runtime(tooltip_format), fmt::arg("status", state_), fmt::runtime(tooltip_format), fmt::arg("status", state_),
fmt::arg("num_connections", connected_devices_.size()), fmt::arg("num_connections", connected_devices_.size()),
fmt::arg("controller_address", cur_controller_ ? cur_controller_->address : "null"), fmt::arg("controller_address", cur_controller_.address),
fmt::arg("controller_address_type", fmt::arg("controller_address_type", cur_controller_.address_type),
cur_controller_ ? cur_controller_->address_type : "null"), fmt::arg("controller_alias", cur_controller_.alias),
fmt::arg("controller_alias", cur_controller_ ? cur_controller_->alias : "null"),
fmt::arg("device_address", cur_focussed_device_.address), fmt::arg("device_address", cur_focussed_device_.address),
fmt::arg("device_address_type", cur_focussed_device_.address_type), fmt::arg("device_address_type", cur_focussed_device_.address_type),
fmt::arg("device_alias", cur_focussed_device_.alias), fmt::arg("icon", icon_tooltip), fmt::arg("device_alias", cur_focussed_device_.alias), fmt::arg("icon", icon_tooltip),
@ -304,8 +292,8 @@ auto waybar::modules::Bluetooth::onInterfaceProxyPropertiesChanged(
Bluetooth* bt = static_cast<Bluetooth*>(user_data); Bluetooth* bt = static_cast<Bluetooth*>(user_data);
if (interface_name == "org.bluez.Adapter1") { if (interface_name == "org.bluez.Adapter1") {
if (object_path == bt->cur_controller_->path) { if (object_path == bt->cur_controller_.path) {
bt->getControllerProperties(G_DBUS_OBJECT(object_proxy), *bt->cur_controller_); bt->getControllerProperties(G_DBUS_OBJECT(object_proxy), bt->cur_controller_);
bt->dp.emit(); bt->dp.emit();
} }
} else if (interface_name == "org.bluez.Device1" || interface_name == "org.bluez.Battery1") { } else if (interface_name == "org.bluez.Device1" || interface_name == "org.bluez.Battery1") {
@ -390,23 +378,22 @@ auto waybar::modules::Bluetooth::getControllerProperties(GDBusObject* object,
return false; return false;
} }
auto waybar::modules::Bluetooth::findCurController() -> std::optional<ControllerInfo> { auto waybar::modules::Bluetooth::findCurController(ControllerInfo& controller_info) -> bool {
std::optional<ControllerInfo> controller_info; bool found_controller = false;
GList* objects = g_dbus_object_manager_get_objects(manager_.get()); GList* objects = g_dbus_object_manager_get_objects(manager_.get());
for (GList* l = objects; l != NULL; l = l->next) { for (GList* l = objects; l != NULL; l = l->next) {
GDBusObject* object = G_DBUS_OBJECT(l->data); GDBusObject* object = G_DBUS_OBJECT(l->data);
ControllerInfo info; if (getControllerProperties(object, controller_info) &&
if (getControllerProperties(object, info) &&
(!config_["controller-alias"].isString() || (!config_["controller-alias"].isString() ||
config_["controller-alias"].asString() == info.alias)) { config_["controller-alias"].asString() == controller_info.alias)) {
controller_info = std::move(info); found_controller = true;
break; break;
} }
} }
g_list_free_full(objects, g_object_unref); g_list_free_full(objects, g_object_unref);
return controller_info; return found_controller;
} }
auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_controller_path, auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_controller_path,
@ -417,7 +404,7 @@ auto waybar::modules::Bluetooth::findConnectedDevices(const std::string& cur_con
GDBusObject* object = G_DBUS_OBJECT(l->data); GDBusObject* object = G_DBUS_OBJECT(l->data);
DeviceInfo device; DeviceInfo device;
if (getDeviceProperties(object, device) && device.connected && if (getDeviceProperties(object, device) && device.connected &&
device.paired_controller == cur_controller_->path) { device.paired_controller == cur_controller_.path) {
connected_devices.push_back(device); connected_devices.push_back(device);
} }
} }

View File

@ -17,15 +17,15 @@
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true), : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
current_time_zone_idx_{0}, current_time_zone_idx_(0),
is_calendar_in_tooltip_{false}, is_calendar_in_tooltip_(false),
is_timezoned_list_in_tooltip_{false} { is_timezoned_list_in_tooltip_(false) {
if (config_["timezones"].isArray() && !config_["timezones"].empty()) { if (config_["timezones"].isArray() && !config_["timezones"].empty()) {
for (const auto& zone_name : config_["timezones"]) { for (const auto& zone_name : config_["timezones"]) {
if (!zone_name.isString()) continue; if (!zone_name.isString()) continue;
if (zone_name.asString().empty()) if (zone_name.asString().empty())
// local time should be shown // nullptr means that local time should be shown
time_zones_.push_back(date::current_zone()); time_zones_.push_back(nullptr);
else else
try { try {
time_zones_.push_back(date::locate_zone(zone_name.asString())); time_zones_.push_back(date::locate_zone(zone_name.asString()));
@ -35,7 +35,8 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
} }
} else if (config_["timezone"].isString()) { } else if (config_["timezone"].isString()) {
if (config_["timezone"].asString().empty()) if (config_["timezone"].asString().empty())
time_zones_.push_back(date::current_zone()); // nullptr means that local time should be shown
time_zones_.push_back(nullptr);
else else
try { try {
time_zones_.push_back(date::locate_zone(config_["timezone"].asString())); time_zones_.push_back(date::locate_zone(config_["timezone"].asString()));
@ -46,18 +47,17 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
// If all timezones are parsed and no one is good // If all timezones are parsed and no one is good
if (!time_zones_.size()) { if (!time_zones_.size()) {
time_zones_.push_back(date::current_zone()); // nullptr means that local time should be shown
time_zones_.push_back(nullptr);
} }
// Check if a particular placeholder is present in the tooltip format, to know what to calculate // Check if a particular placeholder is present in the tooltip format, to know what to calculate
// on update. // on update.
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
std::string trimmed_format{config_["tooltip-format"].asString()}; std::string trimmed_format = config_["tooltip-format"].asString();
fmtMap_.insert({5, trimmed_format});
trimmed_format.erase(std::remove_if(trimmed_format.begin(), trimmed_format.end(), trimmed_format.erase(std::remove_if(trimmed_format.begin(), trimmed_format.end(),
[](unsigned char x) { return std::isspace(x); }), [](unsigned char x) { return std::isspace(x); }),
trimmed_format.end()); trimmed_format.end());
if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) { if (trimmed_format.find("{" + kCalendarPlaceholder + "}") != std::string::npos) {
is_calendar_in_tooltip_ = true; is_calendar_in_tooltip_ = true;
} }
@ -158,35 +158,52 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
} }
const date::time_zone* waybar::modules::Clock::current_timezone() { const date::time_zone* waybar::modules::Clock::current_timezone() {
return time_zones_[current_time_zone_idx_]; return is_timezone_fixed() ? time_zones_[current_time_zone_idx_] : date::current_zone();
}
bool waybar::modules::Clock::is_timezone_fixed() {
return time_zones_[current_time_zone_idx_] != nullptr;
} }
auto waybar::modules::Clock::update() -> void { auto waybar::modules::Clock::update() -> void {
const auto* tz{current_timezone()}; const auto* time_zone = current_timezone();
const date::zoned_time now{ auto now = std::chrono::system_clock::now();
tz, auto ztime = date::zoned_time{time_zone, date::floor<std::chrono::seconds>(now)};
date::floor<std::chrono::seconds>(
std::chrono::system_clock::now())}; // Define local time is based on provided time zone
const date::year_month_day today{
date::floor<date::days>(now.get_local_time())}; // Convert now to year_month_day
const date::year_month_day shiftedDay{today + cldCurrShift_}; // Shift today
// Define shift local time
const auto shiftedNow{date::make_zoned(
tz, date::local_days(shiftedDay) +
(now.get_local_time() - date::floor<date::days>(now.get_local_time())))};
label_.set_markup(fmt::format(locale_, fmt::runtime(format_), now)); auto shifted_date = date::year_month_day{date::floor<date::days>(now)} + cldCurrShift_;
if (cldCurrShift_.count()) {
shifted_date = date::year_month_day(shifted_date.year(), shifted_date.month(), date::day(1));
}
auto now_shifted = date::sys_days{shifted_date} + (now - date::floor<date::days>(now));
auto shifted_ztime = date::zoned_time{time_zone, date::floor<std::chrono::seconds>(now_shifted)};
std::string text{""};
if (!is_timezone_fixed()) {
// As date dep is not fully compatible, prefer fmt
tzset();
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
text = fmt::format(locale_, fmt::runtime(format_), localtime);
} else {
text = fmt::format(locale_, fmt::runtime(format_), ztime);
}
label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
const std::string tz_text{(is_timezoned_list_in_tooltip_) ? timezones_text(now.get_sys_time()) if (config_["tooltip-format"].isString()) {
: ""}; std::string calendar_lines{""};
const std::string cld_text{(is_calendar_in_tooltip_) ? get_calendar(today, shiftedDay, tz) std::string timezoned_time_lines{""};
: ""}; if (is_calendar_in_tooltip_) {
calendar_lines = get_calendar(ztime, shifted_ztime);
const std::string text{fmt::format(locale_, fmt::runtime(fmtMap_[5]), shiftedNow, }
fmt::arg(KTimezonedTimeListPlaceholder.c_str(), tz_text), if (is_timezoned_list_in_tooltip_) {
fmt::arg(kCalendarPlaceholder.c_str(), cld_text))}; timezoned_time_lines = timezones_text(&now);
label_.set_tooltip_markup(text); }
auto tooltip_format = config_["tooltip-format"].asString();
text = fmt::format(locale_, fmt::runtime(tooltip_format), shifted_ztime,
fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines),
fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines));
label_.set_tooltip_markup(text);
}
} }
// Call parent update // Call parent update
@ -202,15 +219,15 @@ auto waybar::modules::Clock::doAction(const std::string& name) -> void {
} }
// The number of weeks in calendar month layout plus 1 more for calendar titles // The number of weeks in calendar month layout plus 1 more for calendar titles
const unsigned cldRowsInMonth(const date::year_month& ym, const date::weekday& firstdow) { unsigned cldRowsInMonth(date::year_month const ym, date::weekday const firstdow) {
using namespace date; using namespace date;
return static_cast<unsigned>( return static_cast<unsigned>(
ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count()) + ceil<weeks>((weekday{ym / 1} - firstdow) + ((ym / last).day() - day{0})).count()) +
2; 2;
} }
auto cldGetWeekForLine(const date::year_month& ym, const date::weekday& firstdow, auto cldGetWeekForLine(date::year_month const ym, date::weekday const firstdow, unsigned const line)
unsigned const line) -> const date::year_month_weekday { -> const date::year_month_weekday {
unsigned index = line - 2; unsigned index = line - 2;
auto sd = date::sys_days{ym / 1}; auto sd = date::sys_days{ym / 1};
if (date::weekday{sd} == firstdow) ++index; if (date::weekday{sd} == firstdow) ++index;
@ -218,8 +235,8 @@ auto cldGetWeekForLine(const date::year_month& ym, const date::weekday& firstdow
return ymdw; return ymdw;
} }
auto getCalendarLine(const date::year_month_day& currDate, const date::year_month ym, auto getCalendarLine(date::year_month_day const currDate, date::year_month const ym,
const unsigned line, const date::weekday& firstdow, unsigned const line, date::weekday const firstdow,
const std::locale* const locale_) -> std::string { const std::locale* const locale_) -> std::string {
using namespace date::literals; using namespace date::literals;
std::ostringstream res; std::ostringstream res;
@ -301,9 +318,10 @@ auto getCalendarLine(const date::year_month_day& currDate, const date::year_mont
return res.str(); return res.str();
} }
auto waybar::modules::Clock::get_calendar(const date::year_month_day& today, auto waybar::modules::Clock::get_calendar(const date::zoned_seconds& now,
const date::year_month_day& ymd, const date::zoned_seconds& wtime) -> std::string {
const date::time_zone* tz) -> const std::string { auto daypoint = date::floor<date::days>(wtime.get_local_time());
const auto ymd{date::year_month_day{daypoint}};
const auto ym{ymd.year() / ymd.month()}; const auto ym{ymd.year() / ymd.month()};
const auto y{ymd.year()}; const auto y{ymd.year()};
const auto d{ymd.day()}; const auto d{ymd.day()};
@ -311,6 +329,9 @@ auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
const auto maxRows{12 / cldMonCols_}; const auto maxRows{12 / cldMonCols_};
std::ostringstream os; std::ostringstream os;
std::ostringstream tmp; std::ostringstream tmp;
// get currdate
daypoint = date::floor<date::days>(now.get_local_time());
const auto currDate{date::year_month_day{daypoint}};
if (cldMode_ == CldMode::YEAR) { if (cldMode_ == CldMode::YEAR) {
if (y / date::month{1} / 1 == cldYearShift_) if (y / date::month{1} / 1 == cldYearShift_)
@ -340,7 +361,6 @@ auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
else else
m = 0u; m = 0u;
} }
for (auto row{0u}; row < maxRows; ++row) { for (auto row{0u}; row < maxRows; ++row) {
const auto lines = *std::max_element(std::begin(ml) + (row * cldMonCols_), const auto lines = *std::max_element(std::begin(ml) + (row * cldMonCols_),
std::begin(ml) + ((row + 1) * cldMonCols_)); std::begin(ml) + ((row + 1) * cldMonCols_));
@ -357,9 +377,8 @@ auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
if (line < ml[static_cast<unsigned>(ymTmp.month()) - 1u]) if (line < ml[static_cast<unsigned>(ymTmp.month()) - 1u])
os << fmt::format(fmt::runtime(fmtMap_[4]), os << fmt::format(fmt::runtime(fmtMap_[4]),
(line == 2) (line == 2)
? date::zoned_seconds{tz, date::local_days{ymTmp / 1}} ? date::sys_days{ymTmp / 1}
: date::zoned_seconds{tz, date::local_days{cldGetWeekForLine( : date::sys_days{cldGetWeekForLine(ymTmp, firstdow, line)})
ymTmp, firstdow, line)}})
<< ' '; << ' ';
else else
os << std::string(cldWnLen_, ' '); os << std::string(cldWnLen_, ' ');
@ -368,7 +387,7 @@ auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
os << fmt::format( os << fmt::format(
fmt::runtime((cldWPos_ != WeeksSide::LEFT || line == 0) ? "{:<{}}" : "{:>{}}"), fmt::runtime((cldWPos_ != WeeksSide::LEFT || line == 0) ? "{:<{}}" : "{:>{}}"),
getCalendarLine(today, ymTmp, line, firstdow, &locale_), getCalendarLine(currDate, ymTmp, line, firstdow, &locale_),
(cldMonColLen_ + ((line < 2) ? cldWnLen_ : 0))); (cldMonColLen_ + ((line < 2) ? cldWnLen_ : 0)));
// Week numbers on the right // Week numbers on the right
@ -378,9 +397,8 @@ auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
os << ' ' os << ' '
<< fmt::format(fmt::runtime(fmtMap_[4]), << fmt::format(fmt::runtime(fmtMap_[4]),
(line == 2) (line == 2)
? date::zoned_seconds{tz, date::local_days{ymTmp / 1}} ? date::sys_days{ymTmp / 1}
: date::zoned_seconds{tz, date::local_days{cldGetWeekForLine( : date::sys_days{cldGetWeekForLine(ymTmp, firstdow, line)});
ymTmp, firstdow, line)}});
else else
os << std::string(cldWnLen_, ' '); os << std::string(cldWnLen_, ' ');
} }
@ -403,7 +421,7 @@ auto waybar::modules::Clock::get_calendar(const date::year_month_day& today,
os << fmt::format( // Apply days format os << fmt::format( // Apply days format
fmt::runtime(fmt::format(fmt::runtime(fmtMap_[2]), tmp.str())), fmt::runtime(fmt::format(fmt::runtime(fmtMap_[2]), tmp.str())),
// Apply today format // Apply today format
fmt::arg("today", fmt::format(fmt::runtime(fmtMap_[3]), date::format("%e", d)))); fmt::arg("today", fmt::format(fmt::runtime(fmtMap_[3]), date::format("%e", ymd.day()))));
if (cldMode_ == CldMode::YEAR) if (cldMode_ == CldMode::YEAR)
cldYearCached_ = os.str(); cldYearCached_ = os.str();
@ -439,7 +457,7 @@ void waybar::modules::Clock::tz_down() {
current_time_zone_idx_ = current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1; current_time_zone_idx_ = current_time_zone_idx_ == 0 ? nr_zones - 1 : current_time_zone_idx_ - 1;
} }
auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_point now) auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_point* now)
-> std::string { -> std::string {
if (time_zones_.size() == 1) { if (time_zones_.size() == 1) {
return ""; return "";
@ -453,7 +471,7 @@ auto waybar::modules::Clock::timezones_text(std::chrono::system_clock::time_poin
if (!timezone) { if (!timezone) {
timezone = date::current_zone(); timezone = date::current_zone();
} }
auto ztime = date::zoned_time{timezone, date::floor<std::chrono::seconds>(now)}; auto ztime = date::zoned_time{timezone, date::floor<std::chrono::seconds>(*now)};
os << fmt::format(locale_, fmt::runtime(format_), ztime) << '\n'; os << fmt::format(locale_, fmt::runtime(format_), ztime) << '\n';
} }
return os.str(); return os.str();

View File

@ -122,14 +122,14 @@ auto waybar::modules::Custom::update() -> void {
(output_.out.empty() || output_.exit_code != 0)) { (output_.out.empty() || output_.exit_code != 0)) {
event_box_.hide(); event_box_.hide();
} else { } else {
fields_.clear();
if (config_["return-type"].asString() == "json") { if (config_["return-type"].asString() == "json") {
parseOutputJson(); parseOutputJson();
} else { } else {
parseOutputRaw(); parseOutputRaw();
} }
auto str = fmt::vformat(format_, fields_); auto str = fmt::format(fmt::runtime(format_), text_, fmt::arg("alt", alt_),
fmt::arg("icon", getIcon(percentage_, alt_)),
fmt::arg("percentage", percentage_));
if (str.empty()) { if (str.empty()) {
event_box_.hide(); event_box_.hide();
} else { } else {
@ -173,7 +173,6 @@ void waybar::modules::Custom::parseOutputRaw() {
} else { } else {
text_ = line; text_ = line;
} }
fields_.push_back(text_);
tooltip_ = line; tooltip_ = line;
class_.clear(); class_.clear();
} else if (i == 1) { } else if (i == 1) {
@ -190,45 +189,32 @@ void waybar::modules::Custom::parseOutputRaw() {
void waybar::modules::Custom::parseOutputJson() { void waybar::modules::Custom::parseOutputJson() {
std::istringstream output(output_.out); std::istringstream output(output_.out);
std::string line; std::string line;
getline(output, line);
class_.clear(); class_.clear();
auto parsed = parser_.parse(line); while (getline(output, line)) {
auto parsed = parser_.parse(line);
// Preserve order so that first "{}" is resolved to "text" for backwards compatability
if (parsed["text"].isString()) {
auto str = parsed["text"].asString();
if (config_["escape"].isBool() && config_["escape"].asBool()) { if (config_["escape"].isBool() && config_["escape"].asBool()) {
str = Glib::Markup::escape_text(str); text_ = Glib::Markup::escape_text(parsed["text"].asString());
} else {
text_ = parsed["text"].asString();
} }
fields_.push_back(str);
}
for (auto const& key : parsed.getMemberNames()) {
if (!parsed[key].isString()) continue;
auto str = parsed[key].asString();
if (config_["escape"].isBool() && config_["escape"].asBool()) { if (config_["escape"].isBool() && config_["escape"].asBool()) {
str = Glib::Markup::escape_text(str); alt_ = Glib::Markup::escape_text(parsed["alt"].asString());
} else {
alt_ = parsed["alt"].asString();
} }
fields_.push_back(fmt::arg(key.c_str(), str)); tooltip_ = parsed["tooltip"].asString();
} if (parsed["class"].isString()) {
class_.push_back(parsed["class"].asString());
tooltip_ = parsed["tooltip"].asString(); } else if (parsed["class"].isArray()) {
if (parsed["class"].isString()) { for (auto const& c : parsed["class"]) {
class_.push_back(parsed["class"].asString()); class_.push_back(c.asString());
} else if (parsed["class"].isArray()) { }
for (auto const& c : parsed["class"]) {
class_.push_back(c.asString());
} }
} if (!parsed["percentage"].asString().empty() && parsed["percentage"].isNumeric()) {
percentage_ = (int)lround(parsed["percentage"].asFloat());
if (!parsed["percentage"].asString().empty() && parsed["percentage"].isNumeric()) { } else {
percentage_ = (int)lround(parsed["percentage"].asFloat()); percentage_ = 0;
} else { }
percentage_ = 0; break;
}
// Allow overriding icon from json, otherwise use percentage based icon
if (parsed["icon"].isNull()) {
fields_.push_back(fmt::arg("icon", getIcon(percentage_, alt_)));
} }
} }

View File

@ -26,7 +26,6 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
queryActiveWorkspace(); queryActiveWorkspace();
update(); update();
dp.emit();
// register for hyprland ipc // register for hyprland ipc
gIPC->registerForIPC("activewindow", this); gIPC->registerForIPC("activewindow", this);

View File

@ -16,7 +16,7 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
Json::Value config_format = config["format"]; Json::Value config_format = config["format"];
format_ = config_format.isString() ? config_format.asString() : "{name}"; format_ = config_format.isString() ? config_format.asString() : "{id}";
with_icon_ = format_.find("{icon}") != std::string::npos; with_icon_ = format_.find("{icon}") != std::string::npos;
if (with_icon_ && icons_map_.empty()) { if (with_icon_ && icons_map_.empty()) {
@ -28,23 +28,13 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
icons_map_.emplace("", ""); icons_map_.emplace("", "");
} }
auto config_all_outputs = config_["all-outputs"];
if (config_all_outputs.isBool()) {
all_outputs_ = config_all_outputs.asBool();
}
auto config_show_special = config_["show-special"];
if (config_show_special.isBool()) {
show_special_ = config_show_special.asBool();
}
box_.set_name("workspaces"); box_.set_name("workspaces");
if (!id.empty()) { if (!id.empty()) {
box_.get_style_context()->add_class(id); box_.get_style_context()->add_class(id);
} }
event_box_.add(box_); event_box_.add(box_);
modulesReady = true; modulesReady = true;
if (!gIPC) { if (!gIPC.get()) {
gIPC = std::make_unique<IPC>(); gIPC = std::make_unique<IPC>();
} }
@ -53,38 +43,32 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
gIPC->registerForIPC("workspace", this); gIPC->registerForIPC("workspace", this);
gIPC->registerForIPC("createworkspace", this); gIPC->registerForIPC("createworkspace", this);
gIPC->registerForIPC("destroyworkspace", this); gIPC->registerForIPC("destroyworkspace", this);
gIPC->registerForIPC("focusedmon", this);
gIPC->registerForIPC("moveworkspace", this);
gIPC->registerForIPC("openwindow", this);
gIPC->registerForIPC("closewindow", this);
gIPC->registerForIPC("movewindow", this);
gIPC->registerForIPC("urgent", this);
} }
auto Workspaces::update() -> void { auto Workspaces::update() -> void {
for (std::string workspace_to_remove : workspaces_to_remove_) { for (int &workspace_to_remove : workspaces_to_remove_) {
remove_workspace(workspace_to_remove); remove_workspace(workspace_to_remove);
} }
workspaces_to_remove_.clear(); workspaces_to_remove_.clear();
for (Json::Value &workspace_to_create : workspaces_to_create_) { for (int &workspace_to_create : workspaces_to_create_) {
create_workspace(workspace_to_create); create_workspace(workspace_to_create);
} }
workspaces_to_create_.clear(); workspaces_to_create_.clear();
for (auto &workspace : workspaces_) { for (std::unique_ptr<Workspace> &workspace : workspaces_) {
workspace->set_active(workspace->name() == active_workspace_name_); workspace->set_active(workspace->id() == active_workspace_id);
if (workspace->name() == active_workspace_name_ && workspace.get()->is_urgent()) {
workspace->set_urgent(false);
}
std::string &workspace_icon = icons_map_[""]; std::string &workspace_icon = icons_map_[""];
if (with_icon_) { if (with_icon_) {
workspace_icon = workspace->select_icon(icons_map_); workspace_icon = workspace->select_icon(icons_map_);
} }
workspace->update(format_, workspace_icon); workspace->update(format_, workspace_icon);
} }
AModule::update(); AModule::update();
} }
@ -92,102 +76,35 @@ void Workspaces::onEvent(const std::string &ev) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
std::string eventName(begin(ev), begin(ev) + ev.find_first_of('>')); std::string eventName(begin(ev), begin(ev) + ev.find_first_of('>'));
std::string payload = ev.substr(eventName.size() + 2); std::string payload = ev.substr(eventName.size() + 2);
if (eventName == "workspace") { if (eventName == "workspace") {
active_workspace_name_ = payload; std::from_chars(payload.data(), payload.data() + payload.size(), active_workspace_id);
} else if (eventName == "destroyworkspace") { } else if (eventName == "destroyworkspace") {
workspaces_to_remove_.push_back(payload); int deleted_workspace_id;
std::from_chars(payload.data(), payload.data() + payload.size(), deleted_workspace_id);
workspaces_to_remove_.push_back(deleted_workspace_id);
} else if (eventName == "createworkspace") { } else if (eventName == "createworkspace") {
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); int new_workspace_id;
for (Json::Value workspace_json : workspaces_json) { std::from_chars(payload.data(), payload.data() + payload.size(), new_workspace_id);
if (workspace_json["name"].asString() == payload && workspaces_to_create_.push_back(new_workspace_id);
(all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) &&
(show_special() || !workspace_json["name"].asString().starts_with("special"))) {
workspaces_to_create_.push_back(workspace_json);
break;
}
}
} else if (eventName == "focusedmon") {
active_workspace_name_ = payload.substr(payload.find(',') + 1);
} else if (eventName == "moveworkspace" && !all_outputs()) {
std::string workspace = payload.substr(0, payload.find(','));
std::string new_output = payload.substr(payload.find(',') + 1);
if (bar_.output->name == new_output) { // TODO: implement this better
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
for (Json::Value workspace_json : workspaces_json) {
if (workspace_json["name"].asString() == workspace &&
bar_.output->name == workspace_json["monitor"].asString()) {
workspaces_to_create_.push_back(workspace_json);
break;
}
}
} else {
workspaces_to_remove_.push_back(workspace);
}
} else if (eventName == "openwindow" || eventName == "closewindow" || eventName == "movewindow") {
update_window_count();
} else if (eventName == "urgent") {
set_urgent_workspace(payload);
} }
dp.emit(); dp.emit();
} }
void Workspaces::update_window_count() { void Workspaces::create_workspace(int id) {
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); workspaces_.push_back(std::make_unique<Workspace>(id));
for (auto &workspace : workspaces_) {
auto workspace_json = std::find_if(
workspaces_json.begin(), workspaces_json.end(),
[&](Json::Value const &x) { return x["name"].asString() == workspace->name(); });
if (workspace_json != workspaces_json.end()) {
try {
workspace->set_windows((*workspace_json)["windows"].asUInt());
} catch (const std::exception &e) {
spdlog::error("Failed to update window count: {}", e.what());
}
} else {
workspace->set_windows(0);
}
}
}
void Workspaces::create_workspace(Json::Value &value) {
// replace the existing persistent workspace if it exists
auto workspace = std::find_if(
workspaces_.begin(), workspaces_.end(), [&](std::unique_ptr<Workspace> const &x) {
auto name = value["name"].asString();
return x->is_persistent() &&
((name.starts_with("special:") && name.substr(8) == x->name()) || name == x->name());
});
if (workspace != workspaces_.end()) {
// replace workspace, but keep persistent flag
workspaces_.erase(workspace);
value["persistent"] = true;
}
// create new workspace
workspaces_.emplace_back(std::make_unique<Workspace>(value));
Gtk::Button &new_workspace_button = workspaces_.back()->button(); Gtk::Button &new_workspace_button = workspaces_.back()->button();
box_.pack_start(new_workspace_button, false, false); box_.pack_start(new_workspace_button, false, false);
sort_workspaces(); sort_workspaces();
new_workspace_button.show_all(); new_workspace_button.show_all();
} }
void Workspaces::remove_workspace(std::string name) { void Workspaces::remove_workspace(int id) {
auto workspace = std::find_if(workspaces_.begin(), workspaces_.end(), auto workspace = std::find_if(workspaces_.begin(), workspaces_.end(),
[&](std::unique_ptr<Workspace> &x) { return x->name() == name; }); [&](std::unique_ptr<Workspace> &x) { return x->id() == id; });
if (workspace == workspaces_.end()) { if (workspace == workspaces_.end()) {
// happens when a workspace on another monitor is destroyed spdlog::warn("Can't find workspace with id {}", id);
return;
}
if ((*workspace)->is_persistent()) {
// don't remove persistent workspaces, create_workspace will take care of replacement
return; return;
} }
@ -195,88 +112,18 @@ void Workspaces::remove_workspace(std::string name) {
workspaces_.erase(workspace); workspaces_.erase(workspace);
} }
void Workspaces::fill_persistent_workspaces() {
if (config_["persistent_workspaces"].isObject() && !all_outputs()) {
const Json::Value persistent_workspaces = config_["persistent_workspaces"];
const std::vector<std::string> keys = persistent_workspaces.getMemberNames();
for (const std::string &key : keys) {
const Json::Value &value = persistent_workspaces[key];
if (value.isInt()) {
// value is a number => create that many workspaces for this monitor
// only add if either:
// 1. key is "*" and this monitor is not already defined in the config
// 2. key is the current monitor name
if ((key == "*" && std::find(keys.begin(), keys.end(), bar_.output->name) == keys.end()) ||
key == bar_.output->name) {
int amount = value.asInt();
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount,
bar_.output->name);
for (int i = 0; i < amount; i++) {
persistent_workspaces_to_create_.emplace_back(
std::to_string(monitor_id_ * amount + i + 1));
}
}
} else if (value.isArray() && !value.empty()) {
// value is an array => key is a workspace name
// values are monitor names this workspace should be shown on
for (const Json::Value &monitor : value) {
if (monitor.isString() && monitor.asString() == bar_.output->name) {
persistent_workspaces_to_create_.emplace_back(key);
break;
}
}
}
}
}
}
void Workspaces::create_persistent_workspaces() {
for (const std::string &workspace_name : persistent_workspaces_to_create_) {
Json::Value new_workspace;
try {
// numbered persistent workspaces get the name as ID
new_workspace["id"] = workspace_name == "special" ? -99 : std::stoi(workspace_name);
} catch (const std::exception &e) {
// named persistent workspaces start with ID=0
new_workspace["id"] = 0;
}
new_workspace["name"] = workspace_name;
new_workspace["monitor"] = bar_.output->name;
new_workspace["windows"] = 0;
new_workspace["persistent"] = true;
create_workspace(new_workspace);
}
}
void Workspaces::init() { void Workspaces::init() {
active_workspace_name_ = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString(); const auto activeWorkspace = WorkspaceDto::parse(gIPC->getSocket1JsonReply("activeworkspace"));
active_workspace_id = activeWorkspace.id;
// get monitor ID from name (used by persistent workspaces)
monitor_id_ = 0;
auto monitors = gIPC->getSocket1JsonReply("monitors");
auto current_monitor = std::find_if(
monitors.begin(), monitors.end(),
[this](const Json::Value &m) { return m["name"].asString() == bar_.output->name; });
if (current_monitor == monitors.end()) {
spdlog::error("Monitor '{}' does not have an ID? Using 0", bar_.output->name);
} else {
monitor_id_ = (*current_monitor)["id"].asInt();
}
fill_persistent_workspaces();
create_persistent_workspaces();
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces"); const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
for (Json::Value workspace_json : workspaces_json) { for (const Json::Value &workspace_json : workspaces_json) {
if ((all_outputs() || bar_.output->name == workspace_json["monitor"].asString()) && workspaces_.push_back(
(!workspace_json["name"].asString().starts_with("special") || show_special())) std::make_unique<Workspace>(Workspace(WorkspaceDto::parse(workspace_json))));
create_workspace(workspace_json);
} }
update_window_count(); for (auto &workspace : workspaces_) {
box_.pack_start(workspace->button(), false, false);
}
sort_workspaces(); sort_workspaces();
@ -289,33 +136,19 @@ Workspaces::~Workspaces() {
std::lock_guard<std::mutex> lg(mutex_); std::lock_guard<std::mutex> lg(mutex_);
} }
Workspace::Workspace(const Json::Value &workspace_data) WorkspaceDto WorkspaceDto::parse(const Json::Value &value) {
: id_(workspace_data["id"].asInt()), return WorkspaceDto{value["id"].asInt()};
name_(workspace_data["name"].asString()), }
output_(workspace_data["monitor"].asString()), // TODO:allow using monitor desc
windows_(workspace_data["windows"].asInt()),
active_(true) {
if (name_.starts_with("name:")) {
name_ = name_.substr(5);
} else if (name_.starts_with("special")) {
name_ = id_ == -99 ? name_ : name_.substr(8);
is_special_ = true;
}
if (workspace_data.isMember("persistent")) { Workspace::Workspace(WorkspaceDto dto) : Workspace(dto.id){};
is_persistent_ = workspace_data["persistent"].asBool();
}
button_.add_events(Gdk::BUTTON_PRESS_MASK);
button_.signal_button_press_event().connect(sigc::mem_fun(*this, &Workspace::handle_clicked),
false);
Workspace::Workspace(int id) : id_(id) {
button_.set_relief(Gtk::RELIEF_NONE); button_.set_relief(Gtk::RELIEF_NONE);
content_.set_center_widget(label_); content_.set_center_widget(label_);
button_.add(content_); button_.add(content_);
}; };
void add_or_remove_class(const Glib::RefPtr<Gtk::StyleContext> &context, bool condition, void add_or_remove_class(Glib::RefPtr<Gtk::StyleContext> context, bool condition,
const std::string &class_name) { const std::string &class_name) {
if (condition) { if (condition) {
context->add_class(class_name); context->add_class(class_name);
@ -325,48 +158,17 @@ void add_or_remove_class(const Glib::RefPtr<Gtk::StyleContext> &context, bool co
} }
void Workspace::update(const std::string &format, const std::string &icon) { void Workspace::update(const std::string &format, const std::string &icon) {
auto style_context = button_.get_style_context(); Glib::RefPtr<Gtk::StyleContext> style_context = button_.get_style_context();
add_or_remove_class(style_context, active(), "active"); add_or_remove_class(style_context, active(), "active");
add_or_remove_class(style_context, is_special(), "special");
add_or_remove_class(style_context, is_empty(), "persistent");
add_or_remove_class(style_context, is_urgent(), "urgent");
label_.set_markup(fmt::format(fmt::runtime(format), fmt::arg("id", id()), label_.set_markup(
fmt::arg("name", name()), fmt::arg("icon", icon))); fmt::format(fmt::runtime(format), fmt::arg("id", id()), fmt::arg("icon", icon)));
} }
void Workspaces::sort_workspaces() { void Workspaces::sort_workspaces() {
std::sort(workspaces_.begin(), workspaces_.end(), std::sort(workspaces_.begin(), workspaces_.end(),
[](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) { [](std::unique_ptr<Workspace> &lhs, std::unique_ptr<Workspace> &rhs) {
// normal -> named persistent -> named -> special -> named special return lhs->id() < rhs->id();
// both normal (includes numbered persistent) => sort by ID
if (a->id() > 0 && b->id() > 0) {
return a->id() < b->id();
}
// one normal, one special => normal first
if ((a->is_special()) ^ (b->is_special())) {
return b->is_special();
}
// only one normal, one named
if ((a->id() > 0) ^ (b->id() > 0)) {
return a->id() > 0;
}
// both special
if (a->is_special() && b->is_special()) {
// if one is -99 => put it last
if (a->id() == -99 || b->id() == -99) {
return b->id() == -99;
}
// both are 0 (not yet named persistents) / both are named specials (-98 <= ID <=-1)
return a->name() < b->name();
}
// sort non-special named workspaces by name (ID <= -1377)
return a->name() < b->name();
}); });
for (size_t i = 0; i < workspaces_.size(); ++i) { for (size_t i = 0; i < workspaces_.size(); ++i) {
@ -382,67 +184,16 @@ std::string &Workspace::select_icon(std::map<std::string, std::string> &icons_ma
} }
} }
if (is_special()) { auto named_icon_it = icons_map.find(std::to_string(id()));
auto special_icon_it = icons_map.find("special");
if (special_icon_it != icons_map.end()) {
return special_icon_it->second;
}
}
auto named_icon_it = icons_map.find(name());
if (named_icon_it != icons_map.end()) { if (named_icon_it != icons_map.end()) {
return named_icon_it->second; return named_icon_it->second;
} }
if (is_persistent()) {
auto persistent_icon_it = icons_map.find("persistent");
if (persistent_icon_it != icons_map.end()) {
return persistent_icon_it->second;
}
}
auto default_icon_it = icons_map.find("default"); auto default_icon_it = icons_map.find("default");
if (default_icon_it != icons_map.end()) { if (default_icon_it != icons_map.end()) {
return default_icon_it->second; return default_icon_it->second;
} }
return icons_map[""]; return icons_map[""];
} }
auto Workspace::handle_clicked(GdkEventButton *bt) -> bool {
try {
if (id() > 0) { // normal or numbered persistent
gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id()));
} else if (!is_special()) { // named
gIPC->getSocket1Reply("dispatch workspace name:" + name());
} else if (id() != -99) { // named special
gIPC->getSocket1Reply("dispatch togglespecialworkspace " + name());
} else { // special
gIPC->getSocket1Reply("dispatch togglespecialworkspace");
}
return true;
} catch (const std::exception &e) {
spdlog::error("Failed to dispatch workspace: {}", e.what());
}
return false;
}
void Workspaces::set_urgent_workspace(std::string windowaddress) {
const Json::Value clients_json = gIPC->getSocket1JsonReply("clients");
int workspace_id;
for (Json::Value client_json : clients_json) {
if (client_json["address"].asString().ends_with(windowaddress)) {
workspace_id = client_json["workspace"]["id"].asInt();
break;
}
}
auto workspace =
std::find_if(workspaces_.begin(), workspaces_.end(),
[&](std::unique_ptr<Workspace> &x) { return x->id() == workspace_id; });
if (workspace->get() != nullptr) {
workspace->get()->set_urgent();
}
}
} // namespace waybar::modules::hyprland } // namespace waybar::modules::hyprland

View File

@ -142,21 +142,6 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
} }
} }
auto keys = config_["binding-keys"];
if (keys.isArray()) {
for (const auto& key : keys) {
if (key.isInt()) {
binding_keys.insert(key.asInt());
} else {
spdlog::warn("Cannot read key binding {} as int.", key.asString());
}
}
} else {
binding_keys.insert(KEY_CAPSLOCK);
binding_keys.insert(KEY_NUMLOCK);
binding_keys.insert(KEY_SCROLLLOCK);
}
DIR* dev_dir = opendir(devices_path_.c_str()); DIR* dev_dir = opendir(devices_path_.c_str());
if (dev_dir == nullptr) { if (dev_dir == nullptr) {
throw errno_error(errno, "Failed to open " + devices_path_); throw errno_error(errno, "Failed to open " + devices_path_);
@ -186,8 +171,14 @@ waybar::modules::KeyboardState::KeyboardState(const std::string& id, const Bar&
auto state = libinput_event_keyboard_get_key_state(keyboard_event); auto state = libinput_event_keyboard_get_key_state(keyboard_event);
if (state == LIBINPUT_KEY_STATE_RELEASED) { if (state == LIBINPUT_KEY_STATE_RELEASED) {
uint32_t key = libinput_event_keyboard_get_key(keyboard_event); uint32_t key = libinput_event_keyboard_get_key(keyboard_event);
if (binding_keys.contains(key)) { switch (key) {
dp.emit(); case KEY_CAPSLOCK:
case KEY_NUMLOCK:
case KEY_SCROLLLOCK:
dp.emit();
break;
default:
break;
} }
} }
} }

View File

@ -18,13 +18,13 @@ auto waybar::modules::Clock::update() -> void {
tzset(); // Update timezone information tzset(); // Update timezone information
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
auto text = fmt::format(fmt::runtime(format_), localtime); auto text = fmt::format(format_, localtime);
label_.set_markup(text); label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
auto tooltip_format = config_["tooltip-format"].asString(); auto tooltip_format = config_["tooltip-format"].asString();
auto tooltip_text = fmt::format(fmt::runtime(tooltip_format), localtime); auto tooltip_text = fmt::format(tooltip_format, localtime);
label_.set_tooltip_text(tooltip_text); label_.set_tooltip_text(tooltip_text);
} else { } else {
label_.set_tooltip_text(text); label_.set_tooltip_text(text);

View File

@ -22,7 +22,7 @@ struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
template <typename FormatContext> template <typename FormatContext>
auto format(const Glib::VariantBase& value, FormatContext& ctx) { auto format(const Glib::VariantBase& value, FormatContext& ctx) {
if (is_printable(value)) { if (is_printable(value)) {
return formatter<std::string>::format(static_cast<std::string>(value.print()), ctx); return formatter<std::string>::format(value.print(), ctx);
} else { } else {
return formatter<std::string>::format(value.get_type_string(), ctx); return formatter<std::string>::format(value.get_type_string(), ctx);
} }

View File

@ -1,7 +1,6 @@
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
#include <fcntl.h> #include <fcntl.h>
#include <spdlog/spdlog.h>
#include <stdexcept> #include <stdexcept>
@ -18,16 +17,12 @@ Ipc::~Ipc() {
if (fd_ > 0) { if (fd_ > 0) {
// To fail the IPC header // To fail the IPC header
if (write(fd_, "close-sway-ipc", 14) == -1) { write(fd_, "close-sway-ipc", 14);
spdlog::error("Failed to close sway IPC");
}
close(fd_); close(fd_);
fd_ = -1; fd_ = -1;
} }
if (fd_event_ > 0) { if (fd_event_ > 0) {
if (write(fd_event_, "close-sway-ipc", 14) == -1) { write(fd_event_, "close-sway-ipc", 14);
spdlog::error("Failed to close sway IPC event handler");
}
close(fd_event_); close(fd_event_);
fd_event_ = -1; fd_event_ = -1;
} }

View File

@ -145,40 +145,6 @@ std::pair<int, int> leafNodesInWorkspace(const Json::Value& node) {
return {sum, floating_sum}; return {sum, floating_sum};
} }
std::optional<std::reference_wrapper<const Json::Value>> getSingleChildNode(
const Json::Value& node) {
auto const& nodes = node["nodes"];
if (nodes.empty()) {
if (node["type"].asString() == "workspace")
return {};
else if (node["type"].asString() == "floating_con") {
return {};
} else {
return {std::cref(node)};
}
}
auto it = std::cbegin(nodes);
if (it == std::cend(nodes)) {
return {};
}
auto const& child = *it;
++it;
if (it != std::cend(nodes)) {
return {};
}
return {getSingleChildNode(child)};
}
std::tuple<std::string, std::string, std::string> getWindowInfo(const Json::Value& node) {
const auto app_id = node["app_id"].isString() ? node["app_id"].asString()
: node["window_properties"]["instance"].asString();
const auto app_class = node["window_properties"]["class"].isString()
? node["window_properties"]["class"].asString()
: "";
const auto shell = node["shell"].isString() ? node["shell"].asString() : "";
return {app_id, app_class, shell};
}
std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string> std::tuple<std::size_t, int, int, std::string, std::string, std::string, std::string, std::string>
gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Value& config_, gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Value& config_,
const Bar& bar_, Json::Value& parentWorkspace, const Bar& bar_, Json::Value& parentWorkspace,
@ -215,7 +181,12 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
// found node // found node
spdlog::trace("actual output {}, output found {}, node (focused) found {}", bar_.output->name, spdlog::trace("actual output {}, output found {}, node (focused) found {}", bar_.output->name,
output, node["name"].asString()); output, node["name"].asString());
const auto [app_id, app_class, shell] = getWindowInfo(node); auto app_id = node["app_id"].isString() ? node["app_id"].asString()
: node["window_properties"]["instance"].asString();
const auto app_class = node["window_properties"]["class"].isString()
? node["window_properties"]["class"].asString()
: "";
const auto shell = node["shell"].isString() ? node["shell"].asString() : "";
int nb = node.size(); int nb = node.size();
int floating_count = 0; int floating_count = 0;
std::string workspace_layout = ""; std::string workspace_layout = "";
@ -255,24 +226,15 @@ gfnWithWorkspace(const Json::Value& nodes, std::string& output, const Json::Valu
std::pair all_leaf_nodes = leafNodesInWorkspace(immediateParent); std::pair all_leaf_nodes = leafNodesInWorkspace(immediateParent);
// using an empty string as default ensures that no window depending styles are set due to the // using an empty string as default ensures that no window depending styles are set due to the
// checks above for !name.empty() // checks above for !name.empty()
std::string app_id = "";
std::string app_class = "";
std::string workspace_layout = "";
if (all_leaf_nodes.first == 1) {
const auto single_child = getSingleChildNode(immediateParent);
if (single_child.has_value()) {
std::tie(app_id, app_class, workspace_layout) = getWindowInfo(single_child.value());
}
}
return {all_leaf_nodes.first, return {all_leaf_nodes.first,
all_leaf_nodes.second, all_leaf_nodes.second,
0, 0,
(all_leaf_nodes.first > 0 || all_leaf_nodes.second > 0) (all_leaf_nodes.first > 0 || all_leaf_nodes.second > 0)
? config_["offscreen-css-text"].asString() ? config_["offscreen-css-text"].asString()
: "", : "",
app_id, "",
app_class, "",
workspace_layout, "",
immediateParent["layout"].asString()}; immediateParent["layout"].asString()};
} }

View File

@ -28,11 +28,6 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
: AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()), : AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()),
bar_(bar), bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) { box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
if (config["format-icons"]["high-priority-named"].isArray()) {
for (auto &it : config["format-icons"]["high-priority-named"]) {
high_priority_named_.push_back(it.asString());
}
}
box_.set_name("workspaces"); box_.set_name("workspaces");
if (!id.empty()) { if (!id.empty()) {
box_.get_style_context()->add_class(id); box_.get_style_context()->add_class(id);
@ -284,24 +279,9 @@ Gtk::Button &Workspaces::addButton(const Json::Value &node) {
} }
std::string Workspaces::getIcon(const std::string &name, const Json::Value &node) { std::string Workspaces::getIcon(const std::string &name, const Json::Value &node) {
std::vector<std::string> keys = {"high-priority-named", "urgent", "focused", name, "default"}; std::vector<std::string> keys = {"urgent", "focused", name, "visible", "default"};
for (auto const &key : keys) { for (auto const &key : keys) {
if (key == "high-priority-named") { if (key == "focused" || key == "visible" || key == "urgent") {
auto it = std::find_if(high_priority_named_.begin(), high_priority_named_.end(),
[&](const std::string &member) { return member == name; });
if (it != high_priority_named_.end()) {
return config_["format-icons"][name].asString();
}
it = std::find_if(high_priority_named_.begin(), high_priority_named_.end(),
[&](const std::string &member) {
return trimWorkspaceName(member) == trimWorkspaceName(name);
});
if (it != high_priority_named_.end()) {
return config_["format-icons"][trimWorkspaceName(name)].asString();
}
}
if (key == "focused" || key == "urgent") {
if (config_["format-icons"][key].isString() && node[key].asBool()) { if (config_["format-icons"][key].isString() && node[key].asBool()) {
return config_["format-icons"][key].asString(); return config_["format-icons"][key].asString();
} }

View File

@ -517,7 +517,7 @@ void Task::handle_closed() {
bool Task::handle_clicked(GdkEventButton *bt) { bool Task::handle_clicked(GdkEventButton *bt) {
/* filter out additional events for double/triple clicks */ /* filter out additional events for double/triple clicks */
if (bt->type == GDK_BUTTON_PRESS) { if (bt->type == GDK_BUTTON_PRESS) {
/* save where the button press occurred in case it becomes a drag */ /* save where the button press ocurred in case it becomes a drag */
drag_start_button = bt->button; drag_start_button = bt->button;
drag_start_x = bt->x; drag_start_x = bt->x;
drag_start_y = bt->y; drag_start_y = bt->y;

View File

@ -1,10 +1,10 @@
[wrap-file] [wrap-file]
directory = Catch2-3.4.0 directory = Catch2-3.3.2
source_url = https://github.com/catchorg/Catch2/archive/v3.4.0.tar.gz source_url = https://github.com/catchorg/Catch2/archive/v3.3.2.tar.gz
source_filename = Catch2-3.4.0.tar.gz source_filename = Catch2-3.3.2.tar.gz
source_hash = 122928b814b75717316c71af69bd2b43387643ba076a6ec16e7882bfb2dfacbb source_hash = 8361907f4d9bff3ae7c1edb027f813659f793053c99b67837a0c0375f065bae2
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/catch2_3.4.0-1/Catch2-3.4.0.tar.gz source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/catch2_3.3.2-1/Catch2-3.3.2.tar.gz
wrapdb_version = 3.4.0-1 wrapdb_version = 3.3.2-1
[provide] [provide]
catch2 = catch2_dep catch2 = catch2_dep

View File

@ -1,7 +1,7 @@
[wrap-file] [wrap-file]
directory = cava-0.8.5 directory = cava-0.8.4
source_url = https://github.com/LukashonakV/cava/archive/0.8.5.tar.gz source_url = https://github.com/LukashonakV/cava/archive/0.8.4.tar.gz
source_filename = cava-0.8.5.tar.gz source_filename = cava-0.8.4.tar.gz
source_hash = 9ce3df7d374dc83ed0704fe3caef5e00600ce061d85608aad4142d2c59aa4647 source_hash = 523353f446570277d40b8e1efb84468d70fdec53e1356a555c14bf466557a3ed
[provide] [provide]
cava = cava_dep cava = cava_dep

View File

@ -1,13 +1,12 @@
[wrap-file] [wrap-file]
directory = fmt-9.1.0 directory = fmt-8.1.1
source_url = https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz source_url = https://github.com/fmtlib/fmt/archive/8.1.1.tar.gz
source_filename = fmt-9.1.0.tar.gz source_filename = fmt-8.1.1.tar.gz
source_hash = 5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2 source_hash = 3d794d3cf67633b34b2771eb9f073bde87e846e0d395d254df7b211ef1ec7346
patch_filename = fmt_9.1.0-2_patch.zip patch_filename = fmt_8.1.1-1_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_9.1.0-2/get_patch patch_url = https://wrapdb.mesonbuild.com/v2/fmt_8.1.1-1/get_patch
patch_hash = 23e8c4829f3e63f509b5643fe6bb87cbed39eae9594c451b338475d14d051967 patch_hash = 6035a67c7a8c90bed74c293c7265c769f47a69816125f7566bccb8e2543cee5e
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_9.1.0-2/fmt-9.1.0.tar.gz
wrapdb_version = 9.1.0-2
[provide] [provide]
fmt = fmt_dep fmt = fmt_dep

View File

@ -1,12 +1,13 @@
[wrap-file] [wrap-file]
directory = spdlog-1.11.0 directory = spdlog-1.10.0
source_url = https://github.com/gabime/spdlog/archive/v1.11.0.tar.gz source_url = https://github.com/gabime/spdlog/archive/v1.10.0.tar.gz
source_filename = v1.11.0.tar.gz source_filename = v1.10.0.tar.gz
source_hash = ca5cae8d6cac15dae0ec63b21d6ad3530070650f68076f3a4a862ca293a858bb source_hash = 697f91700237dbae2326b90469be32b876b2b44888302afbc7aceb68bcfe8224
patch_filename = spdlog_1.11.0-2_patch.zip patch_filename = spdlog_1.10.0-3_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.11.0-2/get_patch patch_url = https://wrapdb.mesonbuild.com/v2/spdlog_1.10.0-3/get_patch
patch_hash = db1364fe89502ac67f245a6c8c51290a52afd74a51eed26fa9ecb5b3443df57a patch_hash = 5bb07b4af1e971817d4b886efbe077aaf6c36d72d3d7e461bbcf6631f3725704
wrapdb_version = 1.11.0-2 wrapdb_version = 1.10.0-3
[provide] [provide]
spdlog = spdlog_dep spdlog = spdlog_dep