mirror of
https://github.com/rad4day/Waybar.git
synced 2023-12-21 10:22:59 +01:00
Compare commits
115 Commits
Author | SHA1 | Date | |
---|---|---|---|
d8a808f76c | |||
5ef6636237 | |||
fc632f50ec | |||
31e4c9023e | |||
3e1c341933 | |||
0d1016d4d2 | |||
12725f4418 | |||
5c64d034a2 | |||
14fa9cf7b7 | |||
6c196b8f8d | |||
18d6dfea88 | |||
d2eb8eb9fc | |||
65f73d3e95 | |||
265b4edb2e | |||
18f5af835f | |||
7ef80d563b | |||
d3be9a7363 | |||
5f29e5a5e8 | |||
cf4d58f30a | |||
bb61461aad | |||
c91c8bbc45 | |||
f26a125d15 | |||
de626dcbbc | |||
c9b963e82b | |||
a1cd0acac5 | |||
c2f9d889f4 | |||
58bdc6a41c | |||
c55cd82b39 | |||
91588fb8bb | |||
6b9600fecd | |||
0bfb29789c | |||
f6a62e258e | |||
1ba05d1ffa | |||
7a01143359 | |||
35496f461f | |||
b9cd0287f4 | |||
9d741f89e2 | |||
cc4370f1b2 | |||
85854c71d6 | |||
6ed550117c | |||
15fe85d18d | |||
b62e5eb822 | |||
25c2aaabcb | |||
cd49eef229 | |||
4f9fbbfa54 | |||
0b602632f2 | |||
dbc7471f83 | |||
887c44bf68 | |||
33236c222f | |||
4116490535 | |||
08e18387c9 | |||
0fff38c751 | |||
afc489869a | |||
ce4da59f34 | |||
43434254e0 | |||
66ce74d29b | |||
77a8420aaf | |||
b0f89f2bc1 | |||
7cda2dfd1a | |||
238cfa9547 | |||
b163b21ace | |||
30c4f08773 | |||
fd7c2a2012 | |||
4f14ce3285 | |||
e233022d1a | |||
e403c3b71b | |||
d367b7e1d6 | |||
038644f8d9 | |||
d650c597f9 | |||
5196009656 | |||
4d8515930f | |||
192cea97f2 | |||
83f3c2321e | |||
dff0583c12 | |||
73c7e54535 | |||
0f8c156f24 | |||
fff4509723 | |||
17af49d421 | |||
9f38631c7f | |||
62f4125927 | |||
a67e692d4a | |||
3c9cbc99d7 | |||
c5379fa52d | |||
070110af0c | |||
6bf5b15c13 | |||
a9779c2aa2 | |||
3af1853260 | |||
d638610db1 | |||
87023c39f8 | |||
e96610e31a | |||
d61b1d54de | |||
e397f568b7 | |||
d22fd3bbd1 | |||
75990c2867 | |||
88a1a702b4 | |||
24407dbf4a | |||
108285e9ac | |||
b728a37b6d | |||
938a93a0d7 | |||
ff6f727631 | |||
84077e0253 | |||
d2787cc2d8 | |||
17a56aa4f7 | |||
ca52892ab9 | |||
655bc8f215 | |||
a3912436be | |||
339bea1213 | |||
9389c8d854 | |||
6a17139423 | |||
3f23792df0 | |||
529031f44f | |||
f51894614d | |||
a7dbab79e5 | |||
4dcce810d2 | |||
1130e8c8ec |
@ -6,6 +6,6 @@ RUN export FEATURES="-ipc-sandbox -network-sandbox -pid-sandbox -sandbox -usersa
|
|||||||
emerge --sync && \
|
emerge --sync && \
|
||||||
eselect news read --quiet new 1>/dev/null 2>&1 && \
|
eselect news read --quiet new 1>/dev/null 2>&1 && \
|
||||||
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
|
emerge --verbose --update --deep --with-bdeps=y --backtrack=30 --newuse @world && \
|
||||||
USE="wayland gtk3 gtk -doc X" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols =dev-cpp/gtkmm-3.24.6 x11-libs/libxkbcommon \
|
USE="wayland gtk3 gtk -doc X pulseaudio minimal" emerge dev-vcs/git dev-libs/wayland dev-libs/wayland-protocols =dev-cpp/gtkmm-3.24.6 x11-libs/libxkbcommon \
|
||||||
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
|
x11-libs/gtk+:3 dev-libs/libdbusmenu dev-libs/libnl sys-power/upower media-libs/libpulse dev-libs/libevdev media-libs/libmpdclient \
|
||||||
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc media-sound/playerctl dev-libs/iniparser
|
media-sound/sndio gui-libs/gtk-layer-shell app-text/scdoc media-sound/playerctl dev-libs/iniparser sci-libs/fftw
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Waybar [](LICENSE) [](https://paypal.me/ARouillard)<br>
|
# Waybar [](LICENSE) [](https://paypal.me/ARouillard)<br>
|
||||||
|
|
||||||
> 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 [community](https://www.archlinux.org/packages/community/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)*
|
||||||
|
|
||||||
|
10
default.nix
Normal file
10
default.nix
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
(import
|
||||||
|
(
|
||||||
|
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
||||||
|
fetchTarball {
|
||||||
|
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ src = ./.; }
|
||||||
|
).defaultNix
|
35
flake.lock
generated
35
flake.lock
generated
@ -6,11 +6,11 @@
|
|||||||
"nixpkgs": "nixpkgs"
|
"nixpkgs": "nixpkgs"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667210711,
|
"lastModified": 1676293499,
|
||||||
"narHash": "sha256-IoErjXZAkzYWHEpQqwu/DeRNJGFdR7X2OGbkhMqMrpw=",
|
"narHash": "sha256-uIOTlTxvrXxpKeTvwBI1JGDGtCxMXE3BI0LFwoQMhiQ=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "devshell",
|
"repo": "devshell",
|
||||||
"rev": "96a9dd12b8a447840cc246e17a47b81a4268bba7",
|
"rev": "71e3022e3ab20bbf1342640547ef5bc14fb43bf4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -19,6 +19,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-compat": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1673956053,
|
||||||
|
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "edolstra",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1642700792,
|
"lastModified": 1642700792,
|
||||||
@ -36,11 +52,11 @@
|
|||||||
},
|
},
|
||||||
"flake-utils_2": {
|
"flake-utils_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667395993,
|
"lastModified": 1676283394,
|
||||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
"narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
"rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -67,11 +83,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1670152712,
|
"lastModified": 1676300157,
|
||||||
"narHash": "sha256-LJttwIvJqsZIj8u1LxVRv82vwUtkzVqQVi7Wb8gxPS4=",
|
"narHash": "sha256-1HjRzfp6LOLfcj/HJHdVKWAkX9QRAouoh6AjzJiIerU=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "14ddeaebcbe9a25748221d1d7ecdf98e20e2325e",
|
"rev": "545c7a31e5dedea4a6d372712a18e00ce097d462",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -84,6 +100,7 @@
|
|||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"devshell": "devshell",
|
"devshell": "devshell",
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-utils": "flake-utils_2",
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
}
|
}
|
||||||
|
38
flake.nix
38
flake.nix
@ -5,9 +5,13 @@
|
|||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
devshell.url = "github:numtide/devshell";
|
devshell.url = "github:numtide/devshell";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
flake-compat = {
|
||||||
|
url = "github:edolstra/flake-compat";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, flake-utils, devshell, nixpkgs }:
|
outputs = { self, flake-utils, devshell, nixpkgs, flake-compat }:
|
||||||
let
|
let
|
||||||
inherit (nixpkgs) lib;
|
inherit (nixpkgs) lib;
|
||||||
genSystems = lib.genAttrs [
|
genSystems = lib.genAttrs [
|
||||||
@ -26,9 +30,9 @@
|
|||||||
]);
|
]);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
overlays.default = _: prev: rec {
|
overlays.default = _: prev: {
|
||||||
waybar = prev.callPackage ./nix/default.nix {
|
waybar = prev.callPackage ./nix/default.nix {
|
||||||
version = "0.9.16" + "+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
|
||||||
@ -57,8 +61,32 @@
|
|||||||
devshell.packages = with pkgs; [
|
devshell.packages = with pkgs; [
|
||||||
clang-tools
|
clang-tools
|
||||||
gdb
|
gdb
|
||||||
];
|
# from nativeBuildInputs
|
||||||
language.c.libraries = with pkgs; [
|
gnumake
|
||||||
|
meson
|
||||||
|
ninja
|
||||||
|
pkg-config
|
||||||
|
scdoc
|
||||||
|
] ++ (map lib.getDev [
|
||||||
|
# from buildInputs
|
||||||
|
wayland wlroots gtkmm3 libsigcxx jsoncpp spdlog gtk-layer-shell howard-hinnant-date libxkbcommon
|
||||||
|
# optional dependencies
|
||||||
|
gobject-introspection glib playerctl python3.pkgs.pygobject3
|
||||||
|
libevdev libinput libjack2 libmpdclient playerctl libnl
|
||||||
|
libpulseaudio sndio sway libdbusmenu-gtk3 udev upower wireplumber
|
||||||
|
|
||||||
|
# from propagated build inputs?
|
||||||
|
at-spi2-atk atkmm cairo cairomm catch2 fmt_8 fontconfig
|
||||||
|
gdk-pixbuf glibmm gtk3 harfbuzz pango pangomm wayland-protocols
|
||||||
|
]);
|
||||||
|
env = with pkgs; [
|
||||||
|
{ name = "CPLUS_INCLUDE_PATH"; prefix = "$DEVSHELL_DIR/include"; }
|
||||||
|
{ name = "PKG_CONFIG_PATH"; prefix = "$DEVSHELL_DIR/lib/pkgconfig"; }
|
||||||
|
{ name = "PKG_CONFIG_PATH"; prefix = "$DEVSHELL_DIR/share/pkgconfig"; }
|
||||||
|
{ name = "PATH"; prefix = "${wayland.bin}/bin"; }
|
||||||
|
{ name = "LIBRARY_PATH"; prefix = "${lib.getLib sndio}/lib"; }
|
||||||
|
{ name = "LIBRARY_PATH"; prefix = "${lib.getLib zlib}/lib"; }
|
||||||
|
{ name = "LIBRARY_PATH"; prefix = "${lib.getLib howard-hinnant-date}/lib"; }
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "modules/hyprland/language.hpp"
|
#include "modules/hyprland/language.hpp"
|
||||||
#include "modules/hyprland/submap.hpp"
|
#include "modules/hyprland/submap.hpp"
|
||||||
#include "modules/hyprland/window.hpp"
|
#include "modules/hyprland/window.hpp"
|
||||||
|
#include "modules/hyprland/workspaces.hpp"
|
||||||
#endif
|
#endif
|
||||||
#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
|
#if defined(__FreeBSD__) || (defined(__linux__) && !defined(NO_FILESYSTEM))
|
||||||
#include "modules/battery.hpp"
|
#include "modules/battery.hpp"
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include "util/json.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::hyprland {
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
class EventHandler {
|
class EventHandler {
|
||||||
@ -22,12 +24,14 @@ class IPC {
|
|||||||
void unregisterForIPC(EventHandler*);
|
void unregisterForIPC(EventHandler*);
|
||||||
|
|
||||||
std::string getSocket1Reply(const std::string& rq);
|
std::string getSocket1Reply(const std::string& rq);
|
||||||
|
Json::Value getSocket1JsonReply(const std::string& rq);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startIPC();
|
void startIPC();
|
||||||
void parseIPC(const std::string&);
|
void parseIPC(const std::string&);
|
||||||
|
|
||||||
std::mutex callbackMutex;
|
std::mutex callbackMutex;
|
||||||
|
util::JsonParser parser_;
|
||||||
std::list<std::pair<std::string, EventHandler*>> callbacks;
|
std::list<std::pair<std::string, EventHandler*>> callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
#include "ALabel.hpp"
|
#include "ALabel.hpp"
|
||||||
#include "bar.hpp"
|
#include "bar.hpp"
|
||||||
#include "modules/hyprland/backend.hpp"
|
#include "modules/hyprland/backend.hpp"
|
||||||
@ -17,15 +15,32 @@ class Window : public waybar::ALabel, public EventHandler {
|
|||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int getActiveWorkspaceID(std::string);
|
struct Workspace {
|
||||||
std::string getLastWindowTitle(int);
|
int id;
|
||||||
|
int windows;
|
||||||
|
std::string last_window;
|
||||||
|
std::string last_window_title;
|
||||||
|
|
||||||
|
static auto parse(const Json::Value&) -> Workspace;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto getActiveWorkspace(const std::string&) -> Workspace;
|
||||||
|
auto getActiveWorkspace() -> Workspace;
|
||||||
void onEvent(const std::string&) override;
|
void onEvent(const std::string&) override;
|
||||||
|
void queryActiveWorkspace();
|
||||||
|
void setClass(const std::string&, bool enable);
|
||||||
|
|
||||||
bool separate_outputs;
|
bool separate_outputs;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
const Bar& bar_;
|
const Bar& bar_;
|
||||||
util::JsonParser parser_;
|
util::JsonParser parser_;
|
||||||
std::string lastView;
|
std::string last_title_;
|
||||||
|
Workspace workspace_;
|
||||||
|
std::string solo_class_;
|
||||||
|
std::string last_solo_class_;
|
||||||
|
bool solo_;
|
||||||
|
bool all_floating_;
|
||||||
|
bool fullscreen_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
64
include/modules/hyprland/workspaces.hpp
Normal file
64
include/modules/hyprland/workspaces.hpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include <gtkmm/button.h>
|
||||||
|
#include <gtkmm/label.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "AModule.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "modules/hyprland/backend.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
|
struct WorkspaceDto {
|
||||||
|
int id;
|
||||||
|
|
||||||
|
static WorkspaceDto parse(const Json::Value& value);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Workspace {
|
||||||
|
public:
|
||||||
|
Workspace(int id);
|
||||||
|
Workspace(WorkspaceDto dto);
|
||||||
|
int id() const { return id_; };
|
||||||
|
int active() const { return active_; };
|
||||||
|
std::string& select_icon(std::map<std::string, std::string>& icons_map);
|
||||||
|
void set_active(bool value = true) { active_ = value; };
|
||||||
|
Gtk::Button& button() { return button_; };
|
||||||
|
|
||||||
|
void update(const std::string& format, const std::string& icon);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int id_;
|
||||||
|
bool active_;
|
||||||
|
|
||||||
|
Gtk::Button button_;
|
||||||
|
Gtk::Box content_;
|
||||||
|
Gtk::Label label_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Workspaces : public AModule, public EventHandler {
|
||||||
|
public:
|
||||||
|
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
|
||||||
|
virtual ~Workspaces();
|
||||||
|
void update() override;
|
||||||
|
void init();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onEvent(const std::string&) override;
|
||||||
|
void sort_workspaces();
|
||||||
|
void create_workspace(int id);
|
||||||
|
void remove_workspace(int id);
|
||||||
|
|
||||||
|
std::string format_;
|
||||||
|
std::map<std::string, std::string> icons_map_;
|
||||||
|
bool with_icon_;
|
||||||
|
int active_workspace_id;
|
||||||
|
std::vector<std::unique_ptr<Workspace>> workspaces_;
|
||||||
|
std::vector<int> workspaces_to_create_;
|
||||||
|
std::vector<int> workspaces_to_remove_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
const Bar& bar_;
|
||||||
|
Gtk::Box box_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::hyprland
|
@ -24,12 +24,15 @@ class Image : public AModule {
|
|||||||
private:
|
private:
|
||||||
void delayWorker();
|
void delayWorker();
|
||||||
void handleEvent();
|
void handleEvent();
|
||||||
|
void parseOutputRaw();
|
||||||
|
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
Gtk::Image image_;
|
Gtk::Image image_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
|
std::string tooltip_;
|
||||||
int size_;
|
int size_;
|
||||||
int interval_;
|
int interval_;
|
||||||
|
util::command::res output_;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
};
|
};
|
||||||
|
@ -66,6 +66,8 @@ class Mpris : public ALabel {
|
|||||||
int album_len_;
|
int album_len_;
|
||||||
int title_len_;
|
int title_len_;
|
||||||
int dynamic_len_;
|
int dynamic_len_;
|
||||||
|
std::string dynamic_separator_;
|
||||||
|
std::vector<std::string> dynamic_order_;
|
||||||
std::vector<std::string> dynamic_prio_;
|
std::vector<std::string> dynamic_prio_;
|
||||||
bool truncate_hours_;
|
bool truncate_hours_;
|
||||||
bool tooltip_len_limits_;
|
bool tooltip_len_limits_;
|
||||||
@ -80,6 +82,7 @@ class Mpris : public ALabel {
|
|||||||
std::string lastPlayer;
|
std::string lastPlayer;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
|
std::chrono::time_point<std::chrono::system_clock> last_update_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::mpris
|
} // namespace waybar::modules::mpris
|
||||||
|
@ -78,7 +78,6 @@ class Network : public ALabel {
|
|||||||
int32_t signal_strength_dbm_;
|
int32_t signal_strength_dbm_;
|
||||||
uint8_t signal_strength_;
|
uint8_t signal_strength_;
|
||||||
std::string signal_strength_app_;
|
std::string signal_strength_app_;
|
||||||
float frequency_;
|
|
||||||
uint32_t route_priority;
|
uint32_t route_priority;
|
||||||
|
|
||||||
util::SleeperThread thread_;
|
util::SleeperThread thread_;
|
||||||
@ -86,6 +85,7 @@ class Network : public ALabel {
|
|||||||
#ifdef WANT_RFKILL
|
#ifdef WANT_RFKILL
|
||||||
util::Rfkill rfkill_;
|
util::Rfkill rfkill_;
|
||||||
#endif
|
#endif
|
||||||
|
float frequency_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules
|
} // namespace waybar::modules
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "ipc.hpp"
|
#include "ipc.hpp"
|
||||||
|
@ -74,6 +74,7 @@ class UPower : public AModule {
|
|||||||
bool showAltText;
|
bool showAltText;
|
||||||
bool upowerRunning;
|
bool upowerRunning;
|
||||||
guint upowerWatcher_id;
|
guint upowerWatcher_id;
|
||||||
|
std::string nativePath_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::upower
|
} // namespace waybar::modules::upower
|
||||||
|
@ -27,6 +27,8 @@ class Wireplumber : public ALabel {
|
|||||||
static void onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id);
|
static void onMixerChanged(waybar::modules::Wireplumber* self, uint32_t id);
|
||||||
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
|
static void onDefaultNodesApiChanged(waybar::modules::Wireplumber* self);
|
||||||
|
|
||||||
|
bool handleScroll(GdkEventScroll* e) override;
|
||||||
|
|
||||||
WpCore* wp_core_;
|
WpCore* wp_core_;
|
||||||
GPtrArray* apis_;
|
GPtrArray* apis_;
|
||||||
WpObjectManager* om_;
|
WpObjectManager* om_;
|
||||||
@ -36,6 +38,7 @@ class Wireplumber : public ALabel {
|
|||||||
uint32_t pending_plugins_;
|
uint32_t pending_plugins_;
|
||||||
bool muted_;
|
bool muted_;
|
||||||
double volume_;
|
double volume_;
|
||||||
|
double min_step_;
|
||||||
uint32_t node_id_{0};
|
uint32_t node_id_{0};
|
||||||
std::string node_name_;
|
std::string node_name_;
|
||||||
};
|
};
|
||||||
|
14
include/util/gtk_icon.hpp
Normal file
14
include/util/gtk_icon.hpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gtkmm/icontheme.h>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class DefaultGtkIconThemeWrapper {
|
||||||
|
private:
|
||||||
|
static std::mutex default_theme_mutex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool has_icon(const std::string&);
|
||||||
|
static Glib::RefPtr<Gdk::Pixbuf> load_icon(const char*, int, Gtk::IconLookupFlags);
|
||||||
|
};
|
9
include/util/prepare_for_sleep.h
Normal file
9
include/util/prepare_for_sleep.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SafeSignal.hpp"
|
||||||
|
|
||||||
|
namespace waybar::util {
|
||||||
|
|
||||||
|
// Get a signal emited with value true when entering sleep, and false when exiting
|
||||||
|
SafeSignal<bool>& prepare_for_sleep();
|
||||||
|
} // namespace waybar::util
|
@ -6,6 +6,8 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include "prepare_for_sleep.h"
|
||||||
|
|
||||||
namespace waybar::util {
|
namespace waybar::util {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +35,11 @@ class SleeperThread {
|
|||||||
signal_ = false;
|
signal_ = false;
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
}} {}
|
}} {
|
||||||
|
connection_ = prepare_for_sleep().connect([this](bool sleep) {
|
||||||
|
if (not sleep) wake_up();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
SleeperThread& operator=(std::function<void()> func) {
|
SleeperThread& operator=(std::function<void()> func) {
|
||||||
thread_ = std::thread([this, func] {
|
thread_ = std::thread([this, func] {
|
||||||
@ -42,6 +48,11 @@ class SleeperThread {
|
|||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (connection_.empty()) {
|
||||||
|
connection_ = prepare_for_sleep().connect([this](bool sleep) {
|
||||||
|
if (not sleep) wake_up();
|
||||||
|
});
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +72,7 @@ class SleeperThread {
|
|||||||
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
|
return condvar_.wait_until(lk, time_point, [this] { return signal_ || !do_run_; });
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wake_up() {
|
void wake_up() {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lck(mutex_);
|
std::lock_guard<std::mutex> lck(mutex_);
|
||||||
signal_ = true;
|
signal_ = true;
|
||||||
@ -96,6 +107,7 @@ class SleeperThread {
|
|||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
bool do_run_ = true;
|
bool do_run_ = true;
|
||||||
bool signal_ = false;
|
bool signal_ = false;
|
||||||
|
sigc::connection connection_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::util
|
} // namespace waybar::util
|
||||||
|
@ -1,105 +1,167 @@
|
|||||||
waybar-clock(5)
|
waybar-clock(5) "waybar-clock" "User Manual"
|
||||||
|
|
||||||
# NAME
|
# NAME
|
||||||
|
|
||||||
waybar - clock module
|
clock
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
The *clock* module displays the current date and time.
|
*clock* module displays current date and time
|
||||||
|
|
||||||
|
# FILES
|
||||||
|
|
||||||
|
$XDG_CONFIG_HOME/waybar/config ++
|
||||||
|
Per user configuration file
|
||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
*interval*: ++
|
1. Addressed by *clock*
|
||||||
typeof: integer ++
|
[- *Option*
|
||||||
default: 60 ++
|
:- *Typeof*
|
||||||
The interval in which the information gets polled.
|
:- *Default*
|
||||||
|
:- *Description*
|
||||||
|
|[ *interval*
|
||||||
|
:[ integer
|
||||||
|
:[ 60
|
||||||
|
:[ The interval in which the information gets polled
|
||||||
|
|[ *format*
|
||||||
|
:[ string
|
||||||
|
:[ *{:%H:%M}*
|
||||||
|
:[ The format, how the date and time should be displayed. See format options below
|
||||||
|
|[ *timezone*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ The timezone to display the time in, e.g. America/New_York. "" represents
|
||||||
|
the system's local timezone. See Wikipedia's unofficial list of timezones <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
|
||||||
|
|[ *timezones*
|
||||||
|
:[ list of strings
|
||||||
|
:[
|
||||||
|
:[ 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.
|
||||||
|
"" represents the system's local timezone
|
||||||
|
|[ *locale*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ A locale to be used to display the time. Intended to render times in custom
|
||||||
|
timezones with the proper language and format
|
||||||
|
|[ *max-length*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ The maximum length in character the module should display
|
||||||
|
|[ *rotate*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ Positive value to rotate the text label
|
||||||
|
|[ *on-click*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Command to execute when clicked on the module
|
||||||
|
|[ *on-click-middle*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Command to execute when you middle clicked on the module using mousewheel
|
||||||
|
|[ *on-click-right*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Command to execute when you right clicked on the module
|
||||||
|
|[ *on-scroll-up*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Command to execute when scrolling up on the module
|
||||||
|
|[ *on-scroll-down*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Command to execute when scrolling down on the module
|
||||||
|
|[ *smooth-scrolling-threshold*
|
||||||
|
:[ double
|
||||||
|
:[
|
||||||
|
:[ Threshold to be used when scrolling
|
||||||
|
|[ *tooltip*
|
||||||
|
:[ bool
|
||||||
|
:[ true
|
||||||
|
:[ Option to enable tooltip on hover
|
||||||
|
|[ *tooltip-format*
|
||||||
|
:[ string
|
||||||
|
:[ same as format
|
||||||
|
:[ Tooltip on hover
|
||||||
|
|
||||||
*format*: ++
|
View all valid format options in *strftime(3)* or have a look <https://fmt.dev/latest/syntax.html#chrono-specs>
|
||||||
typeof: string ++
|
|
||||||
default: {:%H:%M} ++
|
|
||||||
The format, how the date and time should be displayed. ++
|
|
||||||
It uses the format of the date library. See https://howardhinnant.github.io/date/date.html#to_stream_formatting for details.
|
|
||||||
|
|
||||||
*timezone*: ++
|
2. Addressed by *clock: calendar*
|
||||||
typeof: string ++
|
[- *Option*
|
||||||
default: inferred local timezone ++
|
:- *Typeof*
|
||||||
The timezone to display the time in, e.g. America/New_York. ++
|
:- *Default*
|
||||||
This field will be ignored if *timezones* field is set and have at least one value.
|
:- *Description*
|
||||||
|
|[ *mode*
|
||||||
|
:[ string
|
||||||
|
:[ month
|
||||||
|
:[ Calendar view mode. Possible values: year|month
|
||||||
|
|[ *mode-mon-col*
|
||||||
|
:[ integer
|
||||||
|
:[ 3
|
||||||
|
:[ Relevant for *mode=year*. Count of months per row
|
||||||
|
|[ *weeks-pos*
|
||||||
|
:[ integer
|
||||||
|
:[
|
||||||
|
:[ The position where week numbers should be displayed. Disabled when is empty.
|
||||||
|
Possible values: left|right
|
||||||
|
|[ *on-scroll*
|
||||||
|
:[ integer
|
||||||
|
:[ 1
|
||||||
|
:[ Value to scroll months/years forward/backward. Can be negative. Is
|
||||||
|
configured under *on-scroll* option
|
||||||
|
|
||||||
*timezones*: ++
|
3. Adressed by *clock: calendar: format*
|
||||||
typeof: list of strings ++
|
[- *Option*
|
||||||
A list of timezones to use for time display, changed using the scroll wheel. ++
|
:- *Typeof*
|
||||||
Use "" to represent the system's local timezone. Using %Z in the format or tooltip format is useful to track which time zone is currently displayed.
|
:- *Default*
|
||||||
|
:- *Description*
|
||||||
|
|[ *months*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Format is applied to months header(January, February,...etc.)
|
||||||
|
|[ *days*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Format is applied to days
|
||||||
|
|[ *weeks*
|
||||||
|
:[ string
|
||||||
|
:[ *{:%U}*
|
||||||
|
:[ Format is applied to week numbers. When weekday format is not provided then
|
||||||
|
is used default format: '{:%W}' when week starts with Monday, '{:%U}' otherwise
|
||||||
|
|[ *weekdays*
|
||||||
|
:[ string
|
||||||
|
:[
|
||||||
|
:[ Format is applied to weeks header(Su,Mo,...etc.)
|
||||||
|
|[ *today*
|
||||||
|
:[ string
|
||||||
|
:[ *<b><u>{}</u></b>*
|
||||||
|
:[ Format is applied to Today
|
||||||
|
|
||||||
*locale*: ++
|
## Actions
|
||||||
typeof: string ++
|
|
||||||
default: inferred from current locale ++
|
|
||||||
A locale to be used to display the time. Intended to render times in custom timezones with the proper language and format.
|
|
||||||
|
|
||||||
*today-format*: ++
|
[- *String*
|
||||||
typeof: string ++
|
:- *Action*
|
||||||
default: <b><u>{}</u></b> ++
|
|[ *mode*
|
||||||
The format of today's date in the calendar.
|
:[ Switch calendar mode between year/month
|
||||||
|
|[ *tz_up*
|
||||||
*max-length*: ++
|
:[ Switch to the next provided time zone
|
||||||
typeof: integer ++
|
|[ *tz_down*
|
||||||
The maximum length in character the module should display.
|
:[ Switch to the previous provided time zone
|
||||||
|
|[ *shift_up*
|
||||||
*min-length*: ++
|
:[ Switch to the next calendar month/year
|
||||||
typeof: integer ++
|
|[ *shift_down*
|
||||||
The minimum length in characters the module should take up.
|
:[ Switch to the previous calendar month/year
|
||||||
|
|
||||||
*align*: ++
|
|
||||||
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.
|
|
||||||
|
|
||||||
*rotate*: ++
|
|
||||||
typeof: integer ++
|
|
||||||
Positive value to rotate the text label.
|
|
||||||
|
|
||||||
*on-click*: ++
|
|
||||||
typeof: string ++
|
|
||||||
Command to execute when clicked on the module.
|
|
||||||
|
|
||||||
*on-click-middle*: ++
|
|
||||||
typeof: string ++
|
|
||||||
Command to execute when middle-clicked on the module using mousewheel.
|
|
||||||
|
|
||||||
*on-click-right*: ++
|
|
||||||
typeof: string ++
|
|
||||||
Command to execute when you right clicked on the module.
|
|
||||||
|
|
||||||
*on-update*: ++
|
|
||||||
typeof: string ++
|
|
||||||
Command to execute when the module is updated.
|
|
||||||
|
|
||||||
*on-scroll-up*: ++
|
|
||||||
typeof: string ++
|
|
||||||
Command to execute when scrolling up on the module.
|
|
||||||
|
|
||||||
*on-scroll-down*: ++
|
|
||||||
typeof: string ++
|
|
||||||
Command to execute when scrolling down on the module.
|
|
||||||
|
|
||||||
*smooth-scrolling-threshold*: ++
|
|
||||||
typeof: double ++
|
|
||||||
Threshold to be used when scrolling.
|
|
||||||
|
|
||||||
*tooltip*: ++
|
|
||||||
typeof: bool ++
|
|
||||||
default: true ++
|
|
||||||
Option to disable tooltip on hover.
|
|
||||||
|
|
||||||
View all valid format options in *strftime(3)*.
|
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{calendar}*: Current month calendar
|
- *{calendar}*: Current month calendar
|
||||||
*{timezoned_time_list}*: List of time in the rest timezones, if more than one timezone is set in the config
|
- *{timezoned_time_list}*: List of time in the rest timezones, if more than one timezone is set in the config
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
|
1. General
|
||||||
|
|
||||||
```
|
```
|
||||||
"clock": {
|
"clock": {
|
||||||
"interval": 60,
|
"interval": 60,
|
||||||
@ -108,6 +170,101 @@ View all valid format options in *strftime(3)*.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2. Calendar
|
||||||
|
|
||||||
|
```
|
||||||
|
"clock": {
|
||||||
|
"format": "{:%H:%M} ",
|
||||||
|
"format-alt": "{:%A, %B %d, %Y (%R)} ",
|
||||||
|
"tooltip-format": "<tt><small>{calendar}</small></tt>",
|
||||||
|
"calendar": {
|
||||||
|
"mode" : "year",
|
||||||
|
"mode-mon-col" : 3,
|
||||||
|
"weeks-pos" : "right",
|
||||||
|
"on-scroll" : 1,
|
||||||
|
"on-click-right": "mode",
|
||||||
|
"format": {
|
||||||
|
"months": "<span color='#ffead3'><b>{}</b></span>",
|
||||||
|
"days": "<span color='#ecc6d9'><b>{}</b></span>",
|
||||||
|
"weeks": "<span color='#99ffdd'><b>W{}</b></span>",
|
||||||
|
"weekdays": "<span color='#ffcc66'><b>{}</b></span>",
|
||||||
|
"today": "<span color='#ff6699'><b><u>{}</u></b></span>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"on-click-right": "mode",
|
||||||
|
"on-click-forward": "tz_up",
|
||||||
|
"on-click-backward": "tz_down",
|
||||||
|
"on-scroll-up": "shift_up",
|
||||||
|
"on-scroll-down": "shift_down"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Full date on hover
|
||||||
|
|
||||||
|
```
|
||||||
|
"clock": {
|
||||||
|
"interval": 60,
|
||||||
|
"tooltip": true,
|
||||||
|
"format": "{:%H.%M}",
|
||||||
|
"tooltip-format": "{:%Y-%m-%d}",
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
|
||||||
- *#clock*
|
- *#clock*
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
If clock module is disabled at startup with locale::facet::\_S\_create\_c\_locale ++
|
||||||
|
name not valid error message try one of the followings:
|
||||||
|
|
||||||
|
- check if LC_TIME is set properly (glibc)
|
||||||
|
- set locale to C in the config file (musl)
|
||||||
|
|
||||||
|
The locale option must be set for {calendar} to use the correct start-of-week, regardless of system locale.
|
||||||
|
|
||||||
|
## Calendar in Chinese. Alignment
|
||||||
|
|
||||||
|
In order to have aligned Chinese calendar there are some useful recommendations:
|
||||||
|
|
||||||
|
. Use "WenQuanYi Zen Hei Mono" which is provided in most Linux distributions
|
||||||
|
. Try different font sizes and find best for you. size = 9pt should be fine
|
||||||
|
. In case when "WenQuanYi Zen Hei Mono" font is used disable monospace font pango tag
|
||||||
|
|
||||||
|
Example of working config
|
||||||
|
|
||||||
|
```
|
||||||
|
"clock": {
|
||||||
|
"format": "{:%H:%M} ",
|
||||||
|
"format-alt": "{:%A, %B %d, %Y (%R)} ",
|
||||||
|
"tooltip-format": "\n<span size='9pt' font='WenQuanYi Zen Hei Mono'>{calendar}</span>",
|
||||||
|
"calendar": {
|
||||||
|
"mode" : "year",
|
||||||
|
"mode-mon-col" : 3,
|
||||||
|
"weeks-pos" : "right",
|
||||||
|
"on-scroll" : 1,
|
||||||
|
"on-click-right": "mode",
|
||||||
|
"format": {
|
||||||
|
"months": "<span color='#ffead3'><b>{}</b></span>",
|
||||||
|
"days": "<span color='#ecc6d9'><b>{}</b></span>",
|
||||||
|
"weeks": "<span color='#99ffdd'><b>W{}</b></span>",
|
||||||
|
"weekdays": "<span color='#ffcc66'><b>{}</b></span>",
|
||||||
|
"today": "<span color='#ff6699'><b><u>{}</u></b></span>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"on-click-right": "mode",
|
||||||
|
"on-click-forward": "tz_up",
|
||||||
|
"on-click-backward": "tz_down",
|
||||||
|
"on-scroll-up": "shift_up",
|
||||||
|
"on-scroll-down": "shift_down"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
# AUTHOR
|
||||||
|
|
||||||
|
Alexis Rouillard <contact@arouillard.fr>
|
||||||
|
59
man/waybar-hyprland-workspaces.5.scd
Normal file
59
man/waybar-hyprland-workspaces.5.scd
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
waybar-wlr-workspaces(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
|
||||||
|
waybar - hyprland workspaces module
|
||||||
|
|
||||||
|
# DESCRIPTION
|
||||||
|
|
||||||
|
The *workspaces* module displays the currently used workspaces in hyprland compositor.
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
Addressed by *hyprland/workspaces*
|
||||||
|
|
||||||
|
*format*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: {id} ++
|
||||||
|
The format, how information should be displayed.
|
||||||
|
|
||||||
|
*format-icons*: ++
|
||||||
|
typeof: array ++
|
||||||
|
Based on the workspace id and state, the corresponding icon gets selected. See *icons*.
|
||||||
|
|
||||||
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
|
*{id}*: id of workspace assigned by compositor
|
||||||
|
|
||||||
|
*{icon}*: Icon, as defined in *format-icons*.
|
||||||
|
|
||||||
|
# ICONS
|
||||||
|
|
||||||
|
Additional to workspace name matching, the following *format-icons* can be set.
|
||||||
|
|
||||||
|
- *default*: Will be shown, when no string match is found.
|
||||||
|
- *active*: Will be shown, when workspace is active
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
"wlr/workspaces": {
|
||||||
|
"format": "{name}: {icon}",
|
||||||
|
"format-icons": {
|
||||||
|
"1": "",
|
||||||
|
"2": "",
|
||||||
|
"3": "",
|
||||||
|
"4": "",
|
||||||
|
"5": "",
|
||||||
|
"active": "",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"sort-by-number": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Style
|
||||||
|
|
||||||
|
- *#workspaces*
|
||||||
|
- *#workspaces button*
|
||||||
|
- *#workspaces button.active*
|
@ -57,6 +57,20 @@ The *image* module displays an image from a path.
|
|||||||
typeof: double ++
|
typeof: double ++
|
||||||
Threshold to be used when scrolling.
|
Threshold to be used when scrolling.
|
||||||
|
|
||||||
|
*tooltip*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: true ++
|
||||||
|
Option to enable tooltip on hover.
|
||||||
|
|
||||||
|
# SCRIPT OUTPUT
|
||||||
|
|
||||||
|
Similar to the *custom* module, output values of the script is *newline* separated.
|
||||||
|
The following is the output format:
|
||||||
|
|
||||||
|
```
|
||||||
|
$path\\n$tooltip
|
||||||
|
```
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -71,11 +71,27 @@ The *mpris* module displays currently playing media via libplayerctl.
|
|||||||
something less than or equal to this value, so the title will always be ++
|
something less than or equal to this value, so the title will always be ++
|
||||||
displayed.
|
displayed.
|
||||||
|
|
||||||
*dynamic-priority*: ++
|
*dynamic-order*: ++
|
||||||
typeof: []string ++
|
typeof: []string ++
|
||||||
default: ["title", "length", "position", "artist", "album"] ++
|
default: ["title", "artist", "album", "position", "length"] ++
|
||||||
Priority of the tags when truncating the Dynamic tag (absence in this
|
Order of the tags shown by Dynamic tag. The position and length tags ++
|
||||||
list means force inclusion).
|
will always be combined in the format [{position}/{length}]. The order ++
|
||||||
|
of these tags in relation to other tags will be determined based on the ++
|
||||||
|
declaration of the first among the two tags. Absence in this list means ++
|
||||||
|
force exclusion.
|
||||||
|
|
||||||
|
*dynamic-importance-order*: ++
|
||||||
|
typeof: []string ++
|
||||||
|
default: ["title", "artist", "album", "position", "length"] ++
|
||||||
|
Priority of the tags when truncating the Dynamic tag. The final ones ++
|
||||||
|
will be the first to be truncated. Absence in this list means force ++
|
||||||
|
inclusion.
|
||||||
|
|
||||||
|
*dynamic-separator*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: " - " ++
|
||||||
|
These characters will be used to separate two different tags, except ++
|
||||||
|
when one of these tags is position and length.
|
||||||
|
|
||||||
*truncate-hours*: ++
|
*truncate-hours*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
|
@ -91,6 +91,10 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
|
|||||||
typeof: double ++
|
typeof: double ++
|
||||||
Threshold to be used when scrolling.
|
Threshold to be used when scrolling.
|
||||||
|
|
||||||
|
*reverse-scrolling*: ++
|
||||||
|
typeof: bool ++
|
||||||
|
Option to reverse the scroll direction.
|
||||||
|
|
||||||
*tooltip*: ++
|
*tooltip*: ++
|
||||||
typeof: bool ++
|
typeof: bool ++
|
||||||
default: true ++
|
default: true ++
|
||||||
|
@ -77,6 +77,11 @@ Addressed by *sway/workspaces*
|
|||||||
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: ++
|
||||||
|
typeof: bool ++
|
||||||
|
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.
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{value}*: Name of the workspace, as defined by sway.
|
*{value}*: Name of the workspace, as defined by sway.
|
||||||
@ -87,6 +92,8 @@ Addressed by *sway/workspaces*
|
|||||||
|
|
||||||
*{index}*: Index of the workspace.
|
*{index}*: Index of the workspace.
|
||||||
|
|
||||||
|
*{output}*: Output where the workspace is located.
|
||||||
|
|
||||||
# ICONS
|
# ICONS
|
||||||
|
|
||||||
Additional to workspace name matching, the following *format-icons* can be set.
|
Additional to workspace name matching, the following *format-icons* can be set.
|
||||||
|
@ -19,6 +19,8 @@ Addressed by *temperature*
|
|||||||
*hwmon-path*: ++
|
*hwmon-path*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*.
|
The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*.
|
||||||
|
This can also be an array of strings. In this case, waybar will check each item in the array and use the first valid one.
|
||||||
|
This is suitable if you want to share the same configuration file among different machines with different hardware configurations.
|
||||||
|
|
||||||
*hwmon-path-abs*: ++
|
*hwmon-path-abs*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
@ -117,7 +119,7 @@ Addressed by *temperature*
|
|||||||
```
|
```
|
||||||
"temperature": {
|
"temperature": {
|
||||||
// "thermal-zone": 2,
|
// "thermal-zone": 2,
|
||||||
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
|
// "hwmon-path": ["/sys/class/hwmon/hwmon2/temp1_input", "/sys/class/thermal/thermal_zone0/temp"],
|
||||||
// "critical-threshold": 80,
|
// "critical-threshold": 80,
|
||||||
// "format-critical": "{temperatureC}°C ",
|
// "format-critical": "{temperatureC}°C ",
|
||||||
"format": "{temperatureC}°C "
|
"format": "{temperatureC}°C "
|
||||||
|
@ -11,6 +11,12 @@ compatible devices in the tooltip.
|
|||||||
|
|
||||||
# CONFIGURATION
|
# CONFIGURATION
|
||||||
|
|
||||||
|
*native-path*: ++
|
||||||
|
typeof: string ++
|
||||||
|
default: ++
|
||||||
|
The battery to monitor. Refer to the https://upower.freedesktop.org/docs/UpDevice.html#UpDevice--native-path ++
|
||||||
|
Can be obtained using `upower --dump`
|
||||||
|
|
||||||
*icon-size*: ++
|
*icon-size*: ++
|
||||||
typeof: integer ++
|
typeof: integer ++
|
||||||
default: 20 ++
|
default: 20 ++
|
||||||
@ -68,6 +74,25 @@ depending on the charging state.
|
|||||||
"tooltip-spacing": 20
|
"tooltip-spacing": 20
|
||||||
}
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
```
|
||||||
|
"upower": {
|
||||||
|
"native-path": "/org/bluez/hci0/dev_D4_AE_41_38_D0_EF",
|
||||||
|
"icon-size": 20,
|
||||||
|
"hide-if-empty": true,
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-spacing": 20
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
```
|
||||||
|
"upower": {
|
||||||
|
"native-path": "battery_sony_controller_battery_d0o27o88o32ofcoee",
|
||||||
|
"icon-size": 20,
|
||||||
|
"hide-if-empty": true,
|
||||||
|
"tooltip": true,
|
||||||
|
"tooltip-spacing": 20
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# STYLE
|
# STYLE
|
||||||
|
@ -49,6 +49,11 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
|
|||||||
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*: ++
|
||||||
|
typeof: float ++
|
||||||
|
default: 1.0 ++
|
||||||
|
The speed in which to change the volume when scrolling.
|
||||||
|
|
||||||
*on-click*: ++
|
*on-click*: ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
Command to execute when clicked on the module.
|
Command to execute when clicked on the module.
|
||||||
@ -65,6 +70,19 @@ The *wireplumber* module displays the current volume reported by WirePlumber.
|
|||||||
typeof: string ++
|
typeof: string ++
|
||||||
Command to execute when the module is updated.
|
Command to execute when the module is updated.
|
||||||
|
|
||||||
|
*on-scroll-up*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling up on the module. This replaces the default behaviour of volume control.
|
||||||
|
|
||||||
|
*on-scroll-down*: ++
|
||||||
|
typeof: string ++
|
||||||
|
Command to execute when scrolling down on the module. This replaces the default behaviour of volume control.
|
||||||
|
|
||||||
|
*max-volume*: ++
|
||||||
|
typeof: float ++
|
||||||
|
default: 100 ++
|
||||||
|
The maximum volume that can be set, in percentage.
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{volume}*: Volume in percentage.
|
*{volume}*: Volume in percentage.
|
||||||
|
@ -81,6 +81,10 @@ Addressed by *wlr/taskbar*
|
|||||||
typeof: object ++
|
typeof: object ++
|
||||||
Dictionary of app_id to be replaced with
|
Dictionary of app_id to be replaced with
|
||||||
|
|
||||||
|
*rewrite*: ++
|
||||||
|
typeof: object ++
|
||||||
|
Rules to rewrite the module format output. See *rewrite rules*.
|
||||||
|
|
||||||
# FORMAT REPLACEMENTS
|
# FORMAT REPLACEMENTS
|
||||||
|
|
||||||
*{icon}*: The icon of the application.
|
*{icon}*: The icon of the application.
|
||||||
@ -109,6 +113,18 @@ Addressed by *wlr/taskbar*
|
|||||||
|
|
||||||
*close*: Close the application.
|
*close*: Close the application.
|
||||||
|
|
||||||
|
# REWRITE RULES
|
||||||
|
|
||||||
|
*rewrite* is an object where keys are regular expressions and values are
|
||||||
|
rewrite rules if the expression matches. Rules may contain references to
|
||||||
|
captures of the expression.
|
||||||
|
|
||||||
|
Regular expression and replacement follow ECMA-script rules.
|
||||||
|
|
||||||
|
If no expression matches, the format output is left unchanged.
|
||||||
|
|
||||||
|
Invalid expressions (e.g., mismatched parentheses) are skipped.
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -124,6 +140,10 @@ Addressed by *wlr/taskbar*
|
|||||||
],
|
],
|
||||||
"app_ids-mapping": {
|
"app_ids-mapping": {
|
||||||
"firefoxdeveloperedition": "firefox-developer-edition"
|
"firefoxdeveloperedition": "firefox-developer-edition"
|
||||||
|
},
|
||||||
|
"rewrite": {
|
||||||
|
"Firefox Web Browser": "Firefox",
|
||||||
|
"Foot Server": "Terminal"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -65,7 +65,7 @@ Addressed by *wlr/workspaces*
|
|||||||
Additional to workspace name matching, the following *format-icons* can be set.
|
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.
|
||||||
- *focused*: Will be shown, when workspace is focused
|
- *active*: Will be shown, when workspace is active
|
||||||
|
|
||||||
# EXAMPLES
|
# EXAMPLES
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ Additional to workspace name matching, the following *format-icons* can be set.
|
|||||||
"3": "",
|
"3": "",
|
||||||
"4": "",
|
"4": "",
|
||||||
"5": "",
|
"5": "",
|
||||||
"focused": "",
|
"active": "",
|
||||||
"default": ""
|
"default": ""
|
||||||
},
|
},
|
||||||
"sort-by-number": true
|
"sort-by-number": true
|
||||||
|
@ -30,6 +30,7 @@ Also a minimal example configuration can be found on the at the bottom of this m
|
|||||||
*output* ++
|
*output* ++
|
||||||
typeof: string|array ++
|
typeof: string|array ++
|
||||||
Specifies on which screen this bar will be displayed. Exclamation mark(*!*) can be used to exclude specific output.
|
Specifies on which screen this bar will be displayed. Exclamation mark(*!*) can be used to exclude specific output.
|
||||||
|
Output specification follows sway's and can either be the output port such as "HDMI-A-1" or a string consisting of the make, model and serial such as "Some Company ABC123 0x00000000". See *sway-output(5)* for details.
|
||||||
In an array, star '*\**' can be used at the end to accept all outputs, in case all previous entries are exclusions.
|
In an array, star '*\**' can be used at the end to accept all outputs, in case all previous entries are exclusions.
|
||||||
|
|
||||||
*position* ++
|
*position* ++
|
||||||
@ -78,7 +79,12 @@ Also a minimal example configuration can be found on the at the bottom of this m
|
|||||||
Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++
|
Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++
|
||||||
Note: *hide* and *invisible* modes may be not as useful without Sway IPC.
|
Note: *hide* and *invisible* modes may be not as useful without Sway IPC.
|
||||||
|
|
||||||
modifier-reset ++
|
*start_hidden* ++
|
||||||
|
typeof: bool ++
|
||||||
|
default: *false* ++
|
||||||
|
Option to start the bar hidden.
|
||||||
|
|
||||||
|
*modifier-reset* ++
|
||||||
typeof: string ++
|
typeof: string ++
|
||||||
default: *press*
|
default: *press*
|
||||||
Defines the timing of modifier key to reset the bar visibility.
|
Defines the timing of modifier key to reset the bar visibility.
|
||||||
@ -288,3 +294,7 @@ Valid options for the (optional) "orientation" property are: "horizontal", "vert
|
|||||||
- *waybar-wlr-workspaces(5)*
|
- *waybar-wlr-workspaces(5)*
|
||||||
- *waybar-temperature(5)*
|
- *waybar-temperature(5)*
|
||||||
- *waybar-tray(5)*
|
- *waybar-tray(5)*
|
||||||
|
|
||||||
|
# SEE ALSO
|
||||||
|
|
||||||
|
*sway-output(5)*
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.9.18',
|
version: '0.9.19',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>= 0.50.0',
|
meson_version: '>= 0.50.0',
|
||||||
default_options : [
|
default_options : [
|
||||||
@ -170,9 +170,11 @@ src_files = files(
|
|||||||
'src/client.cpp',
|
'src/client.cpp',
|
||||||
'src/config.cpp',
|
'src/config.cpp',
|
||||||
'src/group.cpp',
|
'src/group.cpp',
|
||||||
|
'src/util/prepare_for_sleep.cpp',
|
||||||
'src/util/ustring_clen.cpp',
|
'src/util/ustring_clen.cpp',
|
||||||
'src/util/sanitize_str.cpp',
|
'src/util/sanitize_str.cpp',
|
||||||
'src/util/rewrite_string.cpp'
|
'src/util/rewrite_string.cpp',
|
||||||
|
'src/util/gtk_icon.cpp'
|
||||||
)
|
)
|
||||||
|
|
||||||
inc_dirs = ['include']
|
inc_dirs = ['include']
|
||||||
@ -240,6 +242,7 @@ if true
|
|||||||
src_files += 'src/modules/hyprland/window.cpp'
|
src_files += 'src/modules/hyprland/window.cpp'
|
||||||
src_files += 'src/modules/hyprland/language.cpp'
|
src_files += 'src/modules/hyprland/language.cpp'
|
||||||
src_files += 'src/modules/hyprland/submap.cpp'
|
src_files += 'src/modules/hyprland/submap.cpp'
|
||||||
|
src_files += 'src/modules/hyprland/workspaces.cpp'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if libnl.found() and libnlgen.found()
|
if libnl.found() and libnlgen.found()
|
||||||
|
127
nix/default.nix
127
nix/default.nix
@ -1,60 +1,11 @@
|
|||||||
{ lib
|
{ lib
|
||||||
, stdenv
|
, waybar
|
||||||
, fetchFromGitHub
|
|
||||||
, meson
|
|
||||||
, pkg-config
|
|
||||||
, ninja
|
|
||||||
, wrapGAppsHook
|
|
||||||
, wayland
|
|
||||||
, wlroots
|
|
||||||
, gtkmm3
|
|
||||||
, libsigcxx
|
|
||||||
, jsoncpp
|
|
||||||
, scdoc
|
|
||||||
, spdlog
|
|
||||||
, gtk-layer-shell
|
|
||||||
, howard-hinnant-date
|
|
||||||
, libinotify-kqueue
|
|
||||||
, libxkbcommon
|
|
||||||
, evdevSupport ? true
|
|
||||||
, libevdev
|
|
||||||
, inputSupport ? true
|
|
||||||
, libinput
|
|
||||||
, jackSupport ? true
|
|
||||||
, libjack2
|
|
||||||
, mpdSupport ? true
|
|
||||||
, libmpdclient
|
|
||||||
, nlSupport ? true
|
|
||||||
, libnl
|
|
||||||
, pulseSupport ? true
|
|
||||||
, libpulseaudio
|
|
||||||
, rfkillSupport ? true
|
|
||||||
, runTests ? true
|
|
||||||
, catch2_3
|
|
||||||
, sndioSupport ? true
|
|
||||||
, sndio
|
|
||||||
, swaySupport ? true
|
|
||||||
, sway
|
|
||||||
, traySupport ? true
|
|
||||||
, libdbusmenu-gtk3
|
|
||||||
, udevSupport ? true
|
|
||||||
, udev
|
|
||||||
, upowerSupport ? true
|
|
||||||
, upower
|
|
||||||
, wireplumberSupport ? true
|
|
||||||
, wireplumber
|
|
||||||
, withMediaPlayer ? false
|
|
||||||
, glib
|
|
||||||
, gobject-introspection
|
|
||||||
, python3
|
|
||||||
, playerctl
|
|
||||||
, version
|
, version
|
||||||
}:
|
}:
|
||||||
|
|
||||||
stdenv.mkDerivation rec {
|
waybar.overrideAttrs (prev: {
|
||||||
pname = "waybar";
|
|
||||||
inherit version;
|
inherit version;
|
||||||
# version = "0.9.16";
|
# version = "0.9.17";
|
||||||
|
|
||||||
src = lib.cleanSourceWith {
|
src = lib.cleanSourceWith {
|
||||||
filter = name: type:
|
filter = name: type:
|
||||||
@ -66,74 +17,4 @@ stdenv.mkDerivation rec {
|
|||||||
);
|
);
|
||||||
src = lib.cleanSource ../.;
|
src = lib.cleanSource ../.;
|
||||||
};
|
};
|
||||||
|
})
|
||||||
nativeBuildInputs = [
|
|
||||||
meson
|
|
||||||
ninja
|
|
||||||
pkg-config
|
|
||||||
scdoc
|
|
||||||
wrapGAppsHook
|
|
||||||
] ++ lib.optional withMediaPlayer gobject-introspection;
|
|
||||||
|
|
||||||
propagatedBuildInputs = lib.optionals withMediaPlayer [
|
|
||||||
glib
|
|
||||||
playerctl
|
|
||||||
python3.pkgs.pygobject3
|
|
||||||
];
|
|
||||||
strictDeps = false;
|
|
||||||
|
|
||||||
buildInputs = with lib;
|
|
||||||
[ wayland wlroots gtkmm3 libsigcxx jsoncpp spdlog gtk-layer-shell howard-hinnant-date libxkbcommon ]
|
|
||||||
++ optional (!stdenv.isLinux) libinotify-kqueue
|
|
||||||
++ optional evdevSupport libevdev
|
|
||||||
++ optional inputSupport libinput
|
|
||||||
++ optional jackSupport libjack2
|
|
||||||
++ optional mpdSupport libmpdclient
|
|
||||||
++ optional nlSupport libnl
|
|
||||||
++ optional pulseSupport libpulseaudio
|
|
||||||
++ optional sndioSupport sndio
|
|
||||||
++ optional swaySupport sway
|
|
||||||
++ optional traySupport libdbusmenu-gtk3
|
|
||||||
++ optional udevSupport udev
|
|
||||||
++ optional upowerSupport upower
|
|
||||||
++ optional wireplumberSupport wireplumber;
|
|
||||||
|
|
||||||
checkInputs = [ catch2_3 ];
|
|
||||||
doCheck = runTests;
|
|
||||||
|
|
||||||
mesonFlags = (lib.mapAttrsToList
|
|
||||||
(option: enable: "-D${option}=${if enable then "enabled" else "disabled"}")
|
|
||||||
{
|
|
||||||
dbusmenu-gtk = traySupport;
|
|
||||||
jack = jackSupport;
|
|
||||||
libinput = inputSupport;
|
|
||||||
libnl = nlSupport;
|
|
||||||
libudev = udevSupport;
|
|
||||||
mpd = mpdSupport;
|
|
||||||
pulseaudio = pulseSupport;
|
|
||||||
rfkill = rfkillSupport;
|
|
||||||
sndio = sndioSupport;
|
|
||||||
tests = runTests;
|
|
||||||
upower_glib = upowerSupport;
|
|
||||||
wireplumber = wireplumberSupport;
|
|
||||||
}
|
|
||||||
) ++ [
|
|
||||||
"-Dsystemd=disabled"
|
|
||||||
"-Dgtk-layer-shell=enabled"
|
|
||||||
"-Dman-pages=enabled"
|
|
||||||
];
|
|
||||||
|
|
||||||
preFixup = lib.optionalString withMediaPlayer ''
|
|
||||||
cp $src/resources/custom_modules/mediaplayer.py $out/bin/waybar-mediaplayer.py
|
|
||||||
wrapProgram $out/bin/waybar-mediaplayer.py \
|
|
||||||
--prefix PYTHONPATH : "$PYTHONPATH:$out/${python3.sitePackages}"
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Highly customizable Wayland bar for Sway and Wlroots based compositors";
|
|
||||||
license = licenses.mit;
|
|
||||||
maintainers = with maintainers; [ FlorianFranzen minijackson synthetica lovesegfault ];
|
|
||||||
platforms = platforms.unix;
|
|
||||||
homepage = "https://github.com/alexays/waybar";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// "sway/workspaces": {
|
// "sway/workspaces": {
|
||||||
// "disable-scroll": true,
|
// "disable-scroll": true,
|
||||||
// "all-outputs": true,
|
// "all-outputs": true,
|
||||||
|
// "warp-on-scroll": false,
|
||||||
// "format": "{name}: {icon}",
|
// "format": "{name}: {icon}",
|
||||||
// "format-icons": {
|
// "format-icons": {
|
||||||
// "1": "",
|
// "1": "",
|
||||||
|
@ -97,11 +97,21 @@ bool AModule::handleToggle(GdkEventButton* const& e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) {
|
AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) {
|
||||||
|
// only affects up/down
|
||||||
|
bool reverse = config_["reverse-scrolling"].asBool();
|
||||||
|
bool reverse_mouse = config_["reverse-mouse-scrolling"].asBool();
|
||||||
|
|
||||||
|
// ignore reverse-scrolling if event comes from a mouse wheel
|
||||||
|
GdkDevice* device = gdk_event_get_source_device((GdkEvent*)e);
|
||||||
|
if (device != NULL && gdk_device_get_source(device) == GDK_SOURCE_MOUSE) {
|
||||||
|
reverse = reverse_mouse;
|
||||||
|
}
|
||||||
|
|
||||||
switch (e->direction) {
|
switch (e->direction) {
|
||||||
case GDK_SCROLL_UP:
|
case GDK_SCROLL_UP:
|
||||||
return SCROLL_DIR::UP;
|
return reverse ? SCROLL_DIR::DOWN : SCROLL_DIR::UP;
|
||||||
case GDK_SCROLL_DOWN:
|
case GDK_SCROLL_DOWN:
|
||||||
return SCROLL_DIR::DOWN;
|
return reverse ? SCROLL_DIR::UP : SCROLL_DIR::DOWN;
|
||||||
case GDK_SCROLL_LEFT:
|
case GDK_SCROLL_LEFT:
|
||||||
return SCROLL_DIR::LEFT;
|
return SCROLL_DIR::LEFT;
|
||||||
case GDK_SCROLL_RIGHT:
|
case GDK_SCROLL_RIGHT:
|
||||||
@ -118,9 +128,9 @@ AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (distance_scrolled_y_ < -threshold) {
|
if (distance_scrolled_y_ < -threshold) {
|
||||||
dir = SCROLL_DIR::UP;
|
dir = reverse ? SCROLL_DIR::DOWN : SCROLL_DIR::UP;
|
||||||
} else if (distance_scrolled_y_ > threshold) {
|
} else if (distance_scrolled_y_ > threshold) {
|
||||||
dir = SCROLL_DIR::DOWN;
|
dir = reverse ? SCROLL_DIR::UP : SCROLL_DIR::DOWN;
|
||||||
} else if (distance_scrolled_x_ > threshold) {
|
} else if (distance_scrolled_x_ > threshold) {
|
||||||
dir = SCROLL_DIR::RIGHT;
|
dir = SCROLL_DIR::RIGHT;
|
||||||
} else if (distance_scrolled_x_ < -threshold) {
|
} else if (distance_scrolled_x_ < -threshold) {
|
||||||
|
@ -593,6 +593,10 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
|
|||||||
setMode(MODE_DEFAULT);
|
setMode(MODE_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config["start_hidden"].asBool()) {
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
|
||||||
|
|
||||||
#if HAVE_SWAY
|
#if HAVE_SWAY
|
||||||
|
@ -83,6 +83,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
|||||||
if (ref == "hyprland/submap") {
|
if (ref == "hyprland/submap") {
|
||||||
return new waybar::modules::hyprland::Submap(id, bar_, config_[name]);
|
return new waybar::modules::hyprland::Submap(id, bar_, config_[name]);
|
||||||
}
|
}
|
||||||
|
if (ref == "hyprland/workspaces") {
|
||||||
|
return new waybar::modules::hyprland::Workspaces(id, bar_, config_[name]);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ref == "idle_inhibitor") {
|
if (ref == "idle_inhibitor") {
|
||||||
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
||||||
|
@ -305,14 +305,6 @@ bool waybar::modules::Backlight::handleScroll(GdkEventScroll *e) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_["reverse-scrolling"].asBool()) {
|
|
||||||
if (dir == SCROLL_DIR::UP) {
|
|
||||||
dir = SCROLL_DIR::DOWN;
|
|
||||||
} else if (dir == SCROLL_DIR::DOWN) {
|
|
||||||
dir = SCROLL_DIR::UP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get scroll step
|
// Get scroll step
|
||||||
double step = 1;
|
double step = 1;
|
||||||
|
|
||||||
|
@ -102,7 +102,6 @@ waybar::modules::Cava::Cava(const std::string& id, const Json::Value& config)
|
|||||||
thread_fetch_input_ = [this] {
|
thread_fetch_input_ = [this] {
|
||||||
thread_fetch_input_.sleep_for(fetch_input_delay_);
|
thread_fetch_input_.sleep_for(fetch_input_delay_);
|
||||||
input_source_(&audio_data_);
|
input_source_(&audio_data_);
|
||||||
dp.emit();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
thread_ = [this] {
|
thread_ = [this] {
|
||||||
|
@ -22,14 +22,20 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
|
|||||||
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() || zone_name.asString().empty()) continue;
|
if (!zone_name.isString()) continue;
|
||||||
|
if (zone_name.asString().empty())
|
||||||
|
time_zones_.push_back(date::current_zone());
|
||||||
|
else
|
||||||
try {
|
try {
|
||||||
time_zones_.push_back(date::locate_zone(zone_name.asString()));
|
time_zones_.push_back(date::locate_zone(zone_name.asString()));
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::warn("Timezone: {0}. {1}", zone_name.asString(), e.what());
|
spdlog::warn("Timezone: {0}. {1}", zone_name.asString(), e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (config_["timezone"].isString() && !config_["timezone"].asString().empty()) {
|
} else if (config_["timezone"].isString()) {
|
||||||
|
if (config_["timezone"].asString().empty())
|
||||||
|
time_zones_.push_back(date::current_zone());
|
||||||
|
else
|
||||||
try {
|
try {
|
||||||
time_zones_.push_back(date::locate_zone(config_["timezone"].asString()));
|
time_zones_.push_back(date::locate_zone(config_["timezone"].asString()));
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -72,7 +72,7 @@ static void handle_global(void *data, struct wl_registry *registry, uint32_t nam
|
|||||||
const char *interface, uint32_t version) {
|
const char *interface, uint32_t version) {
|
||||||
if (std::strcmp(interface, zdwl_ipc_manager_v2_interface.name) == 0) {
|
if (std::strcmp(interface, zdwl_ipc_manager_v2_interface.name) == 0) {
|
||||||
static_cast<Tags *>(data)->status_manager_ = static_cast<struct zdwl_ipc_manager_v2 *>(
|
static_cast<Tags *>(data)->status_manager_ = static_cast<struct zdwl_ipc_manager_v2 *>(
|
||||||
(zdwl_ipc_manager_v2 *)wl_registry_bind(registry, name, &zdwl_ipc_manager_v2_interface, 3));
|
(zdwl_ipc_manager_v2 *)wl_registry_bind(registry, name, &zdwl_ipc_manager_v2_interface, 1));
|
||||||
}
|
}
|
||||||
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
if (std::strcmp(interface, wl_seat_interface.name) == 0) {
|
||||||
version = std::min<uint32_t>(version, 1);
|
version = std::min<uint32_t>(version, 1);
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
#include "glibmm/ustring.h"
|
#include "glibmm/ustring.h"
|
||||||
#include "glibmm/variant.h"
|
#include "glibmm/variant.h"
|
||||||
#include "glibmm/varianttype.h"
|
#include "glibmm/varianttype.h"
|
||||||
#include "gtkmm/icontheme.h"
|
|
||||||
#include "gtkmm/label.h"
|
#include "gtkmm/label.h"
|
||||||
#include "gtkmm/tooltip.h"
|
#include "gtkmm/tooltip.h"
|
||||||
|
#include "util/gtk_icon.hpp"
|
||||||
|
|
||||||
namespace waybar::modules {
|
namespace waybar::modules {
|
||||||
Gamemode::Gamemode(const std::string& id, const Json::Value& config)
|
Gamemode::Gamemode(const std::string& id, const Json::Value& config)
|
||||||
@ -224,7 +224,7 @@ auto Gamemode::update() -> void {
|
|||||||
label_.set_markup(str);
|
label_.set_markup(str);
|
||||||
|
|
||||||
if (useIcon) {
|
if (useIcon) {
|
||||||
if (!Gtk::IconTheme::get_default()->has_icon(iconName)) {
|
if (!DefaultGtkIconThemeWrapper::has_icon(iconName)) {
|
||||||
iconName = DEFAULT_ICON_NAME;
|
iconName = DEFAULT_ICON_NAME;
|
||||||
}
|
}
|
||||||
icon_.set_from_icon_name(iconName, Gtk::ICON_SIZE_INVALID);
|
icon_.set_from_icon_name(iconName, Gtk::ICON_SIZE_INVALID);
|
||||||
|
@ -181,17 +181,25 @@ std::string IPC::getSocket1Reply(const std::string& rq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char buffer[8192] = {0};
|
char buffer[8192] = {0};
|
||||||
|
std::string response;
|
||||||
|
|
||||||
|
do {
|
||||||
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
sizeWritten = read(SERVERSOCKET, buffer, 8192);
|
||||||
|
|
||||||
if (sizeWritten < 0) {
|
if (sizeWritten < 0) {
|
||||||
spdlog::error("Hyprland IPC: Couldn't read (5)");
|
spdlog::error("Hyprland IPC: Couldn't read (5)");
|
||||||
|
close(SERVERSOCKET);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
response.append(buffer, sizeWritten);
|
||||||
|
} while (sizeWritten == 8192);
|
||||||
|
|
||||||
close(SERVERSOCKET);
|
close(SERVERSOCKET);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
return std::string(buffer);
|
Json::Value IPC::getSocket1JsonReply(const std::string& rq) {
|
||||||
|
return parser_.parse(getSocket1Reply("j/" + rq));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
@ -22,7 +22,7 @@ Language::Language(const std::string& id, const Bar& bar, const Json::Value& con
|
|||||||
initLanguage();
|
initLanguage();
|
||||||
|
|
||||||
label_.hide();
|
label_.hide();
|
||||||
ALabel::update();
|
update();
|
||||||
|
|
||||||
// register for hyprland ipc
|
// register for hyprland ipc
|
||||||
gIPC->registerForIPC("activelayout", this);
|
gIPC->registerForIPC("activelayout", this);
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <util/sanitize_str.hpp>
|
#include <util/sanitize_str.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "modules/hyprland/backend.hpp"
|
#include "modules/hyprland/backend.hpp"
|
||||||
#include "util/command.hpp"
|
|
||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
#include "util/rewrite_string.hpp"
|
#include "util/rewrite_string.hpp"
|
||||||
|
|
||||||
@ -15,17 +16,21 @@ namespace waybar::modules::hyprland {
|
|||||||
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
|
||||||
: ALabel(config, "window", id, "{}", 0, true), bar_(bar) {
|
: ALabel(config, "window", id, "{}", 0, true), bar_(bar) {
|
||||||
modulesReady = true;
|
modulesReady = true;
|
||||||
separate_outputs = config["separate-outputs"].as<bool>();
|
separate_outputs = config["separate-outputs"].asBool();
|
||||||
|
|
||||||
if (!gIPC.get()) {
|
if (!gIPC.get()) {
|
||||||
gIPC = std::make_unique<IPC>();
|
gIPC = std::make_unique<IPC>();
|
||||||
}
|
}
|
||||||
|
|
||||||
label_.hide();
|
queryActiveWorkspace();
|
||||||
ALabel::update();
|
update();
|
||||||
|
|
||||||
// register for hyprland ipc
|
// register for hyprland ipc
|
||||||
gIPC->registerForIPC("activewindow", this);
|
gIPC->registerForIPC("activewindow", this);
|
||||||
|
gIPC->registerForIPC("closewindow", this);
|
||||||
|
gIPC->registerForIPC("movewindow", this);
|
||||||
|
gIPC->registerForIPC("changefloatingmode", this);
|
||||||
|
gIPC->registerForIPC("fullscreen", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::~Window() {
|
Window::~Window() {
|
||||||
@ -38,63 +43,136 @@ auto Window::update() -> void {
|
|||||||
// fix ampersands
|
// fix ampersands
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
|
||||||
|
std::string window_name = waybar::util::sanitize_string(workspace_.last_window_title);
|
||||||
|
|
||||||
|
if (window_name != last_title_) {
|
||||||
|
if (window_name.empty()) {
|
||||||
|
label_.get_style_context()->add_class("empty");
|
||||||
|
} else {
|
||||||
|
label_.get_style_context()->remove_class("empty");
|
||||||
|
}
|
||||||
|
last_title_ = window_name;
|
||||||
|
}
|
||||||
|
|
||||||
if (!format_.empty()) {
|
if (!format_.empty()) {
|
||||||
label_.show();
|
label_.show();
|
||||||
label_.set_markup(fmt::format(fmt::runtime(format_),
|
label_.set_markup(fmt::format(fmt::runtime(format_),
|
||||||
waybar::util::rewriteString(lastView, config_["rewrite"])));
|
waybar::util::rewriteString(window_name, config_["rewrite"])));
|
||||||
} else {
|
} else {
|
||||||
label_.hide();
|
label_.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setClass("empty", workspace_.windows == 0);
|
||||||
|
setClass("solo", solo_);
|
||||||
|
setClass("fullscreen", fullscreen_);
|
||||||
|
setClass("floating", all_floating_);
|
||||||
|
|
||||||
|
if (!last_solo_class_.empty() && solo_class_ != last_solo_class_) {
|
||||||
|
if (bar_.window.get_style_context()->has_class(last_solo_class_)) {
|
||||||
|
bar_.window.get_style_context()->remove_class(last_solo_class_);
|
||||||
|
spdlog::trace("Removing solo class: {}", last_solo_class_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!solo_class_.empty() && solo_class_ != last_solo_class_) {
|
||||||
|
bar_.window.get_style_context()->add_class(solo_class_);
|
||||||
|
spdlog::trace("Adding solo class: {}", solo_class_);
|
||||||
|
}
|
||||||
|
last_solo_class_ = solo_class_;
|
||||||
|
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Window::getActiveWorkspaceID(std::string monitorName) {
|
auto Window::getActiveWorkspace() -> Workspace {
|
||||||
auto cmd = waybar::util::command::exec("hyprctl monitors -j");
|
const auto workspace = gIPC->getSocket1JsonReply("activeworkspace");
|
||||||
assert(cmd.exit_code == 0);
|
assert(workspace.isObject());
|
||||||
Json::Value json = parser_.parse(cmd.out);
|
return Workspace::parse(workspace);
|
||||||
assert(json.isArray());
|
}
|
||||||
auto monitor = std::find_if(json.begin(), json.end(),
|
|
||||||
|
auto Window::getActiveWorkspace(const std::string& monitorName) -> Workspace {
|
||||||
|
const auto monitors = gIPC->getSocket1JsonReply("monitors");
|
||||||
|
assert(monitors.isArray());
|
||||||
|
auto monitor = std::find_if(monitors.begin(), monitors.end(),
|
||||||
[&](Json::Value monitor) { return monitor["name"] == monitorName; });
|
[&](Json::Value monitor) { return monitor["name"] == monitorName; });
|
||||||
if (monitor == std::end(json)) {
|
if (monitor == std::end(monitors)) {
|
||||||
return 0;
|
spdlog::warn("Monitor not found: {}", monitorName);
|
||||||
|
return Workspace{-1, 0, "", ""};
|
||||||
}
|
}
|
||||||
return (*monitor)["activeWorkspace"]["id"].as<int>();
|
const int id = (*monitor)["activeWorkspace"]["id"].asInt();
|
||||||
|
|
||||||
|
const auto workspaces = gIPC->getSocket1JsonReply("workspaces");
|
||||||
|
assert(workspaces.isArray());
|
||||||
|
auto workspace = std::find_if(monitors.begin(), monitors.end(),
|
||||||
|
[&](Json::Value workspace) { return workspace["id"] == id; });
|
||||||
|
if (workspace == std::end(monitors)) {
|
||||||
|
spdlog::warn("No workspace with id {}", id);
|
||||||
|
return Workspace{-1, 0, "", ""};
|
||||||
|
}
|
||||||
|
return Workspace::parse(*workspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Window::getLastWindowTitle(int workspaceID) {
|
auto Window::Workspace::parse(const Json::Value& value) -> Window::Workspace {
|
||||||
auto cmd = waybar::util::command::exec("hyprctl workspaces -j");
|
return Workspace{value["id"].asInt(), value["windows"].asInt(), value["lastwindow"].asString(),
|
||||||
assert(cmd.exit_code == 0);
|
value["lastwindowtitle"].asString()};
|
||||||
Json::Value json = parser_.parse(cmd.out);
|
}
|
||||||
|
|
||||||
|
void Window::queryActiveWorkspace() {
|
||||||
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
|
||||||
|
if (separate_outputs) {
|
||||||
|
workspace_ = getActiveWorkspace(this->bar_.output->name);
|
||||||
|
} else {
|
||||||
|
workspace_ = getActiveWorkspace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace_.windows > 0) {
|
||||||
|
const auto clients = gIPC->getSocket1Reply("j/clients");
|
||||||
|
Json::Value json = parser_.parse(clients);
|
||||||
assert(json.isArray());
|
assert(json.isArray());
|
||||||
auto workspace = std::find_if(json.begin(), json.end(), [&](Json::Value workspace) {
|
auto active_window = std::find_if(json.begin(), json.end(), [&](Json::Value window) {
|
||||||
return workspace["id"].as<int>() == workspaceID;
|
return window["address"] == workspace_.last_window;
|
||||||
});
|
});
|
||||||
|
if (active_window == std::end(json)) {
|
||||||
if (workspace == std::end(json)) {
|
return;
|
||||||
return "";
|
}
|
||||||
|
|
||||||
|
if (workspace_.windows == 1 && !(*active_window)["floating"].asBool()) {
|
||||||
|
solo_class_ = (*active_window)["class"].asString();
|
||||||
|
} else {
|
||||||
|
solo_class_ = "";
|
||||||
|
}
|
||||||
|
std::vector<Json::Value> workspace_windows;
|
||||||
|
std::copy_if(json.begin(), json.end(), std::back_inserter(workspace_windows),
|
||||||
|
[&](Json::Value window) {
|
||||||
|
return window["workspace"]["id"] == workspace_.id && window["mapped"].asBool();
|
||||||
|
});
|
||||||
|
solo_ = 1 == std::count_if(workspace_windows.begin(), workspace_windows.end(),
|
||||||
|
[&](Json::Value window) { return !window["floating"].asBool(); });
|
||||||
|
all_floating_ = std::all_of(workspace_windows.begin(), workspace_windows.end(),
|
||||||
|
[&](Json::Value window) { return window["floating"].asBool(); });
|
||||||
|
fullscreen_ = (*active_window)["fullscreen"].asBool();
|
||||||
|
} else {
|
||||||
|
solo_class_ = "";
|
||||||
|
solo_ = false;
|
||||||
|
all_floating_ = false;
|
||||||
|
fullscreen_ = false;
|
||||||
}
|
}
|
||||||
return (*workspace)["lastwindowtitle"].as<std::string>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::onEvent(const std::string& ev) {
|
void Window::onEvent(const std::string& ev) {
|
||||||
std::lock_guard<std::mutex> lg(mutex_);
|
queryActiveWorkspace();
|
||||||
|
|
||||||
std::string windowName;
|
|
||||||
if (separate_outputs) {
|
|
||||||
windowName = getLastWindowTitle(getActiveWorkspaceID(this->bar_.output->name));
|
|
||||||
} else {
|
|
||||||
windowName = ev.substr(ev.find_first_of(',') + 1).substr(0, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
windowName = waybar::util::sanitize_string(windowName);
|
|
||||||
|
|
||||||
if (windowName == lastView) return;
|
|
||||||
|
|
||||||
lastView = windowName;
|
|
||||||
|
|
||||||
spdlog::debug("hyprland window onevent with {}", windowName);
|
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::setClass(const std::string& classname, bool enable) {
|
||||||
|
if (enable) {
|
||||||
|
if (!bar_.window.get_style_context()->has_class(classname)) {
|
||||||
|
bar_.window.get_style_context()->add_class(classname);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bar_.window.get_style_context()->remove_class(classname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
199
src/modules/hyprland/workspaces.cpp
Normal file
199
src/modules/hyprland/workspaces.cpp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#include "modules/hyprland/workspaces.hpp"
|
||||||
|
|
||||||
|
#include <json/value.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <charconv>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace waybar::modules::hyprland {
|
||||||
|
|
||||||
|
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
|
||||||
|
: AModule(config, "workspaces", id, false, false),
|
||||||
|
bar_(bar),
|
||||||
|
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
|
||||||
|
Json::Value config_format = config["format"];
|
||||||
|
|
||||||
|
format_ = config_format.isString() ? config_format.asString() : "{id}";
|
||||||
|
with_icon_ = format_.find("{icon}") != std::string::npos;
|
||||||
|
|
||||||
|
if (with_icon_ && icons_map_.empty()) {
|
||||||
|
Json::Value format_icons = config["format-icons"];
|
||||||
|
for (std::string &name : format_icons.getMemberNames()) {
|
||||||
|
icons_map_.emplace(name, format_icons[name].asString());
|
||||||
|
}
|
||||||
|
|
||||||
|
icons_map_.emplace("", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
box_.set_name("workspaces");
|
||||||
|
if (!id.empty()) {
|
||||||
|
box_.get_style_context()->add_class(id);
|
||||||
|
}
|
||||||
|
event_box_.add(box_);
|
||||||
|
modulesReady = true;
|
||||||
|
if (!gIPC.get()) {
|
||||||
|
gIPC = std::make_unique<IPC>();
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
gIPC->registerForIPC("workspace", this);
|
||||||
|
gIPC->registerForIPC("createworkspace", this);
|
||||||
|
gIPC->registerForIPC("destroyworkspace", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Workspaces::update() -> void {
|
||||||
|
for (int &workspace_to_remove : workspaces_to_remove_) {
|
||||||
|
remove_workspace(workspace_to_remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaces_to_remove_.clear();
|
||||||
|
|
||||||
|
for (int &workspace_to_create : workspaces_to_create_) {
|
||||||
|
create_workspace(workspace_to_create);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaces_to_create_.clear();
|
||||||
|
|
||||||
|
for (std::unique_ptr<Workspace> &workspace : workspaces_) {
|
||||||
|
workspace->set_active(workspace->id() == active_workspace_id);
|
||||||
|
|
||||||
|
std::string &workspace_icon = icons_map_[""];
|
||||||
|
if (with_icon_) {
|
||||||
|
workspace_icon = workspace->select_icon(icons_map_);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace->update(format_, workspace_icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
AModule::update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspaces::onEvent(const std::string &ev) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
std::string eventName(begin(ev), begin(ev) + ev.find_first_of('>'));
|
||||||
|
std::string payload = ev.substr(eventName.size() + 2);
|
||||||
|
if (eventName == "workspace") {
|
||||||
|
std::from_chars(payload.data(), payload.data() + payload.size(), active_workspace_id);
|
||||||
|
} else if (eventName == "destroyworkspace") {
|
||||||
|
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") {
|
||||||
|
int new_workspace_id;
|
||||||
|
std::from_chars(payload.data(), payload.data() + payload.size(), new_workspace_id);
|
||||||
|
workspaces_to_create_.push_back(new_workspace_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspaces::create_workspace(int id) {
|
||||||
|
workspaces_.push_back(std::make_unique<Workspace>(id));
|
||||||
|
Gtk::Button &new_workspace_button = workspaces_.back()->button();
|
||||||
|
box_.pack_start(new_workspace_button, false, false);
|
||||||
|
sort_workspaces();
|
||||||
|
new_workspace_button.show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspaces::remove_workspace(int id) {
|
||||||
|
auto workspace = std::find_if(workspaces_.begin(), workspaces_.end(),
|
||||||
|
[&](std::unique_ptr<Workspace> &x) { return x->id() == id; });
|
||||||
|
|
||||||
|
if (workspace == workspaces_.end()) {
|
||||||
|
spdlog::warn("Can't find workspace with id {}", id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
box_.remove(workspace->get()->button());
|
||||||
|
workspaces_.erase(workspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspaces::init() {
|
||||||
|
const auto activeWorkspace = WorkspaceDto::parse(gIPC->getSocket1JsonReply("activeworkspace"));
|
||||||
|
active_workspace_id = activeWorkspace.id;
|
||||||
|
const Json::Value workspaces_json = gIPC->getSocket1JsonReply("workspaces");
|
||||||
|
for (const Json::Value &workspace_json : workspaces_json) {
|
||||||
|
workspaces_.push_back(
|
||||||
|
std::make_unique<Workspace>(Workspace(WorkspaceDto::parse(workspace_json))));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &workspace : workspaces_) {
|
||||||
|
box_.pack_start(workspace->button(), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
sort_workspaces();
|
||||||
|
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Workspaces::~Workspaces() {
|
||||||
|
gIPC->unregisterForIPC(this);
|
||||||
|
// wait for possible event handler to finish
|
||||||
|
std::lock_guard<std::mutex> lg(mutex_);
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkspaceDto WorkspaceDto::parse(const Json::Value &value) {
|
||||||
|
return WorkspaceDto{value["id"].asInt()};
|
||||||
|
}
|
||||||
|
|
||||||
|
Workspace::Workspace(WorkspaceDto dto) : Workspace(dto.id){};
|
||||||
|
|
||||||
|
Workspace::Workspace(int id) : id_(id) {
|
||||||
|
button_.set_relief(Gtk::RELIEF_NONE);
|
||||||
|
content_.set_center_widget(label_);
|
||||||
|
button_.add(content_);
|
||||||
|
};
|
||||||
|
|
||||||
|
void add_or_remove_class(Glib::RefPtr<Gtk::StyleContext> context, bool condition,
|
||||||
|
const std::string &class_name) {
|
||||||
|
if (condition) {
|
||||||
|
context->add_class(class_name);
|
||||||
|
} else {
|
||||||
|
context->remove_class(class_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspace::update(const std::string &format, const std::string &icon) {
|
||||||
|
Glib::RefPtr<Gtk::StyleContext> style_context = button_.get_style_context();
|
||||||
|
add_or_remove_class(style_context, active(), "active");
|
||||||
|
|
||||||
|
label_.set_markup(
|
||||||
|
fmt::format(fmt::runtime(format), fmt::arg("id", id()), fmt::arg("icon", icon)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Workspaces::sort_workspaces() {
|
||||||
|
std::sort(workspaces_.begin(), workspaces_.end(),
|
||||||
|
[](std::unique_ptr<Workspace> &lhs, std::unique_ptr<Workspace> &rhs) {
|
||||||
|
return lhs->id() < rhs->id();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (size_t i = 0; i < workspaces_.size(); ++i) {
|
||||||
|
box_.reorder_child(workspaces_[i]->button(), i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string &Workspace::select_icon(std::map<std::string, std::string> &icons_map) {
|
||||||
|
if (active()) {
|
||||||
|
auto active_icon_it = icons_map.find("active");
|
||||||
|
if (active_icon_it != icons_map.end()) {
|
||||||
|
return active_icon_it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto named_icon_it = icons_map.find(std::to_string(id()));
|
||||||
|
if (named_icon_it != icons_map.end()) {
|
||||||
|
return named_icon_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto default_icon_it = icons_map.find("default");
|
||||||
|
if (default_icon_it != icons_map.end()) {
|
||||||
|
return default_icon_it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return icons_map[""];
|
||||||
|
}
|
||||||
|
} // namespace waybar::modules::hyprland
|
@ -41,14 +41,12 @@ void waybar::modules::Image::refresh(int sig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::Image::update() -> void {
|
auto waybar::modules::Image::update() -> void {
|
||||||
util::command::res output_;
|
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
|
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
|
||||||
if (config_["path"].isString()) {
|
if (config_["path"].isString()) {
|
||||||
path_ = config_["path"].asString();
|
path_ = config_["path"].asString();
|
||||||
} else if (config_["exec"].isString()) {
|
} else if (config_["exec"].isString()) {
|
||||||
output_ = util::command::exec(config_["exec"].asString());
|
output_ = util::command::exec(config_["exec"].asString());
|
||||||
path_ = output_.out;
|
parseOutputRaw();
|
||||||
} else {
|
} else {
|
||||||
path_ = "";
|
path_ = "";
|
||||||
}
|
}
|
||||||
@ -58,6 +56,11 @@ auto waybar::modules::Image::update() -> void {
|
|||||||
pixbuf = {};
|
pixbuf = {};
|
||||||
|
|
||||||
if (pixbuf) {
|
if (pixbuf) {
|
||||||
|
if (tooltipEnabled() && !tooltip_.empty()) {
|
||||||
|
if (box_.get_tooltip_markup() != tooltip_) {
|
||||||
|
box_.set_tooltip_markup(tooltip_);
|
||||||
|
}
|
||||||
|
}
|
||||||
image_.set(pixbuf);
|
image_.set(pixbuf);
|
||||||
image_.show();
|
image_.show();
|
||||||
} else {
|
} else {
|
||||||
@ -67,3 +70,19 @@ auto waybar::modules::Image::update() -> void {
|
|||||||
|
|
||||||
AModule::update();
|
AModule::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waybar::modules::Image::parseOutputRaw() {
|
||||||
|
std::istringstream output(output_.out);
|
||||||
|
std::string line;
|
||||||
|
int i = 0;
|
||||||
|
while (getline(output, line)) {
|
||||||
|
if (i == 0) {
|
||||||
|
path_ = line;
|
||||||
|
} else if (i == 1) {
|
||||||
|
tooltip_ = line;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,14 +24,17 @@ Mpris::Mpris(const std::string& id, const Json::Value& config)
|
|||||||
album_len_(-1),
|
album_len_(-1),
|
||||||
title_len_(-1),
|
title_len_(-1),
|
||||||
dynamic_len_(-1),
|
dynamic_len_(-1),
|
||||||
dynamic_prio_({"title", "length", "position", "artist", "album"}),
|
dynamic_prio_({"title", "artist", "album", "position", "length"}),
|
||||||
|
dynamic_order_({"title", "artist", "album", "position", "length"}),
|
||||||
|
dynamic_separator_(" - "),
|
||||||
truncate_hours_(true),
|
truncate_hours_(true),
|
||||||
tooltip_len_limits_(false),
|
tooltip_len_limits_(false),
|
||||||
// this character is used in Gnome so it's fine to use it here
|
// this character is used in Gnome so it's fine to use it here
|
||||||
ellipsis_("\u2026"),
|
ellipsis_("\u2026"),
|
||||||
player_("playerctld"),
|
player_("playerctld"),
|
||||||
manager(),
|
manager(),
|
||||||
player() {
|
player(),
|
||||||
|
last_update_(std::chrono::system_clock::now() - interval_) {
|
||||||
if (config_["format-playing"].isString()) {
|
if (config_["format-playing"].isString()) {
|
||||||
format_playing_ = config_["format-playing"].asString();
|
format_playing_ = config_["format-playing"].asString();
|
||||||
}
|
}
|
||||||
@ -44,6 +47,9 @@ Mpris::Mpris(const std::string& id, const Json::Value& config)
|
|||||||
if (config_["ellipsis"].isString()) {
|
if (config_["ellipsis"].isString()) {
|
||||||
ellipsis_ = config_["ellipsis"].asString();
|
ellipsis_ = config_["ellipsis"].asString();
|
||||||
}
|
}
|
||||||
|
if (config_["dynamic-separator"].isString()) {
|
||||||
|
dynamic_separator_ = config_["dynamic-separator"].asString();
|
||||||
|
}
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
if (config_["tooltip-format"].isString()) {
|
if (config_["tooltip-format"].isString()) {
|
||||||
tooltip_ = config_["tooltip-format"].asString();
|
tooltip_ = config_["tooltip-format"].asString();
|
||||||
@ -74,12 +80,23 @@ Mpris::Mpris(const std::string& id, const Json::Value& config)
|
|||||||
if (config["dynamic-len"].isUInt()) {
|
if (config["dynamic-len"].isUInt()) {
|
||||||
dynamic_len_ = config["dynamic-len"].asUInt();
|
dynamic_len_ = config["dynamic-len"].asUInt();
|
||||||
}
|
}
|
||||||
if (config_["dynamic-priority"].isArray()) {
|
// "dynamic-priority" has been kept for backward compatibility
|
||||||
|
if (config_["dynamic-importance-order"].isArray() || config_["dynamic-priority"].isArray()) {
|
||||||
dynamic_prio_.clear();
|
dynamic_prio_.clear();
|
||||||
for (auto it = config_["dynamic-priority"].begin(); it != config_["dynamic-priority"].end();
|
const auto& dynamic_priority = config_["dynamic-importance-order"].isArray()
|
||||||
++it) {
|
? config_["dynamic-importance-order"]
|
||||||
|
: config_["dynamic-priority"];
|
||||||
|
for (const auto& value : dynamic_priority) {
|
||||||
|
if (value.isString()) {
|
||||||
|
dynamic_prio_.push_back(value.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config_["dynamic-order"].isArray()) {
|
||||||
|
dynamic_order_.clear();
|
||||||
|
for (auto it = config_["dynamic-order"].begin(); it != config_["dynamic-order"].end(); ++it) {
|
||||||
if (it->isString()) {
|
if (it->isString()) {
|
||||||
dynamic_prio_.push_back(it->asString());
|
dynamic_order_.push_back(it->asString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,18 +289,28 @@ auto Mpris::getDynamicStr(const PlayerInfo& info, bool truncated, bool html) ->
|
|||||||
size_t lengthLen = length.length();
|
size_t lengthLen = length.length();
|
||||||
size_t posLen = position.length();
|
size_t posLen = position.length();
|
||||||
|
|
||||||
bool showArtist = artistLen != 0;
|
bool showArtist = (artistLen != 0) && (std::find(dynamic_order_.begin(), dynamic_order_.end(),
|
||||||
bool showAlbum = albumLen != 0;
|
"artist") != dynamic_order_.end());
|
||||||
bool showTitle = titleLen != 0;
|
bool showAlbum = (albumLen != 0) && (std::find(dynamic_order_.begin(), dynamic_order_.end(),
|
||||||
bool showLength = lengthLen != 0;
|
"album") != dynamic_order_.end());
|
||||||
bool showPos = posLen != 0;
|
bool showTitle = (titleLen != 0) && (std::find(dynamic_order_.begin(), dynamic_order_.end(),
|
||||||
|
"title") != dynamic_order_.end());
|
||||||
|
bool showLength = (lengthLen != 0) && (std::find(dynamic_order_.begin(), dynamic_order_.end(),
|
||||||
|
"length") != dynamic_order_.end());
|
||||||
|
bool showPos = (posLen != 0) && (std::find(dynamic_order_.begin(), dynamic_order_.end(),
|
||||||
|
"position") != dynamic_order_.end());
|
||||||
|
|
||||||
if (truncated && dynamic_len_ >= 0) {
|
if (truncated && dynamic_len_ >= 0) {
|
||||||
size_t dynamicLen = dynamic_len_;
|
// Since the first element doesn't present a separator and we don't know a priori which one
|
||||||
if (showArtist) artistLen += 3;
|
// it will be, we add a "virtual separatorLen" to the dynamicLen, since we are adding the
|
||||||
if (showAlbum) albumLen += 3;
|
// separatorLen to all the other lengths.
|
||||||
if (showLength) lengthLen += 3;
|
size_t separatorLen = utf8_width(dynamic_separator_);
|
||||||
if (showPos) posLen += 3;
|
size_t dynamicLen = dynamic_len_ + separatorLen;
|
||||||
|
if (showArtist) artistLen += separatorLen;
|
||||||
|
if (showAlbum) albumLen += separatorLen;
|
||||||
|
if (showTitle) albumLen += separatorLen;
|
||||||
|
if (showLength) lengthLen += separatorLen;
|
||||||
|
if (showPos) posLen += separatorLen;
|
||||||
|
|
||||||
size_t totalLen = 0;
|
size_t totalLen = 0;
|
||||||
|
|
||||||
@ -330,12 +357,31 @@ auto Mpris::getDynamicStr(const PlayerInfo& info, bool truncated, bool html) ->
|
|||||||
album = Glib::Markup::escape_text(album);
|
album = Glib::Markup::escape_text(album);
|
||||||
title = Glib::Markup::escape_text(title);
|
title = Glib::Markup::escape_text(title);
|
||||||
}
|
}
|
||||||
if (showArtist) dynamic << artist << " - ";
|
|
||||||
if (showAlbum) dynamic << album << " - ";
|
bool lengthOrPositionShown = false;
|
||||||
if (showTitle) dynamic << title;
|
bool previousShown = false;
|
||||||
if (showLength || showPos) {
|
std::string previousOrder = "";
|
||||||
dynamic << ' ';
|
|
||||||
|
for (const std::string& order : dynamic_order_) {
|
||||||
|
if ((order == "artist" && showArtist) || (order == "album" && showAlbum) ||
|
||||||
|
(order == "title" && showTitle)) {
|
||||||
|
if (previousShown && previousOrder != "length" && previousOrder != "position") {
|
||||||
|
dynamic << dynamic_separator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order == "artist") {
|
||||||
|
dynamic << artist;
|
||||||
|
} else if (order == "album") {
|
||||||
|
dynamic << album;
|
||||||
|
} else if (order == "title") {
|
||||||
|
dynamic << title;
|
||||||
|
}
|
||||||
|
|
||||||
|
previousShown = true;
|
||||||
|
} else if (order == "length" || order == "position") {
|
||||||
|
if (!lengthOrPositionShown && (showLength || showPos)) {
|
||||||
if (html) dynamic << "<small>";
|
if (html) dynamic << "<small>";
|
||||||
|
if (previousShown) dynamic << ' ';
|
||||||
dynamic << '[';
|
dynamic << '[';
|
||||||
if (showPos) {
|
if (showPos) {
|
||||||
dynamic << position;
|
dynamic << position;
|
||||||
@ -343,7 +389,12 @@ auto Mpris::getDynamicStr(const PlayerInfo& info, bool truncated, bool html) ->
|
|||||||
}
|
}
|
||||||
if (showLength) dynamic << length;
|
if (showLength) dynamic << length;
|
||||||
dynamic << ']';
|
dynamic << ']';
|
||||||
|
if (!dynamic.str().empty()) dynamic << ' ';
|
||||||
if (html) dynamic << "</small>";
|
if (html) dynamic << "</small>";
|
||||||
|
lengthOrPositionShown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
previousOrder = order;
|
||||||
}
|
}
|
||||||
return dynamic.str();
|
return dynamic.str();
|
||||||
}
|
}
|
||||||
@ -559,6 +610,10 @@ bool Mpris::handleToggle(GdkEventButton* const& e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Mpris::update() -> void {
|
auto Mpris::update() -> void {
|
||||||
|
const auto now = std::chrono::system_clock::now();
|
||||||
|
if (now - last_update_ < interval_) return;
|
||||||
|
last_update_ = now;
|
||||||
|
|
||||||
auto opt = getPlayerInfo();
|
auto opt = getPlayerInfo();
|
||||||
if (!opt) {
|
if (!opt) {
|
||||||
event_box_.set_visible(false);
|
event_box_.set_visible(false);
|
||||||
|
@ -81,13 +81,6 @@ bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) {
|
|||||||
if (dir == SCROLL_DIR::NONE) {
|
if (dir == SCROLL_DIR::NONE) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (config_["reverse-scrolling"].asInt() == 1) {
|
|
||||||
if (dir == SCROLL_DIR::UP) {
|
|
||||||
dir = SCROLL_DIR::DOWN;
|
|
||||||
} else if (dir == SCROLL_DIR::DOWN) {
|
|
||||||
dir = SCROLL_DIR::UP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
|
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
|
||||||
pa_volume_t change = volume_tick;
|
pa_volume_t change = volume_tick;
|
||||||
pa_cvolume pa_volume = pa_volume_;
|
pa_cvolume pa_volume = pa_volume_;
|
||||||
|
@ -106,7 +106,11 @@ void Window::handle_focused_view(const char *title) {
|
|||||||
label_.hide(); // hide empty labels or labels with empty format
|
label_.hide(); // hide empty labels or labels with empty format
|
||||||
} else {
|
} else {
|
||||||
label_.show();
|
label_.show();
|
||||||
label_.set_markup(fmt::format(fmt::runtime(format_), Glib::Markup::escape_text(title).raw()));
|
auto text = fmt::format(fmt::runtime(format_), Glib::Markup::escape_text(title).raw());
|
||||||
|
label_.set_markup(text);
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
label_.set_tooltip_markup(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
|
@ -19,7 +19,7 @@ Host::Host(const std::size_t id, const Json::Value& config, const Bar& bar,
|
|||||||
|
|
||||||
Host::~Host() {
|
Host::~Host() {
|
||||||
if (bus_name_id_ > 0) {
|
if (bus_name_id_ > 0) {
|
||||||
Gio::DBus::unwatch_name(bus_name_id_);
|
Gio::DBus::unown_name(bus_name_id_);
|
||||||
bus_name_id_ = 0;
|
bus_name_id_ = 0;
|
||||||
}
|
}
|
||||||
if (watcher_id_ > 0) {
|
if (watcher_id_ > 0) {
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "util/format.hpp"
|
#include "util/format.hpp"
|
||||||
|
#include "util/gtk_icon.hpp"
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
|
struct fmt::formatter<Glib::VariantBase> : formatter<std::string> {
|
||||||
@ -379,9 +380,7 @@ Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int reque
|
|||||||
return icon_theme->load_icon(name.c_str(), tmp_size,
|
return icon_theme->load_icon(name.c_str(), tmp_size,
|
||||||
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
||||||
}
|
}
|
||||||
Glib::RefPtr<Gtk::IconTheme> default_theme = Gtk::IconTheme::get_default();
|
return DefaultGtkIconThemeWrapper::load_icon(name.c_str(), tmp_size,
|
||||||
default_theme->rescan_if_needed();
|
|
||||||
return default_theme->load_icon(name.c_str(), tmp_size,
|
|
||||||
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ Watcher::~Watcher() {
|
|||||||
g_slist_free_full(hosts_, gfWatchFree);
|
g_slist_free_full(hosts_, gfWatchFree);
|
||||||
hosts_ = nullptr;
|
hosts_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (items_ != nullptr) {
|
if (items_ != nullptr) {
|
||||||
g_slist_free_full(items_, gfWatchFree);
|
g_slist_free_full(items_, gfWatchFree);
|
||||||
items_ = nullptr;
|
items_ = nullptr;
|
||||||
|
@ -5,13 +5,13 @@
|
|||||||
#include <glibmm/keyfile.h>
|
#include <glibmm/keyfile.h>
|
||||||
#include <glibmm/miscutils.h>
|
#include <glibmm/miscutils.h>
|
||||||
#include <gtkmm/enums.h>
|
#include <gtkmm/enums.h>
|
||||||
#include <gtkmm/icontheme.h>
|
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "util/gtk_icon.hpp"
|
||||||
#include "util/rewrite_string.hpp"
|
#include "util/rewrite_string.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::sway {
|
namespace waybar::modules::sway {
|
||||||
@ -81,13 +81,12 @@ std::optional<Glib::ustring> getIconName(const std::string& app_id, const std::s
|
|||||||
if (!desktop_file_path.has_value()) {
|
if (!desktop_file_path.has_value()) {
|
||||||
// Try some heuristics to find a matching icon
|
// Try some heuristics to find a matching icon
|
||||||
|
|
||||||
const auto default_icon_theme = Gtk::IconTheme::get_default();
|
if (DefaultGtkIconThemeWrapper::has_icon(app_id)) {
|
||||||
if (default_icon_theme->has_icon(app_id)) {
|
|
||||||
return app_id;
|
return app_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto app_id_desktop = app_id + "-desktop";
|
const auto app_id_desktop = app_id + "-desktop";
|
||||||
if (default_icon_theme->has_icon(app_id_desktop)) {
|
if (DefaultGtkIconThemeWrapper::has_icon(app_id_desktop)) {
|
||||||
return app_id_desktop;
|
return app_id_desktop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +100,7 @@ std::optional<Glib::ustring> getIconName(const std::string& app_id, const std::s
|
|||||||
const auto first_space = app_id.find_first_of(' ');
|
const auto first_space = app_id.find_first_of(' ');
|
||||||
if (first_space != std::string::npos) {
|
if (first_space != std::string::npos) {
|
||||||
const auto first_word = to_lower(app_id.substr(0, first_space));
|
const auto first_word = to_lower(app_id.substr(0, first_space));
|
||||||
if (default_icon_theme->has_icon(first_word)) {
|
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
|
||||||
return first_word;
|
return first_word;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,7 +108,7 @@ std::optional<Glib::ustring> getIconName(const std::string& app_id, const std::s
|
|||||||
const auto first_dash = app_id.find_first_of('-');
|
const auto first_dash = app_id.find_first_of('-');
|
||||||
if (first_dash != std::string::npos) {
|
if (first_dash != std::string::npos) {
|
||||||
const auto first_word = to_lower(app_id.substr(0, first_dash));
|
const auto first_word = to_lower(app_id.substr(0, first_dash));
|
||||||
if (default_icon_theme->has_icon(first_word)) {
|
if (DefaultGtkIconThemeWrapper::has_icon(first_word)) {
|
||||||
return first_word;
|
return first_word;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,10 +177,6 @@ auto Window::update() -> void {
|
|||||||
} else {
|
} else {
|
||||||
mode += 32;
|
mode += 32;
|
||||||
}
|
}
|
||||||
if (!app_id_.empty() && !bar_.window.get_style_context()->has_class(app_id_)) {
|
|
||||||
bar_.window.get_style_context()->add_class(app_id_);
|
|
||||||
old_app_id_ = app_id_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!old_app_id_.empty() && ((mode & 2) == 0 || old_app_id_ != app_id_) &&
|
if (!old_app_id_.empty() && ((mode & 2) == 0 || old_app_id_ != app_id_) &&
|
||||||
|
@ -235,7 +235,8 @@ auto Workspaces::update() -> void {
|
|||||||
auto format = config_["format"].asString();
|
auto format = config_["format"].asString();
|
||||||
output = fmt::format(fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)),
|
output = fmt::format(fmt::runtime(format), fmt::arg("icon", getIcon(output, *it)),
|
||||||
fmt::arg("value", output), fmt::arg("name", trimWorkspaceName(output)),
|
fmt::arg("value", output), fmt::arg("name", trimWorkspaceName(output)),
|
||||||
fmt::arg("index", (*it)["num"].asString()));
|
fmt::arg("index", (*it)["num"].asString()),
|
||||||
|
fmt::arg("output", (*it)["output"].asString()));
|
||||||
}
|
}
|
||||||
if (!config_["disable-markup"].asBool()) {
|
if (!config_["disable-markup"].asBool()) {
|
||||||
static_cast<Gtk::Label *>(button.get_children()[0])->set_markup(output);
|
static_cast<Gtk::Label *>(button.get_children()[0])->set_markup(output);
|
||||||
@ -278,7 +279,7 @@ 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 = {name, "urgent", "focused", "visible", "default"};
|
std::vector<std::string> keys = {"urgent", "focused", name, "visible", "default"};
|
||||||
for (auto const &key : keys) {
|
for (auto const &key : keys) {
|
||||||
if (key == "focused" || key == "visible" || key == "urgent") {
|
if (key == "focused" || key == "visible" || key == "urgent") {
|
||||||
if (config_["format-icons"][key].isString() && node[key].asBool()) {
|
if (config_["format-icons"][key].isString() && node[key].asBool()) {
|
||||||
@ -326,11 +327,17 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!config_["warp-on-scroll"].asBool()) {
|
||||||
|
ipc_.sendCmd(IPC_COMMAND, fmt::format("mouse_warping none"));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
ipc_.sendCmd(IPC_COMMAND, fmt::format(workspace_switch_cmd_, "--no-auto-back-and-forth", name));
|
ipc_.sendCmd(IPC_COMMAND, fmt::format(workspace_switch_cmd_, "--no-auto-back-and-forth", name));
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
spdlog::error("Workspaces: {}", e.what());
|
spdlog::error("Workspaces: {}", e.what());
|
||||||
}
|
}
|
||||||
|
if (!config_["warp-on-scroll"].asBool()) {
|
||||||
|
ipc_.sendCmd(IPC_COMMAND, fmt::format("mouse_warping container"));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,18 @@ waybar::modules::Temperature::Temperature(const std::string& id, const Json::Val
|
|||||||
#if defined(__FreeBSD__)
|
#if defined(__FreeBSD__)
|
||||||
// try to read sysctl?
|
// try to read sysctl?
|
||||||
#else
|
#else
|
||||||
if (config_["hwmon-path"].isString()) {
|
auto& hwmon_path = config_["hwmon-path"];
|
||||||
file_path_ = config_["hwmon-path"].asString();
|
if (hwmon_path.isString()) {
|
||||||
|
file_path_ = hwmon_path.asString();
|
||||||
|
} else if (hwmon_path.isArray()) {
|
||||||
|
// if hwmon_path is an array, loop to find first valid item
|
||||||
|
for (auto& item : hwmon_path) {
|
||||||
|
auto path = item.asString();
|
||||||
|
if (std::filesystem::exists(path)) {
|
||||||
|
file_path_ = path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) {
|
} else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) {
|
||||||
file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString()))
|
file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString()))
|
||||||
.path()
|
.path()
|
||||||
|
@ -5,10 +5,8 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "gtkmm/icontheme.h"
|
|
||||||
#include "gtkmm/label.h"
|
|
||||||
#include "gtkmm/tooltip.h"
|
#include "gtkmm/tooltip.h"
|
||||||
#include "modules/upower/upower_tooltip.hpp"
|
#include "util/gtk_icon.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::upower {
|
namespace waybar::modules::upower {
|
||||||
UPower::UPower(const std::string& id, const Json::Value& config)
|
UPower::UPower(const std::string& id, const Json::Value& config)
|
||||||
@ -25,6 +23,8 @@ UPower::UPower(const std::string& id, const Json::Value& config)
|
|||||||
box_.set_name(name_);
|
box_.set_name(name_);
|
||||||
event_box_.add(box_);
|
event_box_.add(box_);
|
||||||
|
|
||||||
|
// Device user wants
|
||||||
|
if (config_["native-path"].isString()) nativePath_ = config_["native-path"].asString();
|
||||||
// Icon Size
|
// Icon Size
|
||||||
if (config_["icon-size"].isUInt()) {
|
if (config_["icon-size"].isUInt()) {
|
||||||
iconSize = config_["icon-size"].asUInt();
|
iconSize = config_["icon-size"].asUInt();
|
||||||
@ -195,8 +195,26 @@ void UPower::addDevice(UpDevice* device) {
|
|||||||
|
|
||||||
void UPower::setDisplayDevice() {
|
void UPower::setDisplayDevice() {
|
||||||
std::lock_guard<std::mutex> guard(m_Mutex);
|
std::lock_guard<std::mutex> guard(m_Mutex);
|
||||||
|
|
||||||
|
if (nativePath_.empty())
|
||||||
displayDevice = up_client_get_display_device(client);
|
displayDevice = up_client_get_display_device(client);
|
||||||
g_signal_connect(displayDevice, "notify", G_CALLBACK(deviceNotify_cb), this);
|
else {
|
||||||
|
g_ptr_array_foreach(
|
||||||
|
up_client_get_devices2(client),
|
||||||
|
[](gpointer data, gpointer user_data) {
|
||||||
|
UpDevice* device{static_cast<UpDevice*>(data)};
|
||||||
|
UPower* thisPtr{static_cast<UPower*>(user_data)};
|
||||||
|
gchar* nativePath;
|
||||||
|
if (!thisPtr->displayDevice) {
|
||||||
|
g_object_get(device, "native-path", &nativePath, NULL);
|
||||||
|
if (!std::strcmp(nativePath, thisPtr->nativePath_.c_str()))
|
||||||
|
thisPtr->displayDevice = device;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayDevice) g_signal_connect(displayDevice, "notify", G_CALLBACK(deviceNotify_cb), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPower::removeDevices() {
|
void UPower::removeDevices() {
|
||||||
@ -278,14 +296,22 @@ auto UPower::update() -> void {
|
|||||||
double percentage;
|
double percentage;
|
||||||
gint64 time_empty;
|
gint64 time_empty;
|
||||||
gint64 time_full;
|
gint64 time_full;
|
||||||
gchar* icon_name;
|
gchar* icon_name{(char*)'\0'};
|
||||||
|
std::string percentString{""};
|
||||||
|
std::string time_format{""};
|
||||||
|
|
||||||
|
bool displayDeviceValid{false};
|
||||||
|
|
||||||
|
if (displayDevice) {
|
||||||
g_object_get(displayDevice, "kind", &kind, "state", &state, "percentage", &percentage,
|
g_object_get(displayDevice, "kind", &kind, "state", &state, "percentage", &percentage,
|
||||||
"icon-name", &icon_name, "time-to-empty", &time_empty, "time-to-full", &time_full,
|
"icon-name", &icon_name, "time-to-empty", &time_empty, "time-to-full", &time_full,
|
||||||
NULL);
|
NULL);
|
||||||
|
/* Every Device which is handled by Upower and which is not
|
||||||
bool displayDeviceValid =
|
* UP_DEVICE_KIND_UNKNOWN (0) or UP_DEVICE_KIND_LINE_POWER (1) is a Battery
|
||||||
kind == UpDeviceKind::UP_DEVICE_KIND_BATTERY || kind == UpDeviceKind::UP_DEVICE_KIND_UPS;
|
*/
|
||||||
|
displayDeviceValid = (kind != UpDeviceKind::UP_DEVICE_KIND_UNKNOWN &&
|
||||||
|
kind != UpDeviceKind::UP_DEVICE_KIND_LINE_POWER);
|
||||||
|
}
|
||||||
|
|
||||||
// CSS status class
|
// CSS status class
|
||||||
const std::string status = getDeviceStatus(state);
|
const std::string status = getDeviceStatus(state);
|
||||||
@ -308,6 +334,7 @@ auto UPower::update() -> void {
|
|||||||
|
|
||||||
event_box_.set_visible(true);
|
event_box_.set_visible(true);
|
||||||
|
|
||||||
|
if (displayDeviceValid) {
|
||||||
// Tooltip
|
// Tooltip
|
||||||
if (tooltip_enabled) {
|
if (tooltip_enabled) {
|
||||||
uint tooltipCount = upower_tooltip->updateTooltip(devices);
|
uint tooltipCount = upower_tooltip->updateTooltip(devices);
|
||||||
@ -316,13 +343,9 @@ auto UPower::update() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set percentage
|
// Set percentage
|
||||||
std::string percentString = "";
|
|
||||||
if (displayDeviceValid) {
|
|
||||||
percentString = std::to_string(int(percentage + 0.5)) + "%";
|
percentString = std::to_string(int(percentage + 0.5)) + "%";
|
||||||
}
|
|
||||||
|
|
||||||
// Label format
|
// Label format
|
||||||
std::string time_format = "";
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case UP_DEVICE_STATE_CHARGING:
|
case UP_DEVICE_STATE_CHARGING:
|
||||||
case UP_DEVICE_STATE_PENDING_CHARGE:
|
case UP_DEVICE_STATE_PENDING_CHARGE:
|
||||||
@ -335,6 +358,7 @@ auto UPower::update() -> void {
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
std::string label_format =
|
std::string label_format =
|
||||||
fmt::format(fmt::runtime(showAltText ? format_alt : format),
|
fmt::format(fmt::runtime(showAltText ? format_alt : format),
|
||||||
fmt::arg("percentage", percentString), fmt::arg("time", time_format));
|
fmt::arg("percentage", percentString), fmt::arg("time", time_format));
|
||||||
@ -348,7 +372,7 @@ auto UPower::update() -> void {
|
|||||||
label_.set_markup(onlySpaces ? "" : label_format);
|
label_.set_markup(onlySpaces ? "" : label_format);
|
||||||
|
|
||||||
// Set icon
|
// Set icon
|
||||||
if (icon_name == NULL || !Gtk::IconTheme::get_default()->has_icon(icon_name)) {
|
if (icon_name == NULL || !DefaultGtkIconThemeWrapper::has_icon(icon_name)) {
|
||||||
icon_name = (char*)"battery-missing-symbolic";
|
icon_name = (char*)"battery-missing-symbolic";
|
||||||
}
|
}
|
||||||
icon_.set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID);
|
icon_.set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID);
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#include "gtkmm/box.h"
|
#include "gtkmm/box.h"
|
||||||
#include "gtkmm/enums.h"
|
#include "gtkmm/enums.h"
|
||||||
#include "gtkmm/icontheme.h"
|
|
||||||
#include "gtkmm/image.h"
|
#include "gtkmm/image.h"
|
||||||
#include "gtkmm/label.h"
|
#include "gtkmm/label.h"
|
||||||
|
#include "util/gtk_icon.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::upower {
|
namespace waybar::modules::upower {
|
||||||
UPowerTooltip::UPowerTooltip(uint iconSize_, uint tooltipSpacing_, uint tooltipPadding_)
|
UPowerTooltip::UPowerTooltip(uint iconSize_, uint tooltipSpacing_, uint tooltipPadding_)
|
||||||
@ -62,7 +62,7 @@ uint UPowerTooltip::updateTooltip(Devices& devices) {
|
|||||||
std::string deviceIconName = getDeviceIcon(kind);
|
std::string deviceIconName = getDeviceIcon(kind);
|
||||||
Gtk::Image* deviceIcon = new Gtk::Image();
|
Gtk::Image* deviceIcon = new Gtk::Image();
|
||||||
deviceIcon->set_pixel_size(iconSize);
|
deviceIcon->set_pixel_size(iconSize);
|
||||||
if (!Gtk::IconTheme::get_default()->has_icon(deviceIconName)) {
|
if (!DefaultGtkIconThemeWrapper::has_icon(deviceIconName)) {
|
||||||
deviceIconName = "battery-missing-symbolic";
|
deviceIconName = "battery-missing-symbolic";
|
||||||
}
|
}
|
||||||
deviceIcon->set_from_icon_name(deviceIconName, Gtk::ICON_SIZE_INVALID);
|
deviceIcon->set_from_icon_name(deviceIconName, Gtk::ICON_SIZE_INVALID);
|
||||||
@ -79,7 +79,7 @@ uint UPowerTooltip::updateTooltip(Devices& devices) {
|
|||||||
// Set icon
|
// Set icon
|
||||||
Gtk::Image* icon = new Gtk::Image();
|
Gtk::Image* icon = new Gtk::Image();
|
||||||
icon->set_pixel_size(iconSize);
|
icon->set_pixel_size(iconSize);
|
||||||
if (icon_name == NULL || !Gtk::IconTheme::get_default()->has_icon(icon_name)) {
|
if (icon_name == NULL || !DefaultGtkIconThemeWrapper::has_icon(icon_name)) {
|
||||||
icon_name = (char*)"battery-missing-symbolic";
|
icon_name = (char*)"battery-missing-symbolic";
|
||||||
}
|
}
|
||||||
icon->set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID);
|
icon->set_from_icon_name(icon_name, Gtk::ICON_SIZE_INVALID);
|
||||||
|
@ -15,6 +15,7 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
|
|||||||
pending_plugins_(0),
|
pending_plugins_(0),
|
||||||
muted_(false),
|
muted_(false),
|
||||||
volume_(0.0),
|
volume_(0.0),
|
||||||
|
min_step_(0.0),
|
||||||
node_id_(0) {
|
node_id_(0) {
|
||||||
wp_init(WP_INIT_PIPEWIRE);
|
wp_init(WP_INIT_PIPEWIRE);
|
||||||
wp_core_ = wp_core_new(NULL, NULL);
|
wp_core_ = wp_core_new(NULL, NULL);
|
||||||
@ -39,6 +40,9 @@ waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Val
|
|||||||
activatePlugins();
|
activatePlugins();
|
||||||
|
|
||||||
dp.emit();
|
dp.emit();
|
||||||
|
|
||||||
|
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
|
||||||
|
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &Wireplumber::handleScroll));
|
||||||
}
|
}
|
||||||
|
|
||||||
waybar::modules::Wireplumber::~Wireplumber() {
|
waybar::modules::Wireplumber::~Wireplumber() {
|
||||||
@ -83,7 +87,6 @@ void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber*
|
|||||||
|
|
||||||
void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* self, uint32_t id) {
|
void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* self, uint32_t id) {
|
||||||
spdlog::debug("[{}]: updating volume", self->name_);
|
spdlog::debug("[{}]: updating volume", self->name_);
|
||||||
double vol;
|
|
||||||
GVariant* variant = NULL;
|
GVariant* variant = NULL;
|
||||||
|
|
||||||
if (!isValidNodeId(id)) {
|
if (!isValidNodeId(id)) {
|
||||||
@ -99,11 +102,11 @@ void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* se
|
|||||||
throw std::runtime_error(err);
|
throw std::runtime_error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_lookup(variant, "volume", "d", &vol);
|
g_variant_lookup(variant, "volume", "d", &self->volume_);
|
||||||
|
g_variant_lookup(variant, "step", "d", &self->min_step_);
|
||||||
g_variant_lookup(variant, "mute", "b", &self->muted_);
|
g_variant_lookup(variant, "mute", "b", &self->muted_);
|
||||||
g_clear_pointer(&variant, g_variant_unref);
|
g_clear_pointer(&variant, g_variant_unref);
|
||||||
|
|
||||||
self->volume_ = std::round(vol * 100.0F);
|
|
||||||
self->dp.emit();
|
self->dp.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,11 +283,12 @@ auto waybar::modules::Wireplumber::update() -> void {
|
|||||||
label_.get_style_context()->remove_class("muted");
|
label_.get_style_context()->remove_class("muted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vol = round(volume_ * 100.0);
|
||||||
std::string markup = fmt::format(fmt::runtime(format), fmt::arg("node_name", node_name_),
|
std::string markup = fmt::format(fmt::runtime(format), fmt::arg("node_name", node_name_),
|
||||||
fmt::arg("volume", volume_), fmt::arg("icon", getIcon(volume_)));
|
fmt::arg("volume", vol), fmt::arg("icon", getIcon(vol)));
|
||||||
label_.set_markup(markup);
|
label_.set_markup(markup);
|
||||||
|
|
||||||
getState(volume_);
|
getState(vol);
|
||||||
|
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
if (tooltip_format.empty() && config_["tooltip-format"].isString()) {
|
if (tooltip_format.empty() && config_["tooltip-format"].isString()) {
|
||||||
@ -292,9 +296,9 @@ auto waybar::modules::Wireplumber::update() -> void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!tooltip_format.empty()) {
|
if (!tooltip_format.empty()) {
|
||||||
label_.set_tooltip_text(
|
label_.set_tooltip_text(fmt::format(fmt::runtime(tooltip_format),
|
||||||
fmt::format(fmt::runtime(tooltip_format), fmt::arg("node_name", node_name_),
|
fmt::arg("node_name", node_name_),
|
||||||
fmt::arg("volume", volume_), fmt::arg("icon", getIcon(volume_))));
|
fmt::arg("volume", vol), fmt::arg("icon", getIcon(vol))));
|
||||||
} else {
|
} else {
|
||||||
label_.set_tooltip_text(node_name_);
|
label_.set_tooltip_text(node_name_);
|
||||||
}
|
}
|
||||||
@ -303,3 +307,49 @@ auto waybar::modules::Wireplumber::update() -> void {
|
|||||||
// Call parent update
|
// Call parent update
|
||||||
ALabel::update();
|
ALabel::update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool waybar::modules::Wireplumber::handleScroll(GdkEventScroll* e) {
|
||||||
|
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
|
||||||
|
return AModule::handleScroll(e);
|
||||||
|
}
|
||||||
|
auto dir = AModule::getScrollDir(e);
|
||||||
|
if (dir == SCROLL_DIR::NONE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (config_["reverse-scrolling"].asInt() == 1) {
|
||||||
|
if (dir == SCROLL_DIR::UP) {
|
||||||
|
dir = SCROLL_DIR::DOWN;
|
||||||
|
} else if (dir == SCROLL_DIR::DOWN) {
|
||||||
|
dir = SCROLL_DIR::UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double max_volume = 1;
|
||||||
|
double step = 1.0 / 100.0;
|
||||||
|
if (config_["scroll-step"].isDouble()) {
|
||||||
|
step = config_["scroll-step"].asDouble() / 100.0;
|
||||||
|
}
|
||||||
|
if (config_["max-volume"].isDouble()) {
|
||||||
|
max_volume = config_["max-volume"].asDouble() / 100.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step < min_step_) step = min_step_;
|
||||||
|
|
||||||
|
double new_vol = volume_;
|
||||||
|
if (dir == SCROLL_DIR::UP) {
|
||||||
|
if (volume_ < max_volume) {
|
||||||
|
new_vol = volume_ + step;
|
||||||
|
if (new_vol > max_volume) new_vol = max_volume;
|
||||||
|
}
|
||||||
|
} else if (dir == SCROLL_DIR::DOWN) {
|
||||||
|
if (volume_ > 0) {
|
||||||
|
new_vol = volume_ - step;
|
||||||
|
if (new_vol < 0) new_vol = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (new_vol != volume_) {
|
||||||
|
GVariant* variant = g_variant_new_double(new_vol);
|
||||||
|
gboolean ret;
|
||||||
|
g_signal_emit_by_name(mixer_api_, "set-volume", node_id_, variant, &ret);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "glibmm/fileutils.h"
|
#include "glibmm/fileutils.h"
|
||||||
#include "glibmm/refptr.h"
|
#include "glibmm/refptr.h"
|
||||||
#include "util/format.hpp"
|
#include "util/format.hpp"
|
||||||
|
#include "util/rewrite_string.hpp"
|
||||||
#include "util/string.hpp"
|
#include "util/string.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::wlr {
|
namespace waybar::modules::wlr {
|
||||||
@ -506,11 +507,11 @@ void Task::handle_closed() {
|
|||||||
spdlog::debug("{} closed", repr());
|
spdlog::debug("{} closed", repr());
|
||||||
zwlr_foreign_toplevel_handle_v1_destroy(handle_);
|
zwlr_foreign_toplevel_handle_v1_destroy(handle_);
|
||||||
handle_ = nullptr;
|
handle_ = nullptr;
|
||||||
|
tbar_->remove_task(id_);
|
||||||
if (button_visible_) {
|
if (button_visible_) {
|
||||||
tbar_->remove_button(button);
|
tbar_->remove_button(button);
|
||||||
button_visible_ = false;
|
button_visible_ = false;
|
||||||
}
|
}
|
||||||
tbar_->remove_task(id_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Task::handle_clicked(GdkEventButton *bt) {
|
bool Task::handle_clicked(GdkEventButton *bt) {
|
||||||
@ -622,6 +623,9 @@ void Task::update() {
|
|||||||
fmt::format(fmt::runtime(format_before_), fmt::arg("title", title), fmt::arg("name", name),
|
fmt::format(fmt::runtime(format_before_), fmt::arg("title", title), fmt::arg("name", name),
|
||||||
fmt::arg("app_id", app_id), fmt::arg("state", state_string()),
|
fmt::arg("app_id", app_id), fmt::arg("state", state_string()),
|
||||||
fmt::arg("short_state", state_string(true)));
|
fmt::arg("short_state", state_string(true)));
|
||||||
|
|
||||||
|
txt = waybar::util::rewriteString(txt, config_["rewrite"]);
|
||||||
|
|
||||||
if (markup)
|
if (markup)
|
||||||
text_before_.set_markup(txt);
|
text_before_.set_markup(txt);
|
||||||
else
|
else
|
||||||
@ -633,6 +637,9 @@ void Task::update() {
|
|||||||
fmt::format(fmt::runtime(format_after_), fmt::arg("title", title), fmt::arg("name", name),
|
fmt::format(fmt::runtime(format_after_), fmt::arg("title", title), fmt::arg("name", name),
|
||||||
fmt::arg("app_id", app_id), fmt::arg("state", state_string()),
|
fmt::arg("app_id", app_id), fmt::arg("state", state_string()),
|
||||||
fmt::arg("short_state", state_string(true)));
|
fmt::arg("short_state", state_string(true)));
|
||||||
|
|
||||||
|
txt = waybar::util::rewriteString(txt, config_["rewrite"]);
|
||||||
|
|
||||||
if (markup)
|
if (markup)
|
||||||
text_after_.set_markup(txt);
|
text_after_.set_markup(txt);
|
||||||
else
|
else
|
||||||
@ -710,6 +717,7 @@ Taskbar::Taskbar(const std::string &id, const waybar::Bar &bar, const Json::Valu
|
|||||||
if (!id.empty()) {
|
if (!id.empty()) {
|
||||||
box_.get_style_context()->add_class(id);
|
box_.get_style_context()->add_class(id);
|
||||||
}
|
}
|
||||||
|
box_.get_style_context()->add_class("empty");
|
||||||
event_box_.add(box_);
|
event_box_.add(box_);
|
||||||
|
|
||||||
struct wl_display *display = Client::inst()->wl_display;
|
struct wl_display *display = Client::inst()->wl_display;
|
||||||
@ -862,11 +870,19 @@ void Taskbar::handle_finished() {
|
|||||||
manager_ = nullptr;
|
manager_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Taskbar::add_button(Gtk::Button &bt) { box_.pack_start(bt, false, false); }
|
void Taskbar::add_button(Gtk::Button &bt) {
|
||||||
|
box_.pack_start(bt, false, false);
|
||||||
|
box_.get_style_context()->remove_class("empty");
|
||||||
|
}
|
||||||
|
|
||||||
void Taskbar::move_button(Gtk::Button &bt, int pos) { box_.reorder_child(bt, pos); }
|
void Taskbar::move_button(Gtk::Button &bt, int pos) { box_.reorder_child(bt, pos); }
|
||||||
|
|
||||||
void Taskbar::remove_button(Gtk::Button &bt) { box_.remove(bt); }
|
void Taskbar::remove_button(Gtk::Button &bt) {
|
||||||
|
box_.remove(bt);
|
||||||
|
if (tasks_.empty()) {
|
||||||
|
box_.get_style_context()->add_class("empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Taskbar::remove_task(uint32_t id) {
|
void Taskbar::remove_task(uint32_t id) {
|
||||||
auto it = std::find_if(std::begin(tasks_), std::end(tasks_),
|
auto it = std::find_if(std::begin(tasks_), std::end(tasks_),
|
||||||
|
@ -64,7 +64,7 @@ WorkspaceManager::WorkspaceManager(const std::string &id, const waybar::Bar &bar
|
|||||||
|
|
||||||
auto WorkspaceManager::workspace_comparator() const
|
auto WorkspaceManager::workspace_comparator() const
|
||||||
-> std::function<bool(std::unique_ptr<Workspace> &, std::unique_ptr<Workspace> &)> {
|
-> std::function<bool(std::unique_ptr<Workspace> &, std::unique_ptr<Workspace> &)> {
|
||||||
return [=](std::unique_ptr<Workspace> &lhs, std::unique_ptr<Workspace> &rhs) {
|
return [=, this](std::unique_ptr<Workspace> &lhs, std::unique_ptr<Workspace> &rhs) {
|
||||||
auto is_name_less = lhs->get_name() < rhs->get_name();
|
auto is_name_less = lhs->get_name() < rhs->get_name();
|
||||||
auto is_name_eq = lhs->get_name() == rhs->get_name();
|
auto is_name_eq = lhs->get_name() == rhs->get_name();
|
||||||
auto is_coords_less = lhs->get_coords() < rhs->get_coords();
|
auto is_coords_less = lhs->get_coords() < rhs->get_coords();
|
||||||
@ -73,7 +73,7 @@ auto WorkspaceManager::workspace_comparator() const
|
|||||||
try {
|
try {
|
||||||
auto is_number_less = std::stoi(lhs->get_name()) < std::stoi(rhs->get_name());
|
auto is_number_less = std::stoi(lhs->get_name()) < std::stoi(rhs->get_name());
|
||||||
return is_number_less;
|
return is_number_less;
|
||||||
} catch (std::invalid_argument) {
|
} catch (const std::invalid_argument &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
25
src/util/gtk_icon.cpp
Normal file
25
src/util/gtk_icon.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include "util/gtk_icon.hpp"
|
||||||
|
|
||||||
|
/* We need a global mutex for accessing the object returned by Gtk::IconTheme::get_default()
|
||||||
|
* because it always returns the same object across different threads, and concurrent
|
||||||
|
* access can cause data corruption and lead to invalid memory access and crashes.
|
||||||
|
* Even concurrent calls that seem read only such as has_icon can cause issues because
|
||||||
|
* the GTK lib may update the internal icon cache on this calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::mutex DefaultGtkIconThemeWrapper::default_theme_mutex;
|
||||||
|
|
||||||
|
bool DefaultGtkIconThemeWrapper::has_icon(const std::string& value) {
|
||||||
|
const std::lock_guard<std::mutex> lock(default_theme_mutex);
|
||||||
|
|
||||||
|
return Gtk::IconTheme::get_default()->has_icon(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> DefaultGtkIconThemeWrapper::load_icon(const char* name, int tmp_size,
|
||||||
|
Gtk::IconLookupFlags flags) {
|
||||||
|
const std::lock_guard<std::mutex> lock(default_theme_mutex);
|
||||||
|
|
||||||
|
auto default_theme = Gtk::IconTheme::get_default();
|
||||||
|
default_theme->rescan_if_needed();
|
||||||
|
return default_theme->load_icon(name, tmp_size, flags);
|
||||||
|
}
|
49
src/util/prepare_for_sleep.cpp
Normal file
49
src/util/prepare_for_sleep.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#include "util/prepare_for_sleep.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class PrepareForSleep {
|
||||||
|
private:
|
||||||
|
PrepareForSleep() {
|
||||||
|
GError *error = NULL;
|
||||||
|
login1_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
|
||||||
|
if (!login1_connection) {
|
||||||
|
throw std::runtime_error("Unable to connect to the SYSTEM Bus!...");
|
||||||
|
} else {
|
||||||
|
login1_id = g_dbus_connection_signal_subscribe(
|
||||||
|
login1_connection, "org.freedesktop.login1", "org.freedesktop.login1.Manager",
|
||||||
|
"PrepareForSleep", "/org/freedesktop/login1", NULL, G_DBUS_SIGNAL_FLAGS_NONE,
|
||||||
|
prepareForSleep_cb, this, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prepareForSleep_cb(GDBusConnection *system_bus, const gchar *sender_name,
|
||||||
|
const gchar *object_path, const gchar *interface_name,
|
||||||
|
const gchar *signal_name, GVariant *parameters,
|
||||||
|
gpointer user_data) {
|
||||||
|
if (g_variant_is_of_type(parameters, G_VARIANT_TYPE("(b)"))) {
|
||||||
|
gboolean sleeping;
|
||||||
|
g_variant_get(parameters, "(b)", &sleeping);
|
||||||
|
|
||||||
|
PrepareForSleep *self = static_cast<PrepareForSleep *>(user_data);
|
||||||
|
self->signal.emit(sleeping);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static PrepareForSleep &GetInstance() {
|
||||||
|
static PrepareForSleep instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
waybar::SafeSignal<bool> signal;
|
||||||
|
|
||||||
|
private:
|
||||||
|
guint login1_id;
|
||||||
|
GDBusConnection *login1_connection;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
waybar::SafeSignal<bool> &waybar::util::prepare_for_sleep() {
|
||||||
|
return PrepareForSleep::GetInstance().signal;
|
||||||
|
}
|
@ -63,7 +63,7 @@ bool waybar::util::Rfkill::on_event(Glib::IOCondition cond) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len < RFKILL_EVENT_SIZE_V1) {
|
if (static_cast<size_t>(len) < RFKILL_EVENT_SIZE_V1) {
|
||||||
spdlog::error("Wrong size of RFKILL event: {} < {}", len, RFKILL_EVENT_SIZE_V1);
|
spdlog::error("Wrong size of RFKILL event: {} < {}", len, RFKILL_EVENT_SIZE_V1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -73,10 +73,9 @@ bool waybar::util::Rfkill::on_event(Glib::IOCondition cond) {
|
|||||||
on_update.emit(event);
|
on_update.emit(event);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
spdlog::error("Failed to poll RFKILL control device");
|
spdlog::error("Failed to poll RFKILL control device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool waybar::util::Rfkill::getState() const { return state_; }
|
bool waybar::util::Rfkill::getState() const { return state_; }
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
[wrap-file]
|
[wrap-file]
|
||||||
directory = Catch2-3.1.0
|
directory = Catch2-3.3.2
|
||||||
source_url = https://github.com/catchorg/Catch2/archive/v3.1.0.tar.gz
|
source_url = https://github.com/catchorg/Catch2/archive/v3.3.2.tar.gz
|
||||||
source_filename = Catch2-3.1.0.tar.gz
|
source_filename = Catch2-3.3.2.tar.gz
|
||||||
source_hash = c252b2d9537e18046d8b82535069d2567f77043f8e644acf9a9fffc22ea6e6f7
|
source_hash = 8361907f4d9bff3ae7c1edb027f813659f793053c99b67837a0c0375f065bae2
|
||||||
patch_filename = catch2_3.1.0-1_patch.zip
|
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/catch2_3.3.2-1/Catch2-3.3.2.tar.gz
|
||||||
patch_url = https://wrapdb.mesonbuild.com/v2/catch2_3.1.0-1/get_patch
|
wrapdb_version = 3.3.2-1
|
||||||
patch_hash = 4ebf4277aed574a9912a79f4817a310d837798e099bbafa6097be23a7f5e3ae4
|
|
||||||
wrapdb_version = 3.1.0-1
|
|
||||||
|
|
||||||
[provide]
|
[provide]
|
||||||
catch2 = catch2_dep
|
catch2 = catch2_dep
|
||||||
|
Reference in New Issue
Block a user