Compare commits

..

143 Commits
0.6.6 ... 0.8.0

Author SHA1 Message Date
fe88a3fa81 chore: 0.8.0 2019-08-29 11:56:57 +02:00
02e43a38d2 Merge pull request #439 from jbeich/fmt
Unbreak with fmtlib 6.0.0
2019-08-29 11:29:54 +02:00
f592e3d38b Merge branch 'master' into fmt 2019-08-29 11:29:48 +02:00
c6d7a779b8 Merge pull request #442 from xPMo/master
sway/mode: enable pango markup on supported modes
2019-08-29 11:06:01 +02:00
ceedc689ec Merge branch 'master' into master 2019-08-29 11:05:55 +02:00
b314cb16a9 Merge pull request #437 from alebastr/asan-fixes
fix(network): stack-use-after-return found by address sanitizer
2019-08-29 11:04:30 +02:00
a257126685 Merge branch 'master' into asan-fixes 2019-08-29 11:04:24 +02:00
baaeda0ab7 Merge pull request #438 from alebastr/tray-fixes
Tray fixes
2019-08-29 11:03:09 +02:00
e3dff6e0d8 Merge branch 'master' into tray-fixes 2019-08-29 11:02:50 +02:00
e8a1e6ae35 Merge pull request #431 from MichaelAquilina/man_waybar
Add support for man pages
2019-08-29 11:00:59 +02:00
3a86125495 Merge pull request #1 from xPMo/man_waybar
Add supported xdg-spec directory
2019-08-29 09:39:51 +01:00
da43336409 man: add supported xdg-spec directory
$XDG_CONFIG_HOME
2019-08-28 22:05:03 -05:00
712424f9a8 Unbreak build with fmtlib 6.0.0
In file included from ../src/factory.cpp:1:
In file included from ../include/factory.hpp:4:
../include/modules/clock.hpp:5:10: fatal error: 'fmt/time.h' file not found
 #include "fmt/time.h"
          ^~~~~~~~~~~~
In file included from ../src/bar.cpp:4:
In file included from ../include/factory.hpp:4:
In file included from ../include/modules/clock.hpp:3:
In file included from /usr/include/fmt/chrono.h:12:
/usr/include/fmt/locale.h:19:35: error: parameter type 'fmt::v5::internal::buffer' (aka 'basic_buffer<char>') is an abstract class
    const std::locale& loc, buffer<Char>& buf,
                                  ^
/usr/include/spdlog/fmt/bundled/core.h:238:16: note: unimplemented pure virtual method 'grow' in 'basic_buffer'
  virtual void grow(std::size_t capacity) = 0;
               ^
In file included from ../src/modules/sni/host.cpp:3:
/usr/include/fmt/ostream.h:22:9: error: expected member name or ';' after declaration specifiers
  buffer<Char>& buffer_;
  ~~~~~~^
/usr/include/fmt/ostream.h:25:19: error: expected ')'
  formatbuf(buffer<Char>& buf) : buffer_(buf) {}
                  ^
/usr/include/fmt/ostream.h:25:12: note: to match this '('
  formatbuf(buffer<Char>& buf) : buffer_(buf) {}
           ^
/usr/include/fmt/ostream.h:25:42: error: use of undeclared identifier 'buf'; did you mean 'prettify_handler::buf'?
  formatbuf(buffer<Char>& buf) : buffer_(buf) {}
                                         ^~~
                                         prettify_handler::buf
/usr/include/spdlog/fmt/bundled/format-inl.h:551:11: note: 'prettify_handler::buf' declared here
  buffer &buf;
          ^
2019-08-29 01:38:54 +00:00
e38df047fd sway/mode: enable pango markup on supported modes
IPC reports {"mode": "mode_string", "pango_markup": bool}.
Use this to conditionally enable pango markup.
2019-08-28 19:48:33 -05:00
0b237246f0 Fixes to man pages 2019-08-27 10:40:19 +01:00
01ad3d96d8 fix(tray): pre-create dbusmenu for tray items
It seems that dbusmenu is not ready to display menu immediately and
needs some time to sync data via DBus.
Fixes LIBDBUSMENU-GLIB-CRITICAL: dbusmenu_menuitem_send_about_to_show:
assertion 'DBUSMENU_IS_MENUITEM(mi)' failed.
Also fixes initial render of the menu with layer shell popups support patch.
2019-08-27 00:34:00 -07:00
642fd48af1 fix(tray): restore Activate support for compliant SNI implementation
Set ItemIsMenu to true by default because libappindicator supports
neither ItemIsMenu nor Activate method and compiant SNI implementations
are expected to reset the flag during initial property fetch.
To be revisited if anyone finds the implementation that has Activate
but does not set ItemIsMenu.
2019-08-27 00:33:59 -07:00
8f9e6c132d fix(network): stack-use-after-return found by address sanitizer
Fixes compilation with clang.
2019-08-27 00:11:40 -07:00
ba5592c86a Add waybar-states(5) 2019-08-26 22:49:04 +01:00
2a3f40bc02 Minor fixes to waybar(5) 2019-08-26 22:34:19 +01:00
c60b905831 replace `` with ** 2019-08-26 22:31:05 +01:00
6536f7adb6 Consistent header names 2019-08-26 22:29:10 +01:00
8134215839 s/config/configuration where it makes sense 2019-08-26 22:29:05 +01:00
e6fa37164c List supported modules in waybar(5) 2019-08-26 18:20:22 +01:00
436fc94549 Add waybar-tray(5) 2019-08-26 18:15:58 +01:00
4f9c3d2413 Add waybar-temperature(5) 2019-08-26 18:13:48 +01:00
c19a63e85e Add waybar-sway-workspaces(5) 2019-08-26 18:08:59 +01:00
05e212f67a Add waybar-sway-window(5) 2019-08-26 18:00:46 +01:00
e01e3be488 Add waybar-sway-mode(5) 2019-08-26 17:55:20 +01:00
f380844d61 Add waybar-pulseaudio(5) 2019-08-26 17:50:16 +01:00
7f6e4801eb Add waybar-network(5) 2019-08-26 17:42:30 +01:00
ac461f38f4 Add waybar-mpd(5) 2019-08-26 15:27:32 +01:00
30efd28b6a Add waybar-memory(5) 2019-08-26 15:12:42 +01:00
87392ef653 Add waybar-idle-inhibitor(5) 2019-08-26 15:11:07 +01:00
db85224d59 Add waybar-custom(5) 2019-08-26 13:44:09 +01:00
07d6a8e936 Use tabs not spaces in scd files 2019-08-26 13:31:57 +01:00
53614ab50c Add waybar-cpu(5) 2019-08-26 13:23:11 +01:00
fba1f5c8af Move scd files to man/ folder 2019-08-26 13:11:06 +01:00
df83404c8c Format headers 2019-08-24 21:46:56 +01:00
dd3da7b6ef Minor fixes to waybar(5) 2019-08-24 21:44:11 +01:00
cda9eb683f Add waybar-clock(5) 2019-08-24 18:09:08 +01:00
f0ad918feb Add waybar-battery(5) 2019-08-24 17:53:56 +01:00
8696ac77f9 Replace table with simpler format in waybar.5.scd 2019-08-24 17:19:32 +01:00
9484cdff7d Add waybar-backlight.5.scd 2019-08-24 15:39:46 +01:00
9b9818e95d Set scdoc dependency to required: false 2019-08-22 17:13:04 +01:00
cf72dee60c Add scdoc dependency to Dockerfiles 2019-08-22 17:11:24 +01:00
2e037df045 Add scdoc to meson build process 2019-08-22 17:04:09 +01:00
798fe1a622 Add initial man 5 waybar 2019-08-20 19:58:33 +01:00
9d0842db48 Merge pull request #429 from tufteddeer/#420_mute_bt
add support for muted bluetooth audio, fix #420
2019-08-19 10:00:30 +02:00
d8b1b0d0af add support for muted bluetooth audio, fix #420 2019-08-18 16:15:21 +02:00
e9b6380c18 chore: 0.7.2 2019-08-08 12:25:31 +02:00
43beefb00d Merge pull request #421 from SibrenVasse/media_fix
fix(custom): ignore selected_player if not defined. Fixes #419
2019-07-31 12:13:45 +02:00
12f869ccba chore: add player filter example in config 2019-07-31 11:59:33 +02:00
7e9207d75c fix(custom): ignore selected_player if not defined. Fixes #419 2019-07-31 11:53:59 +02:00
7a2dee7377 Fix typo in log warning (#411)
Fix typo in log warning
2019-07-15 13:38:23 +02:00
21a89ac46d Typo 2019-07-15 12:21:31 +02:00
bb99e6cf5b fix: check before destroy 2019-07-15 10:06:01 +02:00
0834551161 chore: 0.7.1 2019-07-11 17:02:47 +02:00
ccd1586c65 Merge pull request #405 from crwxrws/fix-400
fix(pulseaudio): connect scroll event handler
2019-07-09 09:46:05 +02:00
617b370104 fix(pulseaudio): connect scroll event handler
Reconnect the event handler that was removed in commit 527144a.

Fixes Alexays#400
2019-07-06 15:51:00 +02:00
d607a4e33f Fix deadlock on workspace scrolling (#403)
Fix deadlock on workspace scrolling
2019-07-06 10:30:57 +02:00
a6c0bc5a52 Fix deadlock on workspace scrolling
Make the mutex guard lifecycle finish before the send ipc command
by adding scope around the code.

Fixes #395 .
2019-07-05 20:47:44 -07:00
67ad0e69ce Merge pull request #397 from Jamedjo/jej/add-css-classes-for-multiple-bars
Allow CSS to select specific waybars when multiple are in use
2019-07-04 14:20:03 +02:00
ae88d6bc3c feat(bar): individual bars can be named for CSS
Allows CSS to select individual waybars when multiple are configured
2019-07-04 02:15:56 +01:00
4f3c38c542 feat(bar): add CSS class for window position 2019-07-04 02:15:50 +01:00
a6980fca7f feat: ellipsize modules 2019-06-28 14:16:09 +02:00
bd5146fdcf fix(Label): ELLIPSIZE all label modules 2019-06-28 13:49:04 +02:00
22ddbde394 style(workspaces): update hover style 2019-06-28 13:41:53 +02:00
c916fe258e fix(network): no need to check family here 2019-06-25 07:55:55 +02:00
9c8e39c30c chore: 0.7.0 2019-06-22 18:17:16 +02:00
5b270dae0d refactor: AModule (#387)
refactor: AModule
2019-06-22 18:15:50 +02:00
c621afb0c4 Merge branch 'master' into clean 2019-06-22 18:15:34 +02:00
bcf4725349 Cleanup on clean branch (#391)
Cleanup on clean branch
2019-06-18 09:43:34 +02:00
12b30ca25f AModule::getScrollDir: convert reset if-else into switch 2019-06-17 20:42:19 +02:00
86d6668ed4 AModule::getScrollDir: convert if-else chain into switch statement 2019-06-17 20:40:13 +02:00
7c85aec8e0 AModule::getScrollDir: get deltas in a more C++ way 2019-06-17 20:29:37 +02:00
2c038d1977 AModule::getScrollDir: move dir inside the only scope it is relevant 2019-06-17 20:09:53 +02:00
ff9d598c16 fix: add proper mutex 2019-06-17 11:39:45 +02:00
71a9a75aad refactor: remove fix workaround 2019-06-16 15:14:31 +02:00
05f796158b fix: typo 2019-06-16 15:13:40 +02:00
1d2dd953e7 revert: default config 2019-06-16 15:09:26 +02:00
527144a440 refactor(pulseaudio): proper scroll override 2019-06-16 15:08:08 +02:00
cda6282277 Merge pull request #389 from Synthetica9/x-scroll
AModule: handle X axis scrolling
2019-06-16 14:54:53 +02:00
7f13478396 AModule: handle X axis scrolling 2019-06-16 13:17:34 +02:00
90a9c0e25f refactor: get rid of some mutex 2019-06-15 15:01:03 +02:00
340ec7be91 refactor: AModule 2019-06-15 14:57:52 +02:00
e7eef6b493 Merge pull request #385 from nenad/patch/add-total-memory
Expose total memory to the formatting directive
2019-06-15 11:16:30 +02:00
1b7068e61d Expose total memory to the formatting directive 2019-06-14 22:48:16 +02:00
dabe2bebbb feat(sway/window): handle floating nodes 2019-06-14 11:27:40 +02:00
486b5a5d38 fix(sway/window): check output recursively 2019-06-14 10:57:22 +02:00
11bbc3b24d Fix twitchy scrolling on touchpads (#381)
Fix twitchy scrolling on touchpads
2019-06-14 10:38:25 +02:00
7f74de977c chore: 0.6.9 2019-06-14 10:27:41 +02:00
028b184f7b fix(workspaces): persistant class with empty outputs 2019-06-12 09:50:33 +02:00
564fdcb369 fix(custom): exit status 2019-06-11 22:09:47 +02:00
396f7d4525 Workspaces: implement horizontal continuous scrolling 2019-06-11 18:44:54 +02:00
3c9b533997 fix(window): avoid hexpand 2019-06-11 17:57:17 +02:00
ae397c8fa2 ALabel: add smooth-scrolling-threshold 2019-06-11 17:56:10 +02:00
ec75be0bc3 fix(Tray): click behaviour 2019-06-11 17:53:16 +02:00
ed4521d113 Workspaces: fix twitchy scrolling on touchpads
Previously, any and all scroll events were interpreted as reason to switch
workspaces. This resulted in twitchy behaviour, where the scrolling was
practically unusable.

Now, we pool all scroll values, and only scroll if the value is larger than the
new config option "smooth-scrolling-threshold". If this option is not set, the
behaviour is unchanged.
2019-06-11 17:22:24 +02:00
c2e9ed6091 feat(workspaces): add class to persistant workspaces 2019-06-11 14:08:48 +02:00
a37b4687ff Revert "refactor(window): we don't need to subscribe workspace events"
This reverts commit 648eecdd83.
2019-06-11 14:06:31 +02:00
ee29a35aa5 Update README.md 2019-06-11 13:55:35 +02:00
0be8e200ce adds the wl output name as a css class (#373)
adds the wl output name as a css class
2019-06-10 12:15:05 +02:00
46e5dd93d4 adds the wl output name as a css class
now you can have a custom styling for each bar
2019-06-08 11:04:34 -07:00
2ee4a51546 chore: 0.6.8 2019-06-08 18:33:17 +02:00
91996a85c1 Merge pull request #372 from rianadon/patch-1
Increase specificity of media stylings
2019-06-08 18:28:42 +02:00
460d25ac45 Increase specificity of media stylings
Because of CSS specificity rules, the `#custom-media` style will always override the `custom-spotify` and `custom-vlc` styles, so the background of the media element is always green rather than sometimes orange when VLC is running. I added `#custom-media` in front of each of the class selectors to increase their specificity so they take precedence.
2019-06-07 22:18:06 -07:00
648eecdd83 refactor(window): we don't need to subscribe workspace events 2019-06-07 15:08:33 +02:00
f04ff38567 Merge pull request #370 from toke/bugfix/upstream-369
Prevent zombie apocalypse by ignoring SIGCHLD
2019-06-06 12:07:03 +02:00
d20a586734 Prevent zombie apocalypse by ignoring SIGCHLD
Fixes Issue #369
2019-06-05 14:35:25 +02:00
1962caf144 refactor(window): gtk stuff in update method 2019-06-04 17:34:00 +02:00
9dbf057f58 fix(custom): hide on empty format 2019-06-03 09:50:35 +02:00
918146c16b style: prefer background-color property 2019-05-31 17:20:14 +02:00
0b01b35c76 refactor(pulseaudio): only watch changes 2019-05-31 16:21:01 +02:00
f3fb955d75 chore: 0.6.7 2019-05-31 12:15:01 +02:00
fcf2d18a01 refactor: destroy threads first 2019-05-29 17:53:22 +02:00
b05d4cd413 fix(network): retry around all getExternalInterface 2019-05-29 16:17:40 +02:00
9b89fc6470 refactor: disable bar scroll by default 2019-05-28 16:11:33 +02:00
c06725aa69 fix(network): better disconnect handler 2019-05-28 11:21:59 +02:00
5ae5821929 refactor(network): re-add MAX_RETRY in order to detect external interface 2019-05-28 11:08:48 +02:00
74e40432e5 fix(network): linked state 2019-05-28 09:58:48 +02:00
6e69af8967 refactor(custon): avoid useless logic 2019-05-27 00:08:16 +02:00
be2fa743eb refactor(custon): hide on empty text 2019-05-27 00:05:29 +02:00
5fdb122829 Create FUNDING.yml 2019-05-26 23:55:46 +02:00
6e73c6db61 refactor(network): remove last_ext_iface_ 2019-05-26 23:16:09 +02:00
253366baf4 refactor(network): remove useless assignment 2019-05-26 22:40:29 +02:00
ecec02c8be refactor(network): better events handler 2019-05-26 22:36:26 +02:00
070619fa34 revert: restore idle fix 2019-05-26 20:09:05 +02:00
d4ace4b4d8 fix(network): subscribe only wanted family 2019-05-26 20:06:27 +02:00
5fd92b3c28 fix(network): don't check IFF_UP 2019-05-26 19:53:10 +02:00
c0a39f34cd refactor(network): don't clear ipaddr 2019-05-25 18:02:36 +02:00
2a9fa1a4b9 refactor(bar): onRealize, onMap 2019-05-25 17:50:45 +02:00
07147878a9 refactor(network): code cleaning 2019-05-24 09:49:56 +02:00
ffadd5c1a7 refactor: avoid useless class vars 2019-05-24 09:49:09 +02:00
2b34f3a30f refactor: parse args before app creation 2019-05-23 10:13:49 +02:00
85d60f95c4 refactor(network): const methods 2019-05-22 22:20:50 +02:00
755d38d4d6 fix(custom): bad alloc 2019-05-22 19:46:56 +02:00
b673279a43 style: remove non wanted comment 2019-05-22 12:22:56 +02:00
9e1200ae32 refactor: also pass id to custom modules 2019-05-22 12:20:13 +02:00
e999cca7a6 style: don't specify included namespaces 2019-05-22 12:15:59 +02:00
d24d85bebf refactor: move label name and id to label contructor 2019-05-22 12:06:24 +02:00
97bd637f5d refactor(clock): avoid usless time_point_cast 2019-05-22 11:51:33 +02:00
23d4a811db refactor(clock): avoid usless duration_cast 2019-05-22 11:48:02 +02:00
74 changed files with 2682 additions and 769 deletions

3
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,3 @@
# These are supported funding model platforms
custom: https://paypal.me/ARouillard

View File

@ -1,3 +1,3 @@
FROM alpine:latest
RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev libnl3-dev pulseaudio-dev libmpdclient-dev
RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev libnl3-dev pulseaudio-dev libmpdclient-dev scdoc

View File

@ -1,4 +1,4 @@
FROM archlinux/base:latest
RUN pacman -Syu --noconfirm && \
pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp --noconfirm
pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp scdoc --noconfirm

View File

@ -1,5 +1,5 @@
FROM debian:sid
RUN apt-get update && \
apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev && \
apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev scdoc && \
apt-get clean

View File

@ -1,5 +1,5 @@
FROM fedora:30
RUN dnf install sway meson git libinput-devel wayland-devel wayland-protocols-devel egl-wayland-devel mesa-libEGL-devel mesa-libGLES-devel mesa-libgbm-devel libxkbcommon-devel libudev-devel pixman-devel gtkmm30-devel jsoncpp-devel -y && \
RUN dnf install sway meson git libinput-devel wayland-devel wayland-protocols-devel egl-wayland-devel mesa-libEGL-devel mesa-libGLES-devel mesa-libgbm-devel libxkbcommon-devel libudev-devel pixman-devel gtkmm30-devel jsoncpp-devel scdoc -y && \
dnf group install "C Development Tools and Libraries" -y && \
dnf clean all -y

View File

@ -2,4 +2,4 @@ FROM opensuse/tumbleweed:latest
RUN zypper -n up && \
zypper -n install -t pattern devel_C_C++ && \
zypper -n install git meson clang libinput10 libinput-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel
zypper -n install git meson clang libinput10 libinput-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel scdoc

View File

@ -2,7 +2,8 @@
> 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
[AUR](https://aur.archlinux.org/packages/waybar-git/) and [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar)
[AUR](https://aur.archlinux.org/packages/waybar-git/) and [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar)<br>
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
**Current features**
- Sway (Workspaces, Binding mode, Focused window name)
@ -42,6 +43,7 @@ $ waybar
gtkmm3
jsoncpp
libinput
libsigc++
fmt
wayland

View File

@ -1,40 +1,30 @@
#pragma once
#include <glibmm/markup.h>
#include <gtkmm/eventbox.h>
#include <gtkmm/label.h>
#include <json/json.h>
#include "IModule.hpp"
#include "AModule.hpp"
namespace waybar {
class ALabel : public IModule {
class ALabel : public AModule {
public:
ALabel(const Json::Value &, const std::string &format, uint16_t interval = 0);
virtual ~ALabel();
ALabel(const Json::Value &, const std::string &, const std::string &, const std::string &format,
uint16_t interval = 0, bool ellipsize = false);
virtual ~ALabel() = default;
virtual auto update() -> void;
virtual std::string getIcon(uint16_t, const std::string &alt = "", uint16_t max = 0);
virtual operator Gtk::Widget &();
protected:
bool tooltipEnabled();
Gtk::EventBox event_box_;
Gtk::Label label_;
const Json::Value & config_;
std::string format_;
std::string click_param;
std::mutex mutex_;
const std::chrono::seconds interval_;
bool alt_ = false;
std::string default_format_;
virtual bool handleToggle(GdkEventButton *const &ev);
virtual bool handleScroll(GdkEventScroll *);
virtual bool handleToggle(GdkEventButton *const &e);
virtual std::string getState(uint8_t value, bool lesser = false);
private:
std::vector<int> pid_;
};
} // namespace waybar

40
include/AModule.hpp Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <glibmm/dispatcher.h>
#include <glibmm/markup.h>
#include <gtkmm/eventbox.h>
#include <json/json.h>
#include "IModule.hpp"
namespace waybar {
class AModule : public IModule {
public:
AModule(const Json::Value &, const std::string &, const std::string &,
bool enable_click = false, bool enable_scroll = false);
virtual ~AModule();
virtual auto update() -> void;
virtual operator Gtk::Widget &();
Glib::Dispatcher dp;
protected:
enum SCROLL_DIR { NONE, UP, DOWN, LEFT, RIGHT };
SCROLL_DIR getScrollDir(GdkEventScroll *e);
bool tooltipEnabled();
const Json::Value &config_;
Gtk::EventBox event_box_;
std::string click_param_;
virtual bool handleToggle(GdkEventButton *const &ev);
virtual bool handleScroll(GdkEventScroll *);
private:
std::vector<int> pid_;
gdouble distance_scrolled_y_;
gdouble distance_scrolled_x_;
};
} // namespace waybar

View File

@ -1,7 +1,5 @@
#pragma once
#include <glibmm/dispatcher.h>
#include <gtkmm/box.h>
#include <gtkmm/widget.h>
namespace waybar {
@ -11,7 +9,6 @@ class IModule {
virtual ~IModule() = default;
virtual auto update() -> void = 0;
virtual operator Gtk::Widget &() = 0;
Glib::Dispatcher dp; // Hmmm Maybe I should create an abstract class ?
};
} // namespace waybar

View File

@ -1,11 +1,12 @@
#pragma once
#include <glibmm/refptr.h>
#include <gtkmm/box.h>
#include <gtkmm/cssprovider.h>
#include <gtkmm/main.h>
#include <gtkmm/window.h>
#include <json/json.h>
#include "IModule.hpp"
#include "AModule.hpp"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
@ -14,10 +15,10 @@ namespace waybar {
class Factory;
struct waybar_output {
struct wl_output * output;
struct wl_output * output = nullptr;
std::string name;
uint32_t wl_name;
struct zxdg_output_v1 *xdg_output;
struct zxdg_output_v1 *xdg_output = nullptr;
};
class Bar {
@ -38,13 +39,13 @@ class Bar {
bool vertical = false;
private:
static constexpr const char* MIN_HEIGHT_MSG =
static constexpr const char *MIN_HEIGHT_MSG =
"Requested height: {} exceeds the minimum height: {} required by the modules";
static constexpr const char* MIN_WIDTH_MSG =
static constexpr const char *MIN_WIDTH_MSG =
"Requested width: {} exceeds the minimum width: {} required by the modules";
static constexpr const char* BAR_SIZE_MSG =
static constexpr const char *BAR_SIZE_MSG =
"Bar configured (width: {}, height: {}) for output: {}";
static constexpr const char* SIZE_DEFINED =
static constexpr const char *SIZE_DEFINED =
"{} size is defined in the config file so it will stay like that";
static void layerSurfaceHandleConfigure(void *, struct zwlr_layer_surface_v1 *, uint32_t,
uint32_t, uint32_t);
@ -52,6 +53,8 @@ class Bar {
void destroyOutput();
void onConfigure(GdkEventConfigure *ev);
void onRealize();
void onMap(GdkEventAny *ev);
void setMarginsAndZone(uint32_t height, uint32_t width);
auto setupWidgets() -> void;
void getModules(const Factory &, const std::string &);
@ -66,13 +69,14 @@ class Bar {
} margins_;
uint32_t width_ = 0;
uint32_t height_ = 1;
uint8_t anchor_;
Gtk::Box left_;
Gtk::Box center_;
Gtk::Box right_;
Gtk::Box box_;
std::vector<std::unique_ptr<waybar::IModule>> modules_left_;
std::vector<std::unique_ptr<waybar::IModule>> modules_center_;
std::vector<std::unique_ptr<waybar::IModule>> modules_right_;
std::vector<std::unique_ptr<waybar::AModule>> modules_left_;
std::vector<std::unique_ptr<waybar::AModule>> modules_center_;
std::vector<std::unique_ptr<waybar::AModule>> modules_right_;
};
} // namespace waybar

View File

@ -26,14 +26,15 @@ class Client {
private:
Client() = default;
void setupConfigs(const std::string &config, const std::string &style);
void bindInterfaces();
const std::string getValidPath(const std::vector<std::string> &paths);
std::tuple<const std::string, const std::string> getConfigs(const std::string &config,
const std::string &style) const;
void bindInterfaces();
const std::string getValidPath(const std::vector<std::string> &paths) const;
void handleOutput(std::unique_ptr<struct waybar_output> &output);
bool isValidOutput(const Json::Value &config, std::unique_ptr<struct waybar_output> &output);
auto setupConfig() -> void;
auto setupCss() -> void;
std::unique_ptr<struct waybar_output>& getOutput(uint32_t wl_name);
auto setupConfig(const std::string &config_file) -> void;
auto setupCss(const std::string &css_file) -> void;
std::unique_ptr<struct waybar_output> &getOutput(uint32_t wl_name);
std::vector<Json::Value> getOutputConfigs(std::unique_ptr<struct waybar_output> &output);
static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
@ -46,8 +47,6 @@ class Client {
static void handleDescription(void *, struct zxdg_output_v1 *, const char *);
Json::Value config_;
std::string css_file_;
std::string config_file_;
Glib::RefPtr<Gtk::StyleContext> style_context_;
Glib::RefPtr<Gtk::CssProvider> css_provider_;
std::vector<std::unique_ptr<struct waybar_output>> outputs_;

View File

@ -37,7 +37,7 @@ namespace waybar {
class Factory {
public:
Factory(const Bar& bar, const Json::Value& config);
IModule* makeModule(const std::string& name) const;
AModule* makeModule(const std::string& name) const;
private:
const Bar& bar_;

View File

@ -47,7 +47,6 @@ class Backlight : public ALabel {
template <class ForwardIt, class Inserter>
static void enumerate_devices(ForwardIt first, ForwardIt last, Inserter inserter, udev *udev);
const std::string name_;
const std::string preferred_device_;
static constexpr int EPOLL_MAX_EVENTS = 16;
@ -57,6 +56,6 @@ class Backlight : public ALabel {
std::mutex udev_thread_mutex_;
std::vector<BacklightDev> devices_;
// thread must destruct before shared data
waybar::util::SleeperThread udev_thread_;
util::SleeperThread udev_thread_;
};
} // namespace waybar::modules

View File

@ -31,19 +31,20 @@ class Battery : public ALabel {
private:
static inline const fs::path data_dir_ = "/sys/class/power_supply/";
void getBatteries();
void worker();
const std::string getAdapterStatus(uint8_t capacity) const;
void getBatteries();
void worker();
const std::string getAdapterStatus(uint8_t capacity) const;
const std::tuple<uint8_t, float, std::string> getInfos() const;
const std::string formatTimeRemaining(float hoursRemaining);
const std::string formatTimeRemaining(float hoursRemaining);
util::SleeperThread thread_;
util::SleeperThread thread_timer_;
std::vector<fs::path> batteries_;
fs::path adapter_;
int fd_;
std::vector<int> wds_;
std::string old_status_;
util::SleeperThread thread_;
util::SleeperThread thread_timer_;
};
} // namespace waybar::modules

View File

@ -1,8 +1,12 @@
#pragma once
#include <fmt/format.h>
#if FMT_VERSION < 60000
#include <fmt/time.h>
#else
#include <fmt/chrono.h>
#endif
#include "ALabel.hpp"
#include "fmt/time.h"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
@ -14,7 +18,7 @@ class Clock : public ALabel {
auto update() -> void;
private:
waybar::util::SleeperThread thread_;
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@ -2,12 +2,12 @@
#include <fmt/format.h>
#include <sys/sysinfo.h>
#include <fstream>
#include <cstdint>
#include <fstream>
#include <numeric>
#include <vector>
#include <string>
#include <utility>
#include <vector>
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
@ -26,7 +26,8 @@ class Cpu : public ALabel {
std::vector<std::tuple<size_t, size_t>> parseCpuinfo();
std::vector<std::tuple<size_t, size_t>> prev_times_;
waybar::util::SleeperThread thread_;
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@ -12,7 +12,7 @@ namespace waybar::modules {
class Custom : public ALabel {
public:
Custom(const std::string&, const Json::Value&);
Custom(const std::string&, const std::string&, const Json::Value&);
~Custom();
auto update() -> void;
void refresh(int /*signal*/);
@ -25,17 +25,18 @@ class Custom : public ALabel {
bool handleScroll(GdkEventScroll* e);
bool handleToggle(GdkEventButton* const& e);
const std::string name_;
std::string text_;
std::string alt_;
std::string tooltip_;
std::vector<std::string> class_;
int percentage_;
waybar::util::SleeperThread thread_;
waybar::util::command::res output_;
waybar::util::JsonParser parser_;
FILE* fp_;
int pid_;
const std::string name_;
std::string text_;
std::string alt_;
std::string tooltip_;
std::vector<std::string> class_;
int percentage_;
FILE* fp_;
int pid_;
util::command::res output_;
util::JsonParser parser_;
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@ -15,10 +15,12 @@ class Memory : public ALabel {
private:
static inline const std::string data_dir_ = "/proc/meminfo";
unsigned long memtotal_;
unsigned long memfree_;
void parseMeminfo();
waybar::util::SleeperThread thread_;
unsigned long memtotal_;
unsigned long memfree_;
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@ -27,48 +27,50 @@ class Network : public ALabel {
static int handleEvents(struct nl_msg*, void*);
static int handleScan(struct nl_msg*, void*);
void worker();
void createInfoSocket();
void createEventSocket();
int getExternalInterface(int skip_idx = -1);
void getInterfaceAddress();
int netlinkRequest(void*, uint32_t, uint32_t groups = 0);
int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
void parseEssid(struct nlattr**);
void parseSignal(struct nlattr**);
void parseFreq(struct nlattr**);
bool associatedOrJoined(struct nlattr**);
bool checkInterface(struct ifinfomsg *rtif, std::string name);
int getPreferredIface(int skip_idx = -1);
auto getInfo() -> void;
void clearIface();
bool wildcardMatch(const std::string& pattern, const std::string& text);
void worker();
void createInfoSocket();
void createEventSocket();
int getExternalInterface(int skip_idx = -1) const;
void getInterfaceAddress();
int netlinkRequest(void*, uint32_t, uint32_t groups = 0) const;
int netlinkResponse(void*, uint32_t, uint32_t groups = 0) const;
void parseEssid(struct nlattr**);
void parseSignal(struct nlattr**);
void parseFreq(struct nlattr**);
bool associatedOrJoined(struct nlattr**);
bool checkInterface(struct ifinfomsg* rtif, std::string name);
int getPreferredIface(int skip_idx = -1) const;
auto getInfo() -> void;
void checkNewInterface(struct ifinfomsg* rtif);
const std::string getNetworkState() const;
void clearIface();
bool wildcardMatch(const std::string& pattern, const std::string& text) const;
waybar::util::SleeperThread thread_;
waybar::util::SleeperThread thread_timer_;
int ifid_;
int last_ext_iface_;
sa_family_t family_;
struct sockaddr_nl nladdr_ = {0};
struct nl_sock* sock_ = nullptr;
struct nl_sock* ev_sock_ = nullptr;
int efd_;
int ev_fd_;
int nl80211_id_;
std::mutex mutex_;
int ifid_;
sa_family_t family_;
struct sockaddr_nl nladdr_ = {0};
struct nl_sock* sock_ = nullptr;
struct nl_sock* ev_sock_ = nullptr;
int efd_;
int ev_fd_;
int nl80211_id_;
std::mutex mutex_;
unsigned long long bandwidth_down_total_;
unsigned long long bandwidth_up_total_;
std::string state_;
std::string essid_;
std::string ifname_;
std::string ipaddr_;
std::string netmask_;
int cidr_;
bool linked_;
int32_t signal_strength_dbm_;
uint8_t signal_strength_;
uint32_t frequency_;
util::SleeperThread thread_;
util::SleeperThread thread_timer_;
};
} // namespace waybar::modules

View File

@ -21,14 +21,13 @@ class Pulseaudio : public ALabel {
static void sourceInfoCb(pa_context*, const pa_source_info* i, int, void* data);
static void serverInfoCb(pa_context*, const pa_server_info*, void*);
static void volumeModifyCb(pa_context*, int, void*);
bool handleVolume(GdkEventScroll* e);
bool handleScroll(GdkEventScroll* e);
const std::string getPortIcon() const;
pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_;
pa_context* context_;
bool scrolling_;
// SINK
uint32_t sink_idx_{0};
uint16_t volume_;

View File

@ -46,7 +46,12 @@ class Item : public sigc::trackable {
std::string menu;
DbusmenuGtkMenu* dbus_menu = nullptr;
Gtk::Menu* gtk_menu = nullptr;
bool item_is_menu = false;
/**
* ItemIsMenu flag means that the item only supports the context menu.
* Default value is true because libappindicator supports neither ItemIsMenu nor Activate method
* while compliant SNI implementation would always reset the flag to desired value.
*/
bool item_is_menu = true;
private:
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
@ -60,7 +65,7 @@ class Item : public sigc::trackable {
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
void makeMenu(GdkEventButton* const& ev);
void makeMenu();
bool handleClick(GdkEventButton* const& /*ev*/);
Glib::RefPtr<Gio::DBus::Proxy> proxy_;

View File

@ -1,7 +1,7 @@
#pragma once
#include <fmt/format.h>
#include "IModule.hpp"
#include "AModule.hpp"
#include "bar.hpp"
#include "modules/sni/host.hpp"
#include "modules/sni/watcher.hpp"
@ -9,19 +9,17 @@
namespace waybar::modules::SNI {
class Tray : public IModule {
class Tray : public AModule {
public:
Tray(const std::string&, const Bar&, const Json::Value&);
~Tray() = default;
auto update() -> void;
operator Gtk::Widget&();
private:
void onAdd(std::unique_ptr<Item>& item);
void onRemove(std::unique_ptr<Item>& item);
static inline std::size_t nb_hosts_ = 0;
const Json::Value& config_;
Gtk::Box box_;
SNI::Watcher watcher_;
SNI::Host host_;

View File

@ -5,7 +5,6 @@
#include <sys/un.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <memory>
#include <mutex>
#include "ipc.hpp"

View File

@ -5,8 +5,8 @@
#include "bar.hpp"
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/sleeper_thread.hpp"
#include "util/json.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@ -20,10 +20,12 @@ class Mode : public ALabel, public sigc::trackable {
void onEvent(const struct Ipc::ipc_response&);
void worker();
waybar::util::SleeperThread thread_;
Ipc ipc_;
std::string mode_;
std::string mode_;
util::JsonParser parser_;
std::mutex mutex_;
util::SleeperThread thread_;
Ipc ipc_;
};
} // namespace waybar::modules::sway

View File

@ -21,17 +21,21 @@ class Window : public ALabel, public sigc::trackable {
void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&);
void worker();
std::tuple<std::size_t, int, std::string, std::string> getFocusedNode(const Json::Value& nodes);
std::tuple<std::size_t, int, std::string, std::string> getFocusedNode(const Json::Value& nodes,
std::string& output);
void getTree();
const Bar& bar_;
waybar::util::SleeperThread thread_;
Ipc ipc_;
std::mutex mutex_;
std::string window_;
int windowId_;
std::string app_id_;
util::JsonParser parser_;
const Bar& bar_;
std::string window_;
int windowId_;
std::string app_id_;
std::string old_app_id_;
std::size_t app_nb_;
util::JsonParser parser_;
std::mutex mutex_;
util::SleeperThread thread_;
Ipc ipc_;
};
} // namespace waybar::modules::sway

View File

@ -3,7 +3,7 @@
#include <fmt/format.h>
#include <gtkmm/button.h>
#include <gtkmm/label.h>
#include "IModule.hpp"
#include "AModule.hpp"
#include "bar.hpp"
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
@ -12,12 +12,11 @@
namespace waybar::modules::sway {
class Workspaces : public IModule, public sigc::trackable {
class Workspaces : public AModule, public sigc::trackable {
public:
Workspaces(const std::string&, const waybar::Bar&, const Json::Value&);
~Workspaces() = default;
auto update() -> void;
operator Gtk::Widget&();
private:
void onCmd(const struct Ipc::ipc_response&);
@ -33,16 +32,15 @@ class Workspaces : public IModule, public sigc::trackable {
bool handleScroll(GdkEventScroll*);
const Bar& bar_;
const Json::Value& config_;
std::vector<Json::Value> workspaces_;
std::vector<std::string> workspaces_order_;
waybar::util::SleeperThread thread_;
std::mutex mutex_;
Gtk::Box box_;
Ipc ipc_;
util::JsonParser parser_;
bool scrolling_;
std::unordered_map<std::string, Gtk::Button> buttons_;
std::mutex mutex_;
util::SleeperThread thread_;
Ipc ipc_;
};
} // namespace waybar::modules::sway

View File

@ -17,8 +17,8 @@ class Temperature : public ALabel {
std::tuple<uint16_t, uint16_t> getTemperature();
bool isCritical(uint16_t);
std::string file_path_;
waybar::util::SleeperThread thread_;
std::string file_path_;
util::SleeperThread thread_;
};
} // namespace waybar::modules

View File

@ -33,7 +33,7 @@ inline int close(FILE* fp, pid_t pid) {
fclose(fp);
while (waitpid(pid, &stat, 0) == -1) {
if (errno != EINTR) {
stat = -1;
stat = 0;
break;
}
}
@ -90,6 +90,8 @@ inline int32_t forkExec(std::string cmd) {
setpgid(pid, pid);
execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0);
exit(0);
} else {
signal(SIGCHLD,SIG_IGN);
}
return pid;

View File

@ -14,7 +14,10 @@ class SleeperThread {
SleeperThread(std::function<void()> func)
: thread_{[this, func] {
while (do_run_) func();
while (do_run_) {
signal_ = false;
func();
}
}} {}
SleeperThread& operator=(std::function<void()> func) {
@ -42,7 +45,10 @@ class SleeperThread {
}
auto wake_up() {
signal_ = true;
{
std::lock_guard<std::mutex> lck(mutex_);
signal_ = true;
}
condvar_.notify_all();
}

View File

@ -0,0 +1,67 @@
waybar-backlight(5)
# NAME
waybar - backlight module
# DESCRIPTION
The *backlight* module displays the current backlight level.
# CONFIGURATION
*interval* ++
typeof: integer ++
default: 2 ++
The interval in which information gets polled.
*format* ++
typeof: string ++
default: {percent}% ++
The format, how information should be displayed. On {} data gets inserted.
*max-length* ++
typeof: integer ++
The maximum length in characters the module should display.
*rotate* ++
typeof: integer ++
Positive value to rotate the text label.
*states* ++
typeof: array ++
A number of backlight states which get activated on certain brightness levels.
*on-click* ++
typeof: string ++
Command to execute when the module is clicked.
*on-click-right* ++
typeof: string ++
Command to execute when the module is right clicked.
*on-scroll-up* ++
typeof: string ++
Command to execute when performing a scroll up on the module.
*on-scroll-down* ++
typeof: string
Command to execute when performing a scroll down on the module.
*smooth-scrolling-threshold* ++
typeof: double
Threshold to be used when scrolling.
# EXAMPLE:
```
"backlight": {
"device": "intel_backlight",
"format": "{percent}% {icon}",
"format-icons": ["", ""]
}
```
# STYLE
- *#backlight*

123
man/waybar-battery.5.scd Normal file
View File

@ -0,0 +1,123 @@
waybar-battery(5)
# NAME
waybar - battery module
# DESCRIPTION
The *battery* module displays the current capacity and state (eg. charging) of your battery.
# CONFIGURATION
*bat* ++
typeof: string ++
The battery to monitor, as in /sys/class/power_supply/ instead of auto detect.
*adapter* ++
typeof: string ++
The adapter to monitor, as in /sys/class/power_supply/ instead of auto detect.
*interval* ++
typeof: integer ++
default: 60 ++
The interval in which the information gets polled.
*states* ++
typeof: array ++
A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*.
*format* ++
typeof: string ++
default: {capacity}% ++
The format, how the time should be displayed.
*format-icons*
typeof: array/object
Based on the current capacity, the corresponding icon gets selected. ++
The order is *low* to *high*. Or by the state if it is an object.
*max-length* ++
typeof: integer++
The maximum length in character the module should display.
*rotate* ++
typeof: integer++
Positive value to rotate the text label.
*on-click* ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right* ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# FORMAT REPLACEMENTS
*{capacity}*: Capacity in percentage
*{icon}*: Icon, as defined in *format-icons*.
*{time}*: Estimate of time until full or empty. Note that this is based on the power draw at the last refresh time, not an average.
# CUSTOM FORMATS
The *battery* module allows to define custom formats based on up to two factors. The best fitting format will be selected.
*format-<state>*: With *states*, a custom format can be set depending on the capacity of your battery.
*format-<status>*: With the status, a custom format can be set depending on the status in /sys/class/power_supply/<bat>/status (in lowercase).
*format-<status>-<state>*: You can also set a custom format depending on both values.
# STATES
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. Each class gets activated when the current capacity is equal or below the configured *<value>*.
- Also each state can have its own *format*. Those con be configured via *format-<name>*. Or if you want to differentiate a bit more even as *format-<status>-<state>*. For more information see *custom-formats*.
# EXAMPLES
```
"battery": {
"bat": "BAT2",
"interval": 60,
"states": {
"warning": 30,
"critical": 15
},
"format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""],
"max-length": 25
}
```
# STYLE
- *#battery*
- *#battery.<status>*
- *<status>* is the value of /sys/class/power_supply/<bat>/status in lowercase.
- *#battery.<state>*
- *<state>* can be defined in the *config*. For more information see *states*.
- *#battery.<status>.<state>*
- Combination of both *<status>* and *<state>*.

65
man/waybar-clock.5.scd Normal file
View File

@ -0,0 +1,65 @@
waybar-clock(5)
# NAME
waybar - clock module
# DESCRIPTION
The *clock* module displays the current date and time.
# CONFIGURATION
*interval*: ++
typeof: integer ++
default: 60 ++
The interval in which the information gets polled.
*format*: ++
typeof: string ++
default: {:%H:%M} ++
The format, how the date and time should be displayed.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
View all valid format options in *strftime(3)*.
# EXAMPLES
```
"clock": {
"interval": 60,
"format": "{:%H:%M}",
"max-length": 25
}
```
# STYLE
- *#clock*

78
man/waybar-cpu.5.scd Normal file
View File

@ -0,0 +1,78 @@
waybar-cpu(5)
# NAME
waybar - cpu module
# DESCRIPTION
The *cpu* module displays the current cpu utilization.
# CONFIGURATION
*interval*: ++
typeof: integer ++
default: 10 ++
The interval in which the information gets polled.
*format*: ++
typeof: string ++
default: {usage}% ++
The format, how information should be displayed. On {} data gets inserted.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*states*: ++
typeof: array ++
A number of cpu usage states which get activated on certain usage levels. See *waybar-states(5)*.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# FORMAT REPLACEMENTS
*{load}*: Current cpu load.
*{usage}*: Current cpu usage.
# EXAMPLE
```
"cpu": {
"interval": 10,
"format": "{}% ",
"max-length": 10
}
```
# STYLE
- *#cpu*

190
man/waybar-custom.5.scd Normal file
View File

@ -0,0 +1,190 @@
waybar-custom(5)
# NAME
waybar - custom module
# DESCRIPTION
The *custom* module displays either the output of a script or static text.
To display static text, specify only the *format* field.
# CONFIGURATION
Addressed by *custom/<name>*
*exec*: ++
typeof: string ++
The path to the script, which should be executed.
*exec-if*: ++
typeof: string ++
The path to a script, which determines if the script in *exec* should be executed.
*exec* will be executed if the exit code of *exec-if* equals 0.
*return-type*: ++
typeof: string ++
See *return-type*
*interval*: ++
typeof: integer ++
The interval (in seconds) in which the information gets polled.
Use *once* if you want to execute the module only on startup.
You can update it manually with a signal. If no *interval* is defined,
it is assumed that the out script loops it self.
*signal*: ++
typeof: integer ++
The signal number used to update the module.
The number is valid between 1 and N, where *SIGRTMIN+N* = *SIGRTMAX*.
*format*: ++
typeof: string ++
default: {} ++
The format, how information should be displayed. On {} data gets inserted.
*format-icons*: ++
typeof: array ++
Based on the set percentage, the corresponding icon gets selected. The order is *low* to *high*.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
*escape*: ++
typeof: bool ++
default: false ++
Option to enable escaping of script output.
# RETURN-TYPE
When *return-type* is set to *json*, Waybar expects the *exec*-script to output its data in JSON format.
This should look like this:
```
{"text": "$text", "tooltip": "$tooltip", "class": "$class", "percentage": $percentage }
```
The *class* parameter also accepts an array of strings.
If nothing or an invalid option is specified, Waybar expects i3blocks style output. Values are *newline* separated.
This should look like this:
```
$text\\n$tooltip\\n$class*
```
*class* is a CSS class, to apply different styles in *style.css*
# FORMAT REPLACEMENTS
*{}*: Output of the script.
*{percentage}* Percentage which can be set via a json return-type.
*{icon}*: An icon from 'format-icons' according to percentage.
# EXAMPLES
## Spotify:
```
"custom/spotify": {
"format": " {}",
"max-length": 40,
"interval": 30, // Remove this if your script is endless and write in loop
"exec": "$HOME/.config/waybar/mediaplayer.sh 2> /dev/null", // Script in resources folder
"exec-if": "pgrep spotify"
}
```
## mpd:
```
"custom/mpd": {
"format": "♪ {}",
//"max-length": 15,
"interval": 10,
"exec": "mpc current",
"exec-if": "pgrep mpd",
"on-click": "mpc toggle",
"on-click-right": "sonata"
}
```
## cmus:
```
"custom/cmus": {
"format": "♪ {}",
//"max-length": 15,
"interval": 10,
"exec": "cmus-remote -C \"format_print '%a - %t'\"", // artist - title
"exec-if": "pgrep cmus",
"on-click": "cmus-remote -u", //toggle pause
"escape": true //handle markup entities
}
```
## Pacman
```
"custom/pacman": {
"format": "{} ",
"interval": "once",
"exec": "pacman_packages",
"on-click": "update-system",
"signal": 8
}
```
## Alternate Pacman
```
"custom/pacman": {
"format": "{} ",
"interval": 3600, // every hour
"exec": "checkupdates | wc -l", // # of updates
"exec-if": "exit 0", // always run; consider advanced run conditions
"on-click": "termite -e 'sudo pacman -Syu'; pkill -SIGRTMIN+8 waybar", // update system
"signal": 8
}
```
You can use the signal and update the number of available packages with *pkill -RTMIN+8 waybar*.
# STYLE
- *#custom-<name>*
- *#custom-<name>.<class>*
- *<class>* can be set by the script. For more information see *return-type*

View File

@ -0,0 +1,71 @@
waybar-idle-inhibitor(5)
# NAME
waybar - idle_inhibitor module
# DESCRIPTION
The *idle_inhibitor* module can inhibiting the idle behavior such as screen blanking, locking, and
screensaving, also known as "presentation mode".
# CONFIGURATION
*format*: ++
typeof: string ++
The format, how the state should be displayed.
*format-icons*: ++
typeof: array ++
Based on the current state, the corresponding icon gets selected.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module. A click also toggles the state
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# FORMAT REPLACEMENTS
*{status}*: status (*activated* or *deactivated*)
*{icon}*: Icon, as defined in *format-icons*
# EXAMPLES
```
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "",
"deactivated": ""
}
}
```

93
man/waybar-memory.5.scd Normal file
View File

@ -0,0 +1,93 @@
waybar-memory(5)
# NAME
waybar - memory module
# DESCRIPTION
The *memory* module displays the current date and time.
# CONFIGURATION
Addressed by *memory*
*interval*: ++
typeof: integer++
default: 30 ++
The interval in which the information gets polled.
*format*: ++
typeof: string ++
default: {percentage}% ++
The format, how information should be displayed.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*states*: ++
typeof: array ++
A number of memory utilization states which get activated on certain percentage thresholds. See *waybar-states(5)*.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# FORMAT REPLACEMENTS
*{percentage}*: Percentage of memory in use.
*{total}*: Amount of total memory available in GiB.
*{used}*: Amount of used memory in GiB.
*{avail}*: Amount of available memory in GiB.
# EXAMPLES
```
"memory": {
"interval": 30,
"format": "{}% ",
"max-length": 10
}
```
## FORMATTED MEMORY VALUES
```
"memory": {
"interval": 30,
"format": "{used:0.1f}G/{total:0.1f}G "
}
```
# STYLE
- *#memory*

200
man/waybar-mpd.5.scd Normal file
View File

@ -0,0 +1,200 @@
waybar-mpd(5)
# NAME
waybar - mpd module
# DESCRIPTION
The *mpd* module displays information about a running "Music Player Daemon" instance.
# CONFIGURATION
Addressed by *mpd*
*server*: ++
typeof: string ++
The network address or Unix socket path of the MPD server. If empty, connect to the default host.
*port*: ++
typeof: integer ++
The port MPD listens to. If empty, use the default port.
*interval*: ++
typeof: integer++
default: 5 ++
The interval in which the connection to the MPD server is retried
*timeout*: ++
typeof: integer++
default: 30 ++
The timeout for the connection. Change this if your MPD server has a low `connection_timeout` setting
*unknown-tag*: ++
typeof: string ++
default: "N/A" ++
The text to display when a tag is not present in the current song, but used in `format`
*format*: ++
typeof: string ++
default: "{album} - {artist} - {title}" ++
Information displayed when a song is playing or paused
*format-stopped*: ++
typeof: string ++
default: "stopped" ++
Information displayed when the player is stopped.
*format-disconnected*: ++
typeof: string ++
default: "disconnected" ++
Information displayed when the MPD server can't be reached.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
default: "MPD (connected)" ++
Tooltip information displayed when connected to MPD.
*tooltip-format-disconnected*: ++
typeof: string ++
default: "MPD (disconnected)" ++
Tooltip information displayed when the MPD server can't be reached.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
*state-icons*: ++
typeof: object ++
default: {} ++
Icon to show depending on the play/pause state of the player (*{ "playing": "...", "paused": "..." }*)
*consume-icons*: ++
typeof: object ++
default: {} ++
Icon to show depending on the "consume" option (*{ "on": "...", "off": "..." }*)
*random-icons*: ++
typeof: object ++
default: {} ++
Icon to show depending on the "random" option (*{ "on": "...", "off": "..." }*)
*repeat-icons*: ++
typeof: object ++
default: {} ++
Icon to show depending on the "repeat" option (*{ "on": "...", "off": "..." }*)
*single-icons*: ++
typeof: object ++
default: {} ++
Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*)
# FORMAT REPLACEMENTS
## WHEN PLAYING/PAUSED
*{artist}*: The artist of the current song
*{albumArtist}*: The artist of the current album
*{album}*: The album of the current song
*{title}*: The title of the current song
*{date}*: The date of the current song
*{elapsedTime}*: The current position of the current song. To format as a date/time (see example configuration)
*{totalTime}*: The length of the current song. To format as a date/time (see example configuration)
*{stateIcon}*: The icon corresponding the playing or paused status of the player (see *state-icons* option)
*{consumeIcon}*: The icon corresponding the "consume" option (see *consume-icons* option)
*{randomIcon}*: The icon corresponding the "random" option (see *random-icons* option)
*{repeatIcon}*: The icon corresponding the "repeat" option (see *repeat-icons* option)
*{singleIcon}*: The icon corresponding the "single" option (see *single-icons* option)
## WHEN STOPPED
*{consumeIcon}*: The icon corresponding the "consume" option (see *consume-icons* option)
*{randomIcon}*: The icon corresponding the "random" option (see *random-icons* option)
*{repeatIcon}*: The icon corresponding the "repeat" option (see *repeat-icons* option)
*{singleIcon}*: The icon corresponding the "single" option (see *single-icons* option)
## WHEN DISCONNECTED
Currently, no format replacements when disconnected.
# EXAMPLES
```
"mpd": {
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
"format-disconnected": "Disconnected ",
"format-stopped": "{consumeIcon}{randomIcon}{repeatIcon}{singleIcon}Stopped ",
"interval": 2,
"consume-icons": {
"on": " " // Icon shows only when "consume" is on
},
"random-icons": {
"off": "<span color=\"#f53c3c\"></span> ", // Icon grayed out when "random" is off
"on": " "
},
"repeat-icons": {
"on": " "
},
"single-icons": {
"on": "1 "
},
"state-icons": {
"paused": "",
"playing": ""
},
"tooltip-format": "MPD (connected)",
"tooltip-format-disconnected": "MPD (disconnected)"
}
```
# STYLE
- *#mpd*
- *#mpd.disconnected*
- *#mpd.stopped*
- *#mpd.playing*
- *#mpd.paused*

143
man/waybar-network.5.scd Normal file
View File

@ -0,0 +1,143 @@
waybar-network(5)
# NAME
waybar - network module
# DESCRIPTION
The *network* module displays information about the current network connections.
# CONFIGURATION
Addressed by *network*
*interface*: ++
typeof: string ++
Use the defined interface instead of auto detection. Accepts wildcard.
*interval*: ++
typeof: integer ++
default: 60 ++
The interval in which the network information gets polled (e.g. signal strength).
*format*: ++
typeof: string ++
default: *{ifname}* ++
The format, how information should be displayed. This format is used when other formats aren't specified.
*format-ethernet*: ++
typeof: string ++
This format is used when a ethernet interface is displayed.
*format-wifi*: ++
typeof: string ++
This format is used when a wireless interface is displayed.
*format-linked*: ++
typeof: string ++
This format is used when a linked interface with no ip address is displayed.
*format-disconnected*: ++
typeof: string ++
This format is used when the displayed interface is disconnected.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*on-scroll-up*: ++
typeof: string ++
Command to execute when scrolling up on the module.
*on-scroll-down*: ++
typeof: string ++
Command to execute when scrolling down on the module.
*smooth-scrolling-threshold*: ++
typeof: double ++
Threshold to be used when scrolling.
*tooltip*: ++
typeof: bool ++
default: *true* ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
The format, how information should be displayed in the tooltip. This format is used when other formats aren't specified.
*tooltip-format-ethernet*: ++
typeof: string ++
This format is used when a ethernet interface is displayed.
*tooltip-format-wifi*: ++
typeof: string ++
This format is used when a wireless interface is displayed.
*tooltip-format-disconnected*: ++
typeof: string ++
This format is used when the displayed interface is disconnected.
# FORMAT REPLACEMENTS
*{ifname}*: Name of the network interface.
*{ipaddr}*: The first IP of the interface.
*{netmask}*: The subnetmask corresponding to the IP.
*{cidr}*: The subnetmask corresponding to the IP in CIDR notation.
*{essid}*: Name (SSID) of the wireless network.
*{signalStrength}*: Signal strength of the wireless network.
*{signaldBm}*: Signal strength of the wireless network in dBm.
*{frequency}*: Frequency of the wireless network in MHz.
*{bandwidthUpBits}*: Instant up speed in bits/seconds.
*{bandwidthDownBits}*: Instant down speed in bits/seconds.
*{bandwidthUpOctets}*: Instant up speed in octets/seconds.
*{bandwidthDownOctets}*: Instant down speed in octets/seconds.
# EXAMPLES
```
"network": {
"interface": "wlp2s0",
"format": "{ifname}",
"format-wifi": "{essid} ({signalStrength}%) ",
"format-ethernet": "{ifname} ",
"format-disconnected": "", //An empty format will hide the module.
"tooltip-format": "{ifname}",
"tooltip-format-wifi": "{essid} ({signalStrength}%) ",
"tooltip-format-ethernet": "{ifname} ",
"tooltip-format-disconnected": "Disconnected",
"max-length": 50
}
```
# STYLE
- *#network*
- *#network.disconnected*
- *#network.linked*
- *#network.ethernet*
- *#network.wifi*

132
man/waybar-pulseaudio.5.scd Normal file
View File

@ -0,0 +1,132 @@
waybar-pulseaudio(5)
# NAME
waybar - pulseaudio module
# DESCRIPTION
The *pulseaudio* module displays the current volume reported by PulseAudio.
Additionally you can control the volume by scrolling *up* or *down* while the cursor is over the module.
# CONFIGURATION
*format*: ++
typeof: string ++
default: {volume}% ++
The format, how information should be displayed. This format is used when other formats aren't specified.
*format-bluetooth*: ++
typeof: string ++
This format is used when using bluetooth speakers.
*format-muted*: ++
typeof: string ++
This format is used when the sound is muted.
*format-source*: ++
typeof: string ++
default: {volume}% ++
This format used for the source.
*format-source-muted*: ++
typeof: string ++
This format is used when the source is muted.
*format-icons*: ++
typeof: array ++
Based on the current port-name and volume, the corresponding icon gets selected. The order is *low* to *high*. See [`Icons`](#module-pulseaudio-config-icons)
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*states*: ++
typeof: array ++
A number of volume states which get activated on certain volume levels. See *waybar-states(5)*
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*scroll-step*: ++
typeof: float ++
default: 1.0 ++
The speed in which to change the volume when scrolling.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
*smooth-scrolling-threshold*: ++
typeof: double ++
Threshold to be used when scrolling.
*tooltip*: ++
typeof: bool ++
default: true ++
Option to disable tooltip on hover.
# FORMAT REPLACEMENTS
*{volume}*: Volume in percentage.
*{icon}*: Icon, as defined in `format-icons`.
*{format_source}*: Source format, `format-source`, `format-source-muted`.
# ICONS:
The following strings for `format-icons` are supported.
If they are found in the current PulseAudio port name, the corresponding icons will be selected.
- *default* (Shown, when no other port is found)
- *headphones*
- *speaker*
- *hdmi*
- *headset*
- *handsfree*
- *portable*
- *car*
- *hifi*
- *phone*
# EXAMPLES
```
"pulseaudio": {
"format": "{volume}% {icon}",
"format-bluetooth": "{volume}% {icon}",
"format-muted": "",
"format-icons": {
"headphones": "",
"handsfree": "",
"headset": "",
"phone": "",
"portable": "",
"car": "",
"default": ["", ""]
},
"scroll-step": 1,
"on-click": "pavucontrol"
}
```
# STYLE
- *#pulseaudio*
- *#pulseaudio.bluetooth*
- *#pulseaudio.muted*

43
man/waybar-states.5.scd Normal file
View File

@ -0,0 +1,43 @@
waybar-states(5)
# OVERVIEW
Some modules support 'states' which allows percentage values to be used as styling triggers to
apply a class when the value matches the declared state value.
# STATES
- Every entry (*state*) consits of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state.
Each class gets activated when the current capacity is equal or below the configured *<value>*.
- Also each state can have its own *format*.
Those con be configured via *format-<name>*.
Or if you want to differentiate a bit more even as *format-<status>-<state>*.
# EXAMPLE
```
"battery": {
"bat": "BAT2",
"interval": 60,
"states": {
"warning": 30,
"critical": 15
},
"format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""],
"max-length": 25
}
```
# STYLING STATES
- *#battery.<state>*
- *<state>* can be defined in the *config*.
# EXAMPLE:
- *#battery.warning: { background: orange; }*
- *#battery.critical: { background: red; }*

View File

@ -0,0 +1,64 @@
waybar-sway-mode(5)
# NAME
waybar - sway mode module
# DESCRIPTION
The *mode* module displays the current binding mode of Sway
# CONFIGURATION
Addressed by *sway/mode*
*format*: ++
typeof: string ++
default: {} ++
The format, how information should be displayed. On {} data gets inserted.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# EXAMPLES
```
"sway/window": {
"format": " {}",
"max-length": 50
}
```
# STYLE
- *#mode*

View File

@ -0,0 +1,67 @@
waybar-sway-window(5)
# NAME
waybar - sway window module
# DESCRIPTION
The *window* module displays the title of the currently focused window in Sway
# CONFIGURATION
Addressed by *sway/window*
*format*: ++
typeof: string ++
default: {} ++
The format, how information should be displayed. On {} data gets inserted.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# EXAMPLES
```
"sway/window": {
"format": "{}",
"max-length": 50
}
```
# STYLE
- *#window*
- *window#waybar.empty* When no windows is in the workspace
- *window#waybar.solo* When one window is in the workspace
- *window#waybar.<app_id>* Where *app_id* is the app_id or *instance* name like (*chromium*) of the only window in the workspace

View File

@ -0,0 +1,123 @@
waybar-sway-workspaces(5)
# NAME
waybar - sway workspaces module
# DESCRIPTION
The *workspaces* module displays the currently used workspaces in Sway.
# CONFIGURATION
Addressed by *sway/workspaces*
*all-outputs*: ++
typeof: bool ++
default: false ++
If set to false, workspaces will only be shown on the output they are on. If set to true all workspaces will be shown on every output.
*format*: ++
typeof: string ++
default: {name} ++
The format, how information should be displayed.
*format-icons*: ++
typeof: array ++
Based on the workspace name and state, the corresponding icon gets selected. See *icons*.
*disable-scroll*: ++
typeof: bool ++
default: false ++
If set to false, you can scroll to cycle through workspaces. If set to true this behaviour is disabled.
*smooth-scrolling-threshold*: ++
typeof: double ++
Threshold to be used when scrolling.
*disable-scroll-wraparound*: ++
typeof: bool ++
default: false ++
If set to false, scrolling on the workspace indicator will wrap around to the first workspace when reading the end, and vice versa. If set to true this behavior is disabled.
*enable-bar-scroll*: ++
typeof: bool ++
default: false ++
If set to false, you can't scroll to cycle throughout workspaces from the entire bar. If set to true this behaviour is enabled.
*disable-markup*: ++
typeof: bool ++
default: false ++
If set to true, button label will escape pango markup.
*current-only*: ++
typeof: bool ++
default: false ++
If set to true. Only focused workspaces will be shown.
*persistent_workspaces*: ++
typeof: json (see below) ++
default: empty ++
Lists workspaces that should always be shown, even when non existent
# FORMAT REPLACEMENTS
*{name}*: Name of the workspace, as defined by sway.
*{icon}*: Icon, as defined in *format-icons*.
*{index}*: Index of the workspace.
# ICONS
Additional to workspace name matching, the following *format-icons* can be set.
- *default*: Will be shown, when no string matches is found.
- *urgent*: Will be shown, when workspace is flagged as urgent
- *focused*: Will be shown, when workspace is focused
# PERSISTANT WORKSPACES
Each entry of *persistant_workspace* names a workspace that should always be shown.
Associated with that value is a list of outputs indicating *where* the workspace should be shown,
an empty list denoting all outputs.
```
"sway/workspaces": {
"persistant_workspaces": {
"3": [], // Always show a workspace with name '3', on all outputs if it does not exists
"4": ["eDP-1"], // Always show a workspace with name '4', on output 'eDP-1' if it does not exists
"5": ["eDP-1", "DP-2"] // Always show a workspace with name '5', on outputs 'eDP-1' and 'DP-2' if it does not exists
}
}
```
n.b.: the list of outputs can be obtained from command line using *swaymsg -t get_outputs*
# EXAMPLES
```
"sway/workspaces": {
"disable-scroll": true,
"all-outputs": true,
"format": "{name}: {icon}",
"format-icons": {
"1": "",
"2": "",
"3": "",
"4": "",
"5": "",
"urgent": "",
"focused": "",
"default": ""
}
}
```
# Style
- *#workspaces button*
- *#workspaces button.visible*
- *#workspaces button.focused*
- *#workspaces button.urgent*
- *#workspaces button.persistant*

View File

@ -0,0 +1,99 @@
waybar-temperature(5)
# NAME
waybar - temperature module
# DESCRIPTION
The *temperature* module displays the current temperature from a thermal zone.
# CONFIGURATION
Addressed by *temperature*
*thermal-zone*: ++
typeof: integer ++
The thermal zone, as in */sys/class/thermal/*.
*hwmon-path*: ++
typeof: string ++
The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*.
*critical-threshold*: ++
typeof: integer ++
The threshold before it is considered critical (Celcius).
*interval*: ++
typeof: integer ++
default: 10 ++
The interval in which the information gets polled.
*format-critical*: ++
typeof: string ++
The format to use when temperature is considered critical
*format*: ++
typeof: string ++
default: {temperatureC}°C ++
The format (Celcius/Farenheit) in which the temperature should be displayed.
*format-icons*: ++
typeof: array ++
Based on the current temperature (Celcius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*max-length*: ++
typeof: integer ++
The maximum length in characters the module should display.
*on-click*: ++
typeof: string ++
Command to execute when you clicked on the module.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*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.
# FORMAT REPLACEMENTS
*{temperatureC}*: Temperature in Celcius.
*{temperatureF}*: Temperature in Fahrenheit.
# EXAMPLES
```
"temperature": {
// "thermal-zone": 2,
// "hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
// "critical-threshold": 80,
// "format-critical": "{temperatureC}°C ",
"format": "{temperatureC}°C "
}
```
# STYLE
- *#temperature*
- *#temperature.critical*

35
man/waybar-tray.5.scd Normal file
View File

@ -0,0 +1,35 @@
waybar-tray(5)
# NAME
waybar - tray module
# DESCRIPTION
_WARNING_ *tray* is still in beta. There may me bugs. Breaking changes may occur.
# CONFIGURATION
Addressed by *tray*
*icon-size*: ++
typeof: integer ++
Defines the size of the tray icons.
*spacing*: ++
typeof: integer ++
Defines the spacing between the tray icons.
# EXAMPLES
```
"tray": {
"icon-size": 21,
"spacing": 10
}
```
# STYLE
- *#tray*

193
man/waybar.5.scd Normal file
View File

@ -0,0 +1,193 @@
waybar(5)
# NAME
waybar - configuration file
# DESCRIPTION
The configuration uses the JSON file format and is named *config*.
Valid locations for this file are:
- *$XDG_CONFIG_HOME/waybar/config*
- *~/.config/waybar/config*
- *~/waybar/config*
- */etc/xdg/waybar/config*
A good starting point is the default configuration found at https://github.com/Alexays/Waybar/blob/master/resources/config.
Also a minimal example configuration can be found on the at the bottom of this man page.
# BAR CONFIGURATION
*layer* ++
typeof: string ++
default: bottom ++
Decide if the bar is displayed in front of the windows or behind them.
*output* ++
typeof: string|array ++
Specifies on which screen this bar will be displayed.
*position* ++
typeof: string ++
default: top ++
Bar position, can be *top*, *bottom*, *left*, *right*.
*height* ++
typeof: integer ++
Height to be used by the bar if possible. Leave blank for a dynamic value.
*width* ++
typeof: integer ++
Width to be used by the bar if possible. Leave blank for a dynamic value.
*modules-left* ++
typeof: array ++
Modules that will be displayed on the left.
*modules-center* ++
typeof: array ++
Modules that will be displayed in the center.
*modules-right* ++
typeof: array
Modules that will be displayed on the right.
*margin* ++
typeof: string ++
Margins value using the CSS format without units.
*margin-<top\|left\|bottom\|right>* ++
typeof: integer ++
Margins value without units.
*name* ++
typeof: string ++
Optional name added as a CSS class, for styling multiple waybars.
# MODULE FORMAT
You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat).
e.g.
```
"format": "<span style=\"italic\">{}</span>"
```
# MULTIPLE INSTANCES OF A MODULE
If you want to have a second instance of a module, you can suffix it by a '#' and a custom name.
For example if you want a second battery module, you can add *"battery#bat2"* to your modules.
To configure the newly added module, you then also add a module configuration with the same name.
This could then look something like this *(this is an incomplete example)*:
```
"modules-right": ["battery", "battery#bat2"],
"battery": {
"bat": "BAT1"
},
"battery#bat2": {
"bat": "BAT2"
}
```
# MINIMAL CONFIGURATION
A minimal *config* file could look like this:
```
{
"layer": "top",
"modules-left": ["sway/workspaces", "sway/mode"],
"modules-center": ["sway/window"],
"modules-right": ["battery", "clock"],
"sway/window": {
"max-length": 50
},
"battery": {
"format": "{capacity}% {icon}",
"format-icons": ["", "", "", "", ""]
},
"clock": {
"format-alt": "{:%a, %d. %b %H:%M}"
}
}
```
# MULTI OUTPUT CONFIGURATION
## Limit a configuration to some outputs
```
{
"layer": "top",
"output": "eDP-1",
"modules-left": ["sway/workspaces", "sway/mode"],
...
}
```
```
{
"layer": "top",
"output": ["eDP-1", "VGA"],
"modules-left": ["sway/workspaces", "sway/mode"],
...
}
```
## Configuration of multiple outputs
Don't specify an output to create multiple bars on the same screen.
```
[{
"layer": "top",
"output": "eDP-1",
"modules-left": ["sway/workspaces", "sway/mode"],
...
}, {
"layer": "top",
"output": "VGA",
"modules-right": ["clock"],
...
}]
```
## Rotating modules
When positioning Waybar on the left or right side of the screen, sometimes it's useful to be able to rotate the contents of a module so the text runs vertically. This can be done using the "rotate" property of the module. Example:
```
{
"clock": {
"rotate": 90
}
}
```
Valid options for the "rotate" property are: 0, 90, 180 and 270.
# SUPPORTED MODULES
- *waybar-backlight(5)*
- *waybar-battery(5)*
- *waybar-clock(5)*
- *waybar-cpu(5)*
- *waybar-custom(5)*
- *waybar-idle-inhibitor(5)*
- *waybar-memory(5)*
- *waybar-mdp(5)*
- *waybar-network(5)*
- *waybar-pulseaudio(5)*
- *waybar-sway-mode(5)*
- *waybar-sway-window(5)*
- *waybar-sway-workspaces(5)*
- *waybar-temperature(5)*
- *waybar-tray(5)*

View File

@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
version: '0.6.6',
version: '0.8.0',
license: 'MIT',
default_options : [
'cpp_std=c++17',
@ -65,13 +65,14 @@ libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
src_files = files(
'src/factory.cpp',
'src/AModule.cpp',
'src/ALabel.cpp',
'src/modules/memory.cpp',
'src/modules/battery.cpp',
'src/modules/clock.cpp',
'src/modules/custom.cpp',
'src/modules/cpu.cpp',
'src/modules/idle_inhibitor.cpp',
'src/modules/idle_inhibitor.cpp',
'src/modules/temperature.cpp',
'src/main.cpp',
'src/bar.cpp',
@ -152,6 +153,50 @@ install_data(
install_dir: join_paths(get_option('out'), 'etc/xdg/waybar')
)
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: false)
if scdoc.found()
scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true)
sh = find_program('sh', native: true)
mandir = get_option('mandir')
man_files = [
'waybar.5.scd',
'waybar-backlight.5.scd',
'waybar-battery.5.scd',
'waybar-clock.5.scd',
'waybar-cpu.5.scd',
'waybar-custom.5.scd',
'waybar-idle-inhibitor.5.scd',
'waybar-memory.5.scd',
'waybar-mpd.5.scd',
'waybar-network.5.scd',
'waybar-pulseaudio.5.scd',
'waybar-sway-mode.5.scd',
'waybar-sway-window.5.scd',
'waybar-sway-workspaces.5.scd',
'waybar-temperature.5.scd',
'waybar-tray.5.scd',
'waybar-states.5.scd',
]
foreach filename : man_files
topic = filename.split('.')[-3].split('/')[-1]
section = filename.split('.')[-2]
output = '@0@.@1@'.format(topic, section)
custom_target(
output,
input: 'man/@0@'.format(filename),
output: output,
command: [
sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output)
],
install: true,
install_dir: '@0@/man@1@'.format(mandir, section)
)
endforeach
endif
clangtidy = find_program('clang-tidy', required: false)
if clangtidy.found()

View File

@ -116,6 +116,7 @@
// "scroll-step": 1, // %, can be a float
"format": "{volume}% {icon} {format_source}",
"format-bluetooth": "{volume}% {icon} {format_source}",
"format-bluetooth-muted": " {icon} {format_source}",
"format-muted": " {format_source}",
"format-source": "{volume}% ",
"format-source-muted": "",
@ -140,5 +141,6 @@
},
"escape": true,
"exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
// "exec": "$HOME/.config/waybar/mediaplayer.py --player spotify 2> /dev/null" // Filter player based on name
}
}

View File

@ -39,13 +39,13 @@ def on_metadata(player, metadata, manager):
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
title=player.get_title())
if player.props.status != 'Playing':
if player.props.status != 'Playing' and track_info:
track_info = '' + track_info
write_output(track_info, player)
def on_player_appeared(manager, player, selected_player=None):
if player is not None and player.name == selected_player:
if player is not None and (selected_player is None or player.name == selected_player):
init_player(manager, player)
else:
logger.debug("New player appeared, but it's not the selected player, skipping")

View File

@ -7,10 +7,10 @@
}
window#waybar {
background: rgba(43, 48, 59, 0.5);
background-color: rgba(43, 48, 59, 0.5);
border-bottom: 3px solid rgba(100, 114, 125, 0.5);
color: #ffffff;
transition-property: background, background-color;
transition-property: background-color;
transition-duration: .5s;
}
@ -20,10 +20,10 @@ window#waybar.hidden {
/*
window#waybar.empty {
background: transparent;
background-color: transparent;
}
window#waybar.solo {
background: #FFFFFF;
background-color: #FFFFFF;
}
*/
@ -36,16 +36,22 @@ window#waybar.chromium {
border: none;
}
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
#workspaces button {
padding: 0 5px;
background: transparent;
background-color: transparent;
color: #ffffff;
border-bottom: 3px solid transparent;
}
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
#workspaces button:hover {
background: rgba(0, 0, 0, 0.2);
box-shadow: inherit;
border-bottom: 3px solid #ffffff;
}
#workspaces button.focused {
background: #64727D;
background-color: #64727D;
border-bottom: 3px solid #ffffff;
}
@ -54,13 +60,24 @@ window#waybar.chromium {
}
#mode {
background: #64727D;
background-color: #64727D;
border-bottom: 3px solid #ffffff;
}
#clock, #battery, #cpu, #memory, #temperature, #backlight, #network, #pulseaudio, #custom-media, #tray, #mode, #idle_inhibitor {
#clock,
#battery,
#cpu,
#memory,
#temperature,
#backlight,
#network,
#pulseaudio,
#custom-media,
#tray,
#mode,
#idle_inhibitor {
padding: 0 10px;
margin: 0 5px;
margin: 0 4px;
color: #ffffff;
}
@ -86,7 +103,7 @@ window#waybar.chromium {
}
#battery.critical:not(.charging) {
background: #f53c3c;
background-color: #f53c3c;
color: #ffffff;
animation-name: blink;
animation-duration: 0.5s;
@ -100,56 +117,56 @@ label:focus {
}
#cpu {
background: #2ecc71;
background-color: #2ecc71;
color: #000000;
}
#memory {
background: #9b59b6;
background-color: #9b59b6;
}
#backlight {
background: #90b1b1;
background-color: #90b1b1;
}
#network {
background: #2980b9;
background-color: #2980b9;
}
#network.disconnected {
background: #f53c3c;
background-color: #f53c3c;
}
#pulseaudio {
background: #f1c40f;
background-color: #f1c40f;
color: #000000;
}
#pulseaudio.muted {
background: #90b1b1;
background-color: #90b1b1;
color: #2a5c45;
}
#custom-media {
background: #66cc99;
background-color: #66cc99;
color: #2a5c45;
min-width: 100px;
}
.custom-spotify {
background: #66cc99;
#custom-media.custom-spotify {
background-color: #66cc99;
}
.custom-vlc {
background: #ffa000;
#custom-media.custom-vlc {
background-color: #ffa000;
}
#temperature {
background: #f0932b;
background-color: #f0932b;
}
#temperature.critical {
background: #eb4d4b;
background-color: #eb4d4b;
}
#tray {
@ -166,18 +183,18 @@ label:focus {
}
#mpd {
background: #66cc99;
background-color: #66cc99;
color: #2a5c45;
}
#mpd.disconnected {
background: #f53c3c;
background-color: #f53c3c;
}
#mpd.stopped {
background: #90b1b1;
background-color: #90b1b1;
}
#mpd.paused {
background: #51a37a;
background-color: #51a37a;
}

View File

@ -2,114 +2,39 @@
#include <fmt/format.h>
#include <util/command.hpp>
waybar::ALabel::ALabel(const Json::Value& config, const std::string& format, uint16_t interval)
: config_(config),
namespace waybar {
ALabel::ALabel(const Json::Value& config, const std::string& name, const std::string& id,
const std::string& format, uint16_t interval, bool ellipsize)
: AModule(config, name, id, config["format-alt"].isString()),
format_(config_["format"].isString() ? config_["format"].asString() : format),
interval_(config_["interval"] == "once"
? std::chrono::seconds(100000000)
: std::chrono::seconds(
config_["interval"].isUInt() ? config_["interval"].asUInt() : interval)),
default_format_(format_) {
label_.set_name(name);
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
event_box_.add(label_);
if (config_["max-length"].isUInt()) {
label_.set_max_width_chars(config_["max-length"].asUInt());
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
} else if (ellipsize && label_.get_max_width_chars() == -1) {
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
}
if (config_["rotate"].isUInt()) {
label_.set_angle(config["rotate"].asUInt());
}
if (config_["format-alt"].isString()) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &ALabel::handleToggle));
}
// configure events' user commands
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
config_["on-click-right"].isString()) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &ALabel::handleToggle));
}
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &ALabel::handleScroll));
}
}
waybar::ALabel::~ALabel() {
for (const auto& pid : pid_) {
if (pid != -1) {
kill(-pid, 9);
}
}
}
auto waybar::ALabel::update() -> void {
auto ALabel::update() -> void {
// Nothing here
}
bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
std::string format;
if (config_["on-click"].isString() && e->button == 1) {
format = config_["on-click"].asString();
} else if (config_["on-click-middle"].isString() && e->button == 2) {
format = config_["on-click-middle"].asString();
} else if (config_["on-click-right"].isString() && e->button == 3) {
format = config_["on-click-right"].asString();
} else if (config_["on-click-forward"].isString() && e->button == 8) {
format = config_["on-click-backward"].asString();
} else if (config_["on-click-backward"].isString() && e->button == 9) {
format = config_["on-click-forward"].asString();
}
if (!format.empty()) {
pid_.push_back(
waybar::util::command::forkExec(fmt::format(format, fmt::arg("arg", click_param))));
}
if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) {
alt_ = !alt_;
if (alt_ && config_["format-alt"].isString()) {
format_ = config_["format-alt"].asString();
} else {
format_ = default_format_;
}
}
dp.emit();
return true;
}
bool waybar::ALabel::handleScroll(GdkEventScroll* e) {
// Avoid concurrent scroll event
std::lock_guard<std::mutex> lock(mutex_);
bool direction_up = false;
if (e->direction == GDK_SCROLL_UP) {
direction_up = true;
}
if (e->direction == GDK_SCROLL_DOWN) {
direction_up = false;
}
if (e->direction == GDK_SCROLL_SMOOTH) {
gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent*>(e), &delta_x, &delta_y);
if (delta_y < 0) {
direction_up = true;
} else if (delta_y > 0) {
direction_up = false;
}
}
if (direction_up && config_["on-scroll-up"].isString()) {
pid_.push_back(waybar::util::command::forkExec(config_["on-scroll-up"].asString()));
} else if (config_["on-scroll-down"].isString()) {
pid_.push_back(waybar::util::command::forkExec(config_["on-scroll-down"].asString()));
}
dp.emit();
return true;
}
std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
auto format_icons = config_["format-icons"];
if (format_icons.isObject()) {
if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) {
@ -129,7 +54,19 @@ std::string waybar::ALabel::getIcon(uint16_t percentage, const std::string& alt,
return "";
}
std::string waybar::ALabel::getState(uint8_t value, bool lesser) {
bool waybar::ALabel::handleToggle(GdkEventButton* const& e) {
if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) {
alt_ = !alt_;
if (alt_ && config_["format-alt"].isString()) {
format_ = config_["format-alt"].asString();
} else {
format_ = default_format_;
}
}
return AModule::handleToggle(e);
}
std::string ALabel::getState(uint8_t value, bool lesser) {
if (!config_["states"].isObject()) {
return "";
}
@ -158,8 +95,4 @@ std::string waybar::ALabel::getState(uint8_t value, bool lesser) {
return valid_state;
}
bool waybar::ALabel::tooltipEnabled() {
return config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true;
}
waybar::ALabel::operator Gtk::Widget&() { return event_box_; }
} // namespace waybar

119
src/AModule.cpp Normal file
View File

@ -0,0 +1,119 @@
#include "AModule.hpp"
#include <fmt/format.h>
#include <util/command.hpp>
namespace waybar {
AModule::AModule(const Json::Value& config, const std::string& name, const std::string& id,
bool enable_click, bool enable_scroll)
: config_(std::move(config)) {
// configure events' user commands
if (config_["on-click"].isString() || config_["on-click-middle"].isString() ||
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
config_["on-click-right"].isString() || enable_click) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &AModule::handleToggle));
}
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString() || enable_scroll) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &AModule::handleScroll));
}
}
AModule::~AModule() {
for (const auto& pid : pid_) {
if (pid != -1) {
kill(-pid, 9);
}
}
}
auto AModule::update() -> void {
// Nothing here
}
bool AModule::handleToggle(GdkEventButton* const& e) {
std::string format;
if (config_["on-click"].isString() && e->button == 1) {
format = config_["on-click"].asString();
} else if (config_["on-click-middle"].isString() && e->button == 2) {
format = config_["on-click-middle"].asString();
} else if (config_["on-click-right"].isString() && e->button == 3) {
format = config_["on-click-right"].asString();
} else if (config_["on-click-forward"].isString() && e->button == 8) {
format = config_["on-click-backward"].asString();
} else if (config_["on-click-backward"].isString() && e->button == 9) {
format = config_["on-click-forward"].asString();
}
if (!format.empty()) {
pid_.push_back(util::command::forkExec(fmt::format(format, fmt::arg("arg", click_param_))));
}
dp.emit();
return true;
}
AModule::SCROLL_DIR AModule::getScrollDir(GdkEventScroll* e) {
switch (e -> direction) {
case GDK_SCROLL_UP: return SCROLL_DIR::UP;
case GDK_SCROLL_DOWN: return SCROLL_DIR::DOWN;
case GDK_SCROLL_LEFT: return SCROLL_DIR::LEFT;
case GDK_SCROLL_RIGHT: return SCROLL_DIR::RIGHT;
case GDK_SCROLL_SMOOTH: {
SCROLL_DIR dir{SCROLL_DIR::NONE};
distance_scrolled_y_ += e->delta_y;
distance_scrolled_x_ += e->delta_x;
gdouble threshold = 0;
if (config_["smooth-scrolling-threshold"].isNumeric()) {
threshold = config_["smooth-scrolling-threshold"].asDouble();
}
if (distance_scrolled_y_ < -threshold) {
dir = SCROLL_DIR::UP;
} else if (distance_scrolled_y_ > threshold) {
dir = SCROLL_DIR::DOWN;
} else if (distance_scrolled_x_ > threshold) {
dir = SCROLL_DIR::RIGHT;
} else if (distance_scrolled_x_ < -threshold) {
dir = SCROLL_DIR::LEFT;
}
switch (dir) {
case SCROLL_DIR::UP:
case SCROLL_DIR::DOWN:
distance_scrolled_y_ = 0;
break;
case SCROLL_DIR::LEFT:
case SCROLL_DIR::RIGHT:
distance_scrolled_x_ = 0;
break;
case SCROLL_DIR::NONE:
break;
}
return dir;
}
// Silence -Wreturn-type:
default: return SCROLL_DIR::NONE;
}
}
bool AModule::handleScroll(GdkEventScroll* e) {
auto dir = getScrollDir(e);
if (dir == SCROLL_DIR::UP && config_["on-scroll-up"].isString()) {
pid_.push_back(util::command::forkExec(config_["on-scroll-up"].asString()));
} else if (dir == SCROLL_DIR::DOWN && config_["on-scroll-down"].isString()) {
pid_.push_back(util::command::forkExec(config_["on-scroll-down"].asString()));
}
dp.emit();
return true;
}
bool AModule::tooltipEnabled() {
return config_["tooltip"].isBool() ? config_["tooltip"].asBool() : true;
}
AModule::operator Gtk::Widget&() { return event_box_; }
} // namespace waybar

View File

@ -1,7 +1,7 @@
#include "bar.hpp"
#include <spdlog/spdlog.h>
#include "client.hpp"
#include "factory.hpp"
#include <spdlog/spdlog.h>
waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
: output(w_output),
@ -9,6 +9,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
window{Gtk::WindowType::WINDOW_TOPLEVEL},
surface(nullptr),
layer_surface(nullptr),
anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP),
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
right_(Gtk::ORIENTATION_HORIZONTAL, 0),
@ -16,46 +17,35 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
window.set_title("waybar");
window.set_name("waybar");
window.set_decorated(false);
window.get_style_context()->add_class(output->name);
window.get_style_context()->add_class(config["name"].asString());
window.get_style_context()->add_class(config["position"].asString());
if (config["position"] == "right" || config["position"] == "left") {
height_ = 0;
width_ = 1;
}
height_ = config["height"].isUInt() ? config["height"].asUInt() : height_;
width_ = config["width"].isUInt() ? config["width"].asUInt() : width_;
auto gtk_window = window.gobj();
auto gtk_widget = GTK_WIDGET(gtk_window);
gtk_widget_realize(gtk_widget);
auto gdk_window = window.get_window()->gobj();
gdk_wayland_window_set_use_custom_surface(gdk_window);
surface = gdk_wayland_window_get_wl_surface(gdk_window);
window.signal_realize().connect_notify(sigc::mem_fun(*this, &Bar::onRealize));
window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap));
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
window.set_size_request(width_, height_);
std::size_t layer =
config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
auto client = waybar::Client::inst();
layer_surface = zwlr_layer_shell_v1_get_layer_surface(
client->layer_shell, surface, output->output, layer, "waybar");
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layerSurfaceHandleConfigure,
.closed = layerSurfaceHandleClosed,
};
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
auto height = config["height"].isUInt() ? config["height"].asUInt() : height_;
auto width = config["width"].isUInt() ? config["width"].asUInt() : width_;
std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
if (config["position"] == "bottom") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else if (config["position"] == "left") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT;
} else if (config["position"] == "right") {
anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
}
if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM || anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
} else if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ||
anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
if (anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ||
anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
anchor_ |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
} else if (anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ||
anchor_ == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
anchor_ |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
right_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0);
@ -63,17 +53,71 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
vertical = true;
}
zwlr_layer_surface_v1_set_anchor(layer_surface, anchor);
zwlr_layer_surface_v1_set_size(layer_surface, width, height);
setMarginsAndZone(height, width);
setupWidgets();
if (window.get_realized()) {
onRealize();
}
window.show_all();
}
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
auto tmp_height = height_;
auto tmp_width = width_;
if (ev->height > static_cast<int>(height_)) {
// Default minimal value
if (height_ != 1) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
if (config["height"].isUInt()) {
spdlog::info(SIZE_DEFINED, "Height");
} else {
tmp_height = ev->height;
}
}
if (ev->width > static_cast<int>(width_)) {
// Default minimal value
if (width_ != 1) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
if (config["width"].isUInt()) {
spdlog::info(SIZE_DEFINED, "Width");
} else {
tmp_width = ev->width;
}
}
if (tmp_width != width_ || tmp_height != height_) {
zwlr_layer_surface_v1_set_size(layer_surface, tmp_width, tmp_height);
}
}
void waybar::Bar::onRealize() {
auto gdk_window = window.get_window()->gobj();
gdk_wayland_window_set_use_custom_surface(gdk_window);
}
void waybar::Bar::onMap(GdkEventAny* ev) {
auto gdk_window = window.get_window()->gobj();
surface = gdk_wayland_window_get_wl_surface(gdk_window);
auto client = waybar::Client::inst();
auto layer =
config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
layer_surface = zwlr_layer_shell_v1_get_layer_surface(
client->layer_shell, surface, output->output, layer, "waybar");
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, false);
zwlr_layer_surface_v1_set_anchor(layer_surface, anchor_);
zwlr_layer_surface_v1_set_size(layer_surface, width_, height_);
setMarginsAndZone(height_, width_);
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.configure = layerSurfaceHandleConfigure,
.closed = layerSurfaceHandleClosed,
};
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
wl_surface_commit(surface);
wl_display_roundtrip(client->wl_display);
setupWidgets();
window.set_size_request(width_, height_);
window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure));
}
void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {
@ -127,36 +171,6 @@ void waybar::Bar::setMarginsAndZone(uint32_t height, uint32_t width) {
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone);
}
void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
auto tmp_height = height_;
auto tmp_width = width_;
if (ev->height > static_cast<int>(height_)) {
// Default minimal value
if (height_ != 1) {
spdlog::warn(MIN_HEIGHT_MSG, height_, ev->height);
}
if (config["height"].isUInt()) {
spdlog::info(SIZE_DEFINED, "Height");
} else {
tmp_height = ev->height;
}
}
if (ev->width > static_cast<int>(width_)) {
// Default minimal value
if (width_ != 1) {
spdlog::warn(MIN_WIDTH_MSG, width_, ev->width);
}
if (config["width"].isUInt()) {
spdlog::info(SIZE_DEFINED, "Width");
} else {
tmp_width = ev->width;
}
}
if (tmp_width != width_ || tmp_height != height_) {
zwlr_layer_surface_v1_set_size(layer_surface, tmp_width, tmp_height);
}
}
// Converting string to button code rn as to avoid doing it later
void waybar::Bar::setupAltFormatKeyForModule(const std::string& module_name) {
if (config.isMember(module_name)) {
@ -229,9 +243,9 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surf
auto zone = o->vertical ? width + o->margins_.right : height + o->margins_.bottom;
zwlr_layer_surface_v1_set_exclusive_zone(o->layer_surface, zone);
spdlog::info(BAR_SIZE_MSG,
o->width_ == 1 ? "auto" : std::to_string(o->width_),
o->height_ == 1 ? "auto" : std::to_string(o->height_),
o->output->name);
o->width_ == 1 ? "auto" : std::to_string(o->width_),
o->height_ == 1 ? "auto" : std::to_string(o->height_),
o->output->name);
wl_surface_commit(o->surface);
}
zwlr_layer_surface_v1_ack_configure(surface, serial);
@ -239,7 +253,10 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surf
void waybar::Bar::layerSurfaceHandleClosed(void* data, struct zwlr_layer_surface_v1* /*surface*/) {
auto o = static_cast<waybar::Bar*>(data);
zwlr_layer_surface_v1_destroy(o->layer_surface);
if (o->layer_surface) {
zwlr_layer_surface_v1_destroy(o->layer_surface);
o->layer_surface = nullptr;
}
o->modules_left_.clear();
o->modules_center_.clear();
o->modules_right_.clear();
@ -272,14 +289,11 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
modules_right_.emplace_back(module);
}
module->dp.connect([module, &name] {
// Fix https://github.com/Alexays/Waybar/issues/320, proper way?
Glib::signal_idle().connect_once([module, &name] {
try {
module->update();
} catch (const std::exception& e) {
spdlog::error("{}: {}", name.asString(), e.what());
}
});
try {
module->update();
} catch (const std::exception& e) {
spdlog::error("{}: {}", name.asString(), e.what());
}
});
} catch (const std::exception& e) {
spdlog::warn("module {}: {}", name.asString(), e.what());
@ -290,9 +304,9 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos) {
auto waybar::Bar::setupWidgets() -> void {
window.add(box_);
box_.pack_start(left_, true, true);
box_.pack_start(left_, false, false);
box_.set_center_widget(center_);
box_.pack_end(right_, true, true);
box_.pack_end(right_, false, false);
// Convert to button code for every module that is used.
setupAltFormatKeyForModuleList("modules-left");
@ -304,14 +318,13 @@ auto waybar::Bar::setupWidgets() -> void {
getModules(factory, "modules-center");
getModules(factory, "modules-right");
for (auto const& module : modules_left_) {
left_.pack_start(*module, false, true, 0);
left_.pack_start(*module, false, false);
}
for (auto const& module : modules_center_) {
center_.pack_start(*module, true, true, 0);
center_.pack_start(*module, false, false);
}
std::reverse(modules_right_.begin(), modules_right_.end());
for (auto const& module : modules_right_) {
right_.pack_end(*module, false, false, 0);
right_.pack_end(*module, false, false);
}
window.show_all();
}

View File

@ -1,7 +1,7 @@
#include "client.hpp"
#include <spdlog/spdlog.h>
#include <fstream>
#include <iostream>
#include <spdlog/spdlog.h>
#include "util/clara.hpp"
#include "util/json.hpp"
@ -10,7 +10,7 @@ waybar::Client *waybar::Client::inst() {
return c;
}
const std::string waybar::Client::getValidPath(const std::vector<std::string> &paths) {
const std::string waybar::Client::getValidPath(const std::vector<std::string> &paths) const {
wordexp_t p;
for (const std::string &path : paths) {
@ -65,8 +65,14 @@ void waybar::Client::handleGlobalRemove(void * data, struct wl_registry * /*re
client->outputs_.end(),
[&name](const auto &output) { return output->wl_name == name; });
if (it != client->outputs_.end()) {
zxdg_output_v1_destroy((*it)->xdg_output);
wl_output_destroy((*it)->output);
if ((*it)->xdg_output != nullptr) {
zxdg_output_v1_destroy((*it)->xdg_output);
(*it)->xdg_output = nullptr;
}
if ((*it)->output != nullptr) {
wl_output_destroy((*it)->output);
(*it)->output = nullptr;
}
client->outputs_.erase(it);
}
}
@ -151,8 +157,14 @@ void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_
output->name = name;
auto configs = client->getOutputConfigs(output);
if (configs.empty()) {
wl_output_destroy(output->output);
zxdg_output_v1_destroy(output->xdg_output);
if (output->output != nullptr) {
wl_output_destroy(output->output);
output->output = nullptr;
}
if (output->xdg_output != nullptr) {
zxdg_output_v1_destroy(output->xdg_output);
output->xdg_output = nullptr;
}
} else {
wl_display_roundtrip(client->wl_display);
for (const auto &config : configs) {
@ -172,31 +184,33 @@ void waybar::Client::handleDescription(void * /*data*/, struct zxdg_output_v1 *
// Nothing here
}
void waybar::Client::setupConfigs(const std::string &config, const std::string &style) {
config_file_ = config.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/config",
"$HOME/.config/waybar/config",
"$HOME/waybar/config",
"/etc/xdg/waybar/config",
"./resources/config",
std::tuple<const std::string, const std::string> waybar::Client::getConfigs(
const std::string &config, const std::string &style) const {
auto config_file = config.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/config",
"$HOME/.config/waybar/config",
"$HOME/waybar/config",
"/etc/xdg/waybar/config",
"./resources/config",
})
: config;
auto css_file = style.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/style.css",
"$HOME/.config/waybar/style.css",
"$HOME/waybar/style.css",
"/etc/xdg/waybar/style.css",
"./resources/style.css",
})
: config;
css_file_ = style.empty() ? getValidPath({
"$XDG_CONFIG_HOME/waybar/style.css",
"$HOME/.config/waybar/style.css",
"$HOME/waybar/style.css",
"/etc/xdg/waybar/style.css",
"./resources/style.css",
})
: style;
if (css_file_.empty() || config_file_.empty()) {
: style;
if (css_file.empty() || config_file.empty()) {
throw std::runtime_error("Missing required resources files");
}
spdlog::info("Resources files: {}, {}", config_file_, css_file_);
spdlog::info("Resources files: {}, {}", config_file, css_file);
return {config_file, css_file};
}
auto waybar::Client::setupConfig() -> void {
std::ifstream file(config_file_);
auto waybar::Client::setupConfig(const std::string &config_file) -> void {
std::ifstream file(config_file);
if (!file.is_open()) {
throw std::runtime_error("Can't open config file");
}
@ -205,12 +219,12 @@ auto waybar::Client::setupConfig() -> void {
config_ = parser.parse(str);
}
auto waybar::Client::setupCss() -> void {
auto waybar::Client::setupCss(const std::string &css_file) -> void {
css_provider_ = Gtk::CssProvider::create();
style_context_ = Gtk::StyleContext::create();
// Load our css file, wherever that may be hiding
if (!css_provider_->load_from_path(css_file_)) {
if (!css_provider_->load_from_path(css_file)) {
throw std::runtime_error("Can't open style file");
}
}
@ -229,15 +243,6 @@ void waybar::Client::bindInterfaces() {
}
int waybar::Client::main(int argc, char *argv[]) {
gtk_app = Gtk::Application::create(argc, argv, "fr.arouillard.waybar");
gdk_display = Gdk::Display::get_default();
if (!gdk_display) {
throw std::runtime_error("Can't find display");
}
if (!GDK_IS_WAYLAND_DISPLAY(gdk_display->gobj())) {
throw std::runtime_error("Bar need to run under Wayland");
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
bool show_help = false;
bool show_version = false;
std::string config;
@ -268,9 +273,18 @@ int waybar::Client::main(int argc, char *argv[]) {
if (!log_level.empty()) {
spdlog::set_level(spdlog::level::from_str(log_level));
}
setupConfigs(config, style);
setupConfig();
setupCss();
gtk_app = Gtk::Application::create(argc, argv, "fr.arouillard.waybar");
gdk_display = Gdk::Display::get_default();
if (!gdk_display) {
throw std::runtime_error("Can't find display");
}
if (!GDK_IS_WAYLAND_DISPLAY(gdk_display->gobj())) {
throw std::runtime_error("Bar need to run under Wayland");
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
auto [config_file, css_file] = getConfigs(config, style);
setupConfig(config_file);
setupCss(css_file);
bindInterfaces();
gtk_app->hold();
gtk_app->run();

View File

@ -2,7 +2,7 @@
waybar::Factory::Factory(const Bar& bar, const Json::Value& config) : bar_(bar), config_(config) {}
waybar::IModule* waybar::Factory::makeModule(const std::string& name) const {
waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
try {
auto hash_pos = name.find('#');
auto ref = name.substr(0, hash_pos);
@ -64,7 +64,7 @@ waybar::IModule* waybar::Factory::makeModule(const std::string& name) const {
return new waybar::modules::Temperature(id, config_[name]);
}
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
return new waybar::modules::Custom(ref.substr(7), config_[name]);
return new waybar::modules::Custom(ref.substr(7), id, config_[name]);
}
} catch (const std::exception& e) {
auto err = fmt::format("Disabling module \"{}\", {}", name, e.what());

View File

@ -88,12 +88,9 @@ int waybar::modules::Backlight::BacklightDev::get_max() const { return max_; }
void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; }
waybar::modules::Backlight::Backlight(const std::string &name, const Json::Value &config)
: ALabel(config, "{percent}%", 2),
name_(name),
waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config)
: ALabel(config, "backlight", id, "{percent}%", 2),
preferred_device_(config["device"].isString() ? config["device"].asString() : "") {
label_.set_name("backlight");
// Get initial state
{
std::unique_ptr<udev, UdevDeleter> udev_check{udev_new()};
@ -181,7 +178,7 @@ auto waybar::modules::Backlight::update() -> void {
const auto percent = best->get_max() == 0 ? 100 : best->get_actual() * 100 / best->get_max();
label_.set_markup(fmt::format(
format_, fmt::arg("percent", std::to_string(percent)), fmt::arg("icon", getIcon(percent))));
getState(percent);
getState(percent);
} else {
if (!previous_best_.has_value()) {
return;
@ -213,7 +210,8 @@ void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last,
const char *name = udev_device_get_sysname(dev);
check_nn(name);
const char *actual_brightness_attr = strcmp(name, "amdgpu_bl0") == 0 ? "brightness" : "actual_brightness";
const char *actual_brightness_attr =
strcmp(name, "amdgpu_bl0") == 0 ? "brightness" : "actual_brightness";
const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
check_nn(actual);

View File

@ -2,11 +2,7 @@
#include <spdlog/spdlog.h>
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
: ALabel(config, "{capacity}%", 60) {
label_.set_name("battery");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
: ALabel(config, "battery", id, "{capacity}%", 60) {
getBatteries();
fd_ = inotify_init1(IN_CLOEXEC);
if (fd_ == -1) {

View File

@ -1,20 +1,13 @@
#include "modules/clock.hpp"
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: ALabel(config, "{:%H:%M}", 60) {
label_.set_name("clock");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
: ALabel(config, "clock", id, "{:%H:%M}", 60) {
thread_ = [this] {
dp.emit();
auto now = std::chrono::system_clock::now();
auto timeout = std::chrono::floor<std::chrono::seconds>(now + interval_);
auto time_s = std::chrono::time_point_cast<std::chrono::seconds>(timeout);
auto sub_m =
std::chrono::duration_cast<std::chrono::seconds>(time_s.time_since_epoch()).count() %
interval_.count();
thread_.sleep_until(timeout - std::chrono::seconds(sub_m));
auto diff = std::chrono::seconds(timeout.time_since_epoch().count() % interval_.count());
thread_.sleep_until(timeout - diff);
};
}

View File

@ -2,11 +2,7 @@
#include <numeric>
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: ALabel(config, "{usage}%", 10) {
label_.set_name("cpu");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
: ALabel(config, "cpu", id, "{usage}%", 10) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);

View File

@ -1,9 +1,9 @@
#include "modules/custom.hpp"
#include <spdlog/spdlog.h>
waybar::modules::Custom::Custom(const std::string& name, const Json::Value& config)
: ALabel(config, "{}"), name_(name), fp_(nullptr), pid_(-1) {
label_.set_name("custom-" + name_);
waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
const Json::Value& config)
: ALabel(config, "custom-" + name, id, "{}"), name_(name), fp_(nullptr), pid_(-1) {
if (config_["exec"].isString()) {
if (interval_.count() > 0) {
delayWorker();
@ -25,14 +25,14 @@ void waybar::modules::Custom::delayWorker() {
thread_ = [this] {
bool can_update = true;
if (config_["exec-if"].isString()) {
auto res = waybar::util::command::exec(config_["exec-if"].asString());
auto res = util::command::exec(config_["exec-if"].asString());
if (res.exit_code != 0) {
can_update = false;
event_box_.hide();
}
}
if (can_update) {
output_ = waybar::util::command::exec(config_["exec"].asString());
output_ = util::command::exec(config_["exec"].asString());
dp.emit();
}
thread_.sleep_for(interval_);
@ -74,7 +74,7 @@ void waybar::modules::Custom::continuousWorker() {
};
}
void waybar::modules::Custom::refresh(int sig /*signal*/) {
void waybar::modules::Custom::refresh(int sig) {
if (sig == SIGRTMIN + config_["signal"].asInt()) {
thread_.wake_up();
}
@ -102,29 +102,31 @@ auto waybar::modules::Custom::update() -> void {
} else {
parseOutputRaw();
}
auto str = fmt::format(format_,
text_,
fmt::arg("alt", alt_),
fmt::arg("icon", getIcon(percentage_, alt_)),
fmt::arg("percentage", percentage_));
label_.set_markup(str);
if (tooltipEnabled()) {
if (text_ == tooltip_) {
label_.set_tooltip_text(str);
} else {
label_.set_tooltip_text(tooltip_);
if (str.empty()) {
event_box_.hide();
} else {
label_.set_markup(str);
if (tooltipEnabled()) {
if (text_ == tooltip_) {
label_.set_tooltip_text(str);
} else {
label_.set_tooltip_text(tooltip_);
}
}
auto classes = label_.get_style_context()->list_classes();
for (auto const& c : classes) {
label_.get_style_context()->remove_class(c);
}
for (auto const& c : class_) {
label_.get_style_context()->add_class(c);
}
event_box_.show();
}
auto classes = label_.get_style_context()->list_classes();
for (auto const& c : classes) {
label_.get_style_context()->remove_class(c);
}
for (auto const& c : class_) {
label_.get_style_context()->add_class(c);
}
event_box_.show();
}
}

View File

@ -3,15 +3,11 @@
waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar,
const Json::Value& config)
: ALabel(config, "{status}"),
: ALabel(config, "idle_inhibitor", id, "{status}"),
bar_(bar),
status_("deactivated"),
idle_inhibitor_(nullptr),
pid_(-1) {
label_.set_name("idle_inhibitor");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
event_box_.signal_button_press_event().connect(
sigc::mem_fun(*this, &IdleInhibitor::handleToggle));

View File

@ -1,11 +1,7 @@
#include "modules/memory.hpp"
waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config)
: ALabel(config, "{}%", 30) {
label_.set_name("memory");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
: ALabel(config, "memory", id, "{}%", 30) {
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);
@ -15,12 +11,15 @@ waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config
auto waybar::modules::Memory::update() -> void {
parseMeminfo();
if (memtotal_ > 0 && memfree_ >= 0) {
int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_;
auto total_ram_gigabytes = memtotal_ / std::pow(1024, 2);
int used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_;
auto used_ram_gigabytes = (memtotal_ - memfree_) / std::pow(1024, 2);
auto available_ram_gigabytes = memfree_ / std::pow(1024, 2);
getState(used_ram_percentage);
label_.set_markup(fmt::format(format_, used_ram_percentage,
label_.set_markup(fmt::format(format_,
used_ram_percentage,
fmt::arg("total", total_ram_gigabytes),
fmt::arg("percentage", used_ram_percentage),
fmt::arg("used", used_ram_gigabytes),
fmt::arg("avail", available_ram_gigabytes)));

View File

@ -4,7 +4,7 @@
#include <spdlog/spdlog.h>
waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
: ALabel(config, "{album} - {artist} - {title}", 5),
: ALabel(config, "mpd", id, "{album} - {artist} - {title}", 5),
module_name_(id.empty() ? "mpd" : "mpd#" + id),
server_(nullptr),
port_(config_["port"].isUInt() ? config["port"].asUInt() : 0),
@ -21,11 +21,6 @@ waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
spdlog::warn("{}: `timeout` configuration should be an unsigned int", module_name_);
}
label_.set_name("mpd");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
if (!config["server"].isNull()) {
if (!config_["server"].isString()) {
spdlog::warn("{}:`server` configuration should be a string", module_name_);
@ -261,7 +256,7 @@ void waybar::modules::MPD::tryConnect() {
checkErrors(connection_.get());
spdlog::info("{}: Connected to MPD", module_name_);
} catch (std::runtime_error& e) {
spdlog::error("{}: Failed to connect to MPD: {}", module_name_, e.what());
spdlog::error("{}: Failed to connect to MPD: {}", module_name_, e.what());
connection_.reset();
alternate_connection_.reset();
}

View File

@ -73,9 +73,8 @@ std::optional<unsigned long long> read_netstat(std::string_view category, std::s
} // namespace
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
: ALabel(config, "{ifname}", 60),
: ALabel(config, "network", id, "{ifname}", 60),
ifid_(-1),
last_ext_iface_(-1),
family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET),
efd_(-1),
ev_fd_(-1),
@ -83,11 +82,6 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
signal_strength_dbm_(0),
signal_strength_(0),
frequency_(0) {
label_.set_name("network");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
auto down_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_DOWN_TOTAL_KEY);
auto up_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_UP_TOTAL_KEY);
if (down_octets) {
@ -102,10 +96,11 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
bandwidth_up_total_ = 0;
}
createInfoSocket();
createEventSocket();
createInfoSocket();
auto default_iface = getPreferredIface();
if (default_iface != -1) {
ifid_ = default_iface;
char ifname[IF_NAMESIZE];
if_indextoname(default_iface, ifname);
ifname_ = ifname;
@ -126,8 +121,11 @@ waybar::modules::Network::~Network() {
}
if (ev_sock_ != nullptr) {
nl_socket_drop_membership(ev_sock_, RTNLGRP_LINK);
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
if (family_ == AF_INET) {
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
} else {
nl_socket_drop_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
}
nl_close(ev_sock_);
nl_socket_free(ev_sock_);
}
@ -137,17 +135,21 @@ waybar::modules::Network::~Network() {
}
}
void waybar::modules::Network::createInfoSocket() {
void waybar::modules::Network::createEventSocket() {
ev_sock_ = nl_socket_alloc();
nl_socket_disable_seq_check(ev_sock_);
nl_socket_modify_cb(ev_sock_, NL_CB_VALID, NL_CB_CUSTOM, handleEvents, this);
nl_join_groups(ev_sock_, RTMGRP_LINK);
auto groups = RTMGRP_LINK | (family_ == AF_INET ? RTMGRP_IPV4_IFADDR : RTMGRP_IPV6_IFADDR);
nl_join_groups(ev_sock_, groups); // Deprecated
if (nl_connect(ev_sock_, NETLINK_ROUTE) != 0) {
throw std::runtime_error("Can't connect network socket");
}
nl_socket_add_membership(ev_sock_, RTNLGRP_LINK);
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
if (family_ == AF_INET) {
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV4_IFADDR);
} else {
nl_socket_add_membership(ev_sock_, RTNLGRP_IPV6_IFADDR);
}
efd_ = epoll_create1(EPOLL_CLOEXEC);
if (efd_ < 0) {
throw std::runtime_error("Can't create epoll");
@ -174,7 +176,7 @@ void waybar::modules::Network::createInfoSocket() {
}
}
void waybar::modules::Network::createEventSocket() {
void waybar::modules::Network::createInfoSocket() {
sock_ = nl_socket_alloc();
if (genl_connect(sock_) != 0) {
throw std::runtime_error("Can't connect to netlink socket");
@ -199,14 +201,13 @@ void waybar::modules::Network::worker() {
}
thread_timer_.sleep_for(interval_);
};
std::array<struct epoll_event, EPOLL_MAX> events{};
thread_ = [this, &events] {
thread_ = [this] {
std::array<struct epoll_event, EPOLL_MAX> events{};
int ec = epoll_wait(efd_, events.data(), EPOLL_MAX, -1);
if (ec > 0) {
for (auto i = 0; i < ec; i++) {
if (events[i].data.fd == nl_socket_get_fd(ev_sock_)) {
nl_recvmsgs_default(ev_sock_);
} else {
if (events[i].data.fd != nl_socket_get_fd(ev_sock_) || nl_recvmsgs_default(ev_sock_) < 0) {
thread_.stop();
break;
}
@ -215,10 +216,16 @@ void waybar::modules::Network::worker() {
};
}
const std::string waybar::modules::Network::getNetworkState() const {
if (ifid_ == -1) return "disconnected";
if (ipaddr_.empty()) return "linked";
if (essid_.empty()) return "ethernet";
return "wifi";
}
auto waybar::modules::Network::update() -> void {
std::string connectiontype;
std::string tooltip_format;
std::lock_guard<std::mutex> lock(mutex_);
std::string tooltip_format;
auto down_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_DOWN_TOTAL_KEY);
auto up_octets = read_netstat(BANDWIDTH_CATEGORY, BANDWIDTH_UP_TOTAL_KEY);
@ -233,45 +240,22 @@ auto waybar::modules::Network::update() -> void {
bandwidth_up = *up_octets - bandwidth_up_total_;
bandwidth_up_total_ = *up_octets;
}
if (ifid_ <= 0 || !linked_) {
if (config_["format-disconnected"].isString()) {
default_format_ = config_["format-disconnected"].asString();
}
if (config_["tooltip-format-disconnected"].isString()) {
tooltip_format = config_["tooltip-format-disconnected"].asString();
}
label_.get_style_context()->add_class("disconnected");
connectiontype = "disconnected";
} else {
if (essid_.empty()) {
if (config_["format-ethernet"].isString()) {
default_format_ = config_["format-ethernet"].asString();
}
if (config_["tooltip-format-ethernet"].isString()) {
tooltip_format = config_["tooltip-format-ethernet"].asString();
}
connectiontype = "ethernet";
} else if (ipaddr_.empty()) {
if (config_["format-linked"].isString()) {
default_format_ = config_["format-linked"].asString();
}
if (config_["tooltip-format-linked"].isString()) {
tooltip_format = config_["tooltip-format-linked"].asString();
}
connectiontype = "linked";
} else {
if (config_["format-wifi"].isString()) {
default_format_ = config_["format-wifi"].asString();
}
if (config_["tooltip-format-wifi"].isString()) {
tooltip_format = config_["tooltip-format-wifi"].asString();
}
connectiontype = "wifi";
}
label_.get_style_context()->remove_class("disconnected");
}
if (!alt_) {
auto state = getNetworkState();
if (!state_.empty() && label_.get_style_context()->has_class(state_)) {
label_.get_style_context()->remove_class(state_);
}
if (config_["format-" + state].isString()) {
default_format_ = config_["format-" + state].asString();
}
if (config_["tooltip-format-" + state].isString()) {
tooltip_format = config_["tooltip-format-" + state].asString();
}
if (!label_.get_style_context()->has_class(state)) {
label_.get_style_context()->add_class(state);
}
format_ = default_format_;
state_ = state;
}
getState(signal_strength_);
@ -305,7 +289,7 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)),
fmt::arg("icon", getIcon(signal_strength_, state_)),
fmt::arg("bandwidthDownBits", pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / interval_.count(), "o/s")),
@ -328,7 +312,7 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("ipaddr", ipaddr_),
fmt::arg("cidr", cidr_),
fmt::arg("frequency", frequency_),
fmt::arg("icon", getIcon(signal_strength_, connectiontype)),
fmt::arg("icon", getIcon(signal_strength_, state_)),
fmt::arg("bandwidthDownBits",
pow_format(bandwidth_down * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
@ -344,7 +328,7 @@ auto waybar::modules::Network::update() -> void {
}
// Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698
int waybar::modules::Network::getExternalInterface(int skip_idx) {
int waybar::modules::Network::getExternalInterface(int skip_idx) const {
static const uint32_t route_buffer_size = 8192;
struct nlmsghdr * hdr = nullptr;
struct rtmsg * rt = nullptr;
@ -462,22 +446,19 @@ int waybar::modules::Network::getExternalInterface(int skip_idx) {
} while (true);
out:
last_ext_iface_ = ifidx;
return ifidx;
}
void waybar::modules::Network::getInterfaceAddress() {
unsigned int cidrRaw;
struct ifaddrs *ifaddr, *ifa;
ipaddr_.clear();
netmask_.clear();
cidr_ = 0;
int success = getifaddrs(&ifaddr);
if (success != 0) {
return;
}
ifa = ifaddr;
while (ifa != nullptr && ipaddr_.empty() && netmask_.empty()) {
while (ifa != nullptr) {
if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_ &&
ifa->ifa_name == ifname_) {
char ipaddr[INET6_ADDRSTRLEN];
@ -489,20 +470,20 @@ void waybar::modules::Network::getInterfaceAddress() {
auto net_addr = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask);
netmask_ = inet_ntop(family_, &net_addr->sin_addr, netmask, INET6_ADDRSTRLEN);
cidrRaw = net_addr->sin_addr.s_addr;
linked_ = ifa->ifa_flags & IFF_RUNNING;
unsigned int cidr = 0;
while (cidrRaw) {
cidr += cidrRaw & 1;
cidrRaw >>= 1;
}
cidr_ = cidr;
break;
}
ifa = ifa->ifa_next;
}
freeifaddrs(ifaddr);
}
int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_t groups) {
int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_t groups) const {
struct sockaddr_nl sa = {};
sa.nl_family = AF_NETLINK;
sa.nl_groups = groups;
@ -516,7 +497,7 @@ int waybar::modules::Network::netlinkRequest(void *req, uint32_t reqlen, uint32_
return sendmsg(nl_socket_get_fd(ev_sock_), &msg, 0);
}
int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint32_t groups) {
int waybar::modules::Network::netlinkResponse(void *resp, uint32_t resplen, uint32_t groups) const {
struct sockaddr_nl sa = {};
sa.nl_family = AF_NETLINK;
sa.nl_groups = groups;
@ -539,20 +520,23 @@ bool waybar::modules::Network::checkInterface(struct ifinfomsg *rtif, std::strin
return config_["interface"].asString() == name ||
wildcardMatch(config_["interface"].asString(), name);
}
auto external_iface = getExternalInterface();
if (external_iface == -1) {
// Try with lastest working external iface
return last_ext_iface_ == rtif->ifi_index;
// getExternalInterface may need some delay to detect external interface
for (uint8_t tries = 0; tries < MAX_RETRY; tries += 1) {
auto external_iface = getExternalInterface();
if (external_iface > 0) {
return external_iface == rtif->ifi_index;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return external_iface == rtif->ifi_index;
return false;
}
int waybar::modules::Network::getPreferredIface(int skip_idx) {
int waybar::modules::Network::getPreferredIface(int skip_idx) const {
int ifid = -1;
if (config_["interface"].isString()) {
ifid_ = if_nametoindex(config_["interface"].asCString());
if (ifid_ > 0) {
ifname_ = config_["interface"].asString();
return ifid_;
ifid = if_nametoindex(config_["interface"].asCString());
if (ifid > 0) {
return ifid;
} else {
// Try with wildcard
struct ifaddrs *ifaddr, *ifa;
@ -561,24 +545,25 @@ int waybar::modules::Network::getPreferredIface(int skip_idx) {
return -1;
}
ifa = ifaddr;
ifid_ = -1;
ifid = -1;
while (ifa != nullptr) {
if (wildcardMatch(config_["interface"].asString(), ifa->ifa_name)) {
ifid_ = if_nametoindex(ifa->ifa_name);
ifid = if_nametoindex(ifa->ifa_name);
break;
}
ifa = ifa->ifa_next;
}
freeifaddrs(ifaddr);
return ifid_;
return ifid;
}
}
ifid_ = getExternalInterface(skip_idx);
if (ifid_ > 0) {
char ifname[IF_NAMESIZE];
if_indextoname(ifid_, ifname);
ifname_ = ifname;
return ifid_;
// getExternalInterface may need some delay to detect external interface
for (uint8_t tries = 0; tries < MAX_RETRY; tries += 1) {
ifid = getExternalInterface(skip_idx);
if (ifid > 0) {
return ifid;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return -1;
}
@ -591,64 +576,80 @@ void waybar::modules::Network::clearIface() {
signal_strength_dbm_ = 0;
signal_strength_ = 0;
frequency_ = 0;
linked_ = false;
}
void waybar::modules::Network::checkNewInterface(struct ifinfomsg *rtif) {
auto new_iface = getPreferredIface(rtif->ifi_index);
if (new_iface != -1) {
ifid_ = new_iface;
char ifname[IF_NAMESIZE];
if_indextoname(new_iface, ifname);
ifname_ = ifname;
getInterfaceAddress();
thread_timer_.wake_up();
} else {
ifid_ = -1;
dp.emit();
}
}
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
auto net = static_cast<waybar::modules::Network *>(data);
auto nh = nlmsg_hdr(msg);
std::lock_guard<std::mutex> lock(net->mutex_);
if (nh->nlmsg_type == RTM_NEWADDR) {
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
char ifname[IF_NAMESIZE];
if_indextoname(rtif->ifi_index, ifname);
// Auto detected network can also be assigned here
if ((net->ifid_ == -1 || rtif->ifi_index != net->ifid_) && net->checkInterface(rtif, ifname)) {
// If iface is different, clear data
if (rtif->ifi_index != net->ifid_) {
net->clearIface();
}
net->linked_ = true;
net->ifname_ = ifname;
net->ifid_ = rtif->ifi_index;
}
auto nh = nlmsg_hdr(msg);
auto ifi = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
if (nh->nlmsg_type == RTM_DELADDR) {
// Check for valid interface
if (rtif->ifi_index == net->ifid_) {
net->linked_ = true;
// Get Iface and WIFI info
net->getInterfaceAddress();
net->thread_timer_.wake_up();
}
} else if (nh->nlmsg_type == RTM_DELADDR) {
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
// Check for valid interface
if (rtif->ifi_index == net->ifid_) {
if (ifi->ifi_index == net->ifid_) {
net->ipaddr_.clear();
net->netmask_.clear();
net->cidr_ = 0;
net->dp.emit();
}
} else if (nh->nlmsg_type < RTM_NEWADDR) {
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
char ifname[IF_NAMESIZE];
if_indextoname(rtif->ifi_index, ifname);
// Check for valid interface
if (rtif->ifi_flags & IFF_RUNNING && net->checkInterface(rtif, ifname)) {
net->linked_ = true;
net->ifname_ = ifname;
net->ifid_ = rtif->ifi_index;
net->dp.emit();
} else if (rtif->ifi_index == net->ifid_) {
net->clearIface();
// Check for a new interface and get info
auto new_iface = net->getPreferredIface(rtif->ifi_index);
if (new_iface != -1) {
net->getInterfaceAddress();
net->thread_timer_.wake_up();
if (!(ifi->ifi_flags & IFF_RUNNING)) {
net->clearIface();
// Check for a new interface and get info
net->checkNewInterface(ifi);
} else {
net->dp.emit();
}
return NL_OK;
}
} else if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK) {
char ifname[IF_NAMESIZE];
if_indextoname(ifi->ifi_index, ifname);
// Check for valid interface
if (ifi->ifi_index != net->ifid_ && net->checkInterface(ifi, ifname)) {
net->ifname_ = ifname;
net->ifid_ = ifi->ifi_index;
// Get Iface and WIFI info
net->getInterfaceAddress();
net->thread_timer_.wake_up();
return NL_OK;
} else if (ifi->ifi_index == net->ifid_ &&
(!(ifi->ifi_flags & IFF_RUNNING) || !(ifi->ifi_flags & IFF_UP) ||
!net->checkInterface(ifi, ifname))) {
net->clearIface();
// Check for a new interface and get info
net->checkNewInterface(ifi);
return NL_OK;
}
} else {
char ifname[IF_NAMESIZE];
if_indextoname(ifi->ifi_index, ifname);
// Auto detected network can also be assigned here
if (ifi->ifi_index != net->ifid_ && net->checkInterface(ifi, ifname)) {
// If iface is different, clear data
if (ifi->ifi_index != net->ifid_) {
net->clearIface();
}
net->ifname_ = ifname;
net->ifid_ = ifi->ifi_index;
}
// Check for valid interface
if (ifi->ifi_index == net->ifid_) {
// Get Iface and WIFI info
net->getInterfaceAddress();
net->thread_timer_.wake_up();
return NL_OK;
}
}
return NL_SKIP;
@ -686,11 +687,10 @@ int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
net->parseEssid(bss);
net->parseSignal(bss);
net->parseFreq(bss);
return NL_SKIP;
return NL_OK;
}
void waybar::modules::Network::parseEssid(struct nlattr **bss) {
essid_.clear();
if (bss[NL80211_BSS_INFORMATION_ELEMENTS] != nullptr) {
auto ies = static_cast<char *>(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]));
auto ies_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
@ -763,7 +763,8 @@ auto waybar::modules::Network::getInfo() -> void {
}
// https://gist.github.com/rressi/92af77630faf055934c723ce93ae2495
bool waybar::modules::Network::wildcardMatch(const std::string &pattern, const std::string &text) {
bool waybar::modules::Network::wildcardMatch(const std::string &pattern,
const std::string &text) const {
auto P = int(pattern.size());
auto T = int(text.size());

View File

@ -1,21 +1,16 @@
#include "modules/pulseaudio.hpp"
waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value &config)
: ALabel(config, "{volume}%"),
: ALabel(config, "pulseaudio", id, "{volume}%"),
mainloop_(nullptr),
mainloop_api_(nullptr),
context_(nullptr),
scrolling_(false),
sink_idx_(0),
volume_(0),
muted_(false),
source_idx_(0),
source_volume_(0),
source_muted_(false) {
label_.set_name("pulseaudio");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
mainloop_ = pa_threaded_mainloop_new();
if (mainloop_ == nullptr) {
throw std::runtime_error("pa_mainloop_new() failed.");
@ -36,13 +31,8 @@ waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value
throw std::runtime_error("pa_mainloop_run() failed.");
}
pa_threaded_mainloop_unlock(mainloop_);
// define the pulse scroll events only when no user provided
// events are configured
if (!config["on-scroll-up"].isString() && !config["on-scroll-down"].isString()) {
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &Pulseaudio::handleVolume));
}
event_box_.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
event_box_.signal_scroll_event().connect(sigc::mem_fun(*this, &Pulseaudio::handleScroll));
}
waybar::modules::Pulseaudio::~Pulseaudio() {
@ -78,50 +68,33 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) {
}
}
bool waybar::modules::Pulseaudio::handleVolume(GdkEventScroll *e) {
// Avoid concurrent scroll event
if (scrolling_) {
return false;
bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) {
// change the pulse volume only when no user provided
// events are configured
if (config_["on-scroll-up"].isString() || config_["on-scroll-down"].isString()) {
return AModule::handleScroll(e);
}
bool direction_up = false;
double volume_tick = (double)PA_VOLUME_NORM / 100;
auto dir = AModule::getScrollDir(e);
if (dir == SCROLL_DIR::NONE) {
return true;
}
double volume_tick = static_cast<double>(PA_VOLUME_NORM) / 100;
pa_volume_t change = volume_tick;
pa_cvolume pa_volume = pa_volume_;
scrolling_ = true;
if (e->direction == GDK_SCROLL_UP) {
direction_up = true;
}
if (e->direction == GDK_SCROLL_DOWN) {
direction_up = false;
}
if (e->direction == GDK_SCROLL_SMOOTH) {
gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), &delta_x, &delta_y);
if (delta_y < 0) {
direction_up = true;
} else if (delta_y > 0) {
direction_up = false;
}
}
// isDouble returns true for integers as well, just in case
if (config_["scroll-step"].isDouble()) {
change = round(config_["scroll-step"].asDouble() * volume_tick);
}
if (direction_up) {
if (dir == SCROLL_DIR::UP) {
if (volume_ + 1 < 100) {
pa_cvolume_inc(&pa_volume, change);
}
} else {
} else if (dir == SCROLL_DIR::DOWN) {
if (volume_ - 1 >= 0) {
pa_cvolume_dec(&pa_volume, change);
}
}
pa_context_set_sink_volume_by_index(context_, sink_idx_, &pa_volume, volumeModifyCb, this);
return true;
}
@ -132,6 +105,10 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context * conte
pa_subscription_event_type_t type, uint32_t idx,
void *data) {
unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
unsigned operation = type & PA_SUBSCRIPTION_EVENT_TYPE_MASK;
if (operation != PA_SUBSCRIPTION_EVENT_CHANGE) {
return;
}
if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
pa_context_get_sink_info_by_index(context, idx, sinkInfoCb, data);
} else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE) {
@ -220,19 +197,21 @@ const std::string waybar::modules::Pulseaudio::getPortIcon() const {
auto waybar::modules::Pulseaudio::update() -> void {
auto format = format_;
if (muted_) {
format = config_["format-muted"].isString() ? config_["format-muted"].asString() : format;
std::string format_name = "format";
if (monitor_.find("a2dp_sink") != std::string::npos) {
format_name = format_name + "-bluetooth";
label_.get_style_context()->add_class("bluetooth");
} else {
label_.get_style_context()->remove_class("bluetooth");
}
if (muted_ ) {
format_name = format_name + "-muted";
label_.get_style_context()->add_class("muted");
} else {
label_.get_style_context()->remove_class("muted");
if (monitor_.find("a2dp_sink") != std::string::npos) {
format =
config_["format-bluetooth"].isString() ? config_["format-bluetooth"].asString() : format;
label_.get_style_context()->add_class("bluetooth");
} else {
label_.get_style_context()->remove_class("bluetooth");
}
}
format =
config_[format_name].isString() ? config_[format_name].asString() : format;
// TODO: find a better way to split source/sink
std::string format_source = "{volume}%";
if (source_muted_ && config_["format-source-muted"].isString()) {
@ -249,7 +228,4 @@ auto waybar::modules::Pulseaudio::update() -> void {
if (tooltipEnabled()) {
label_.set_tooltip_text(desc_);
}
if (scrolling_) {
scrolling_ = false;
}
}

View File

@ -1,6 +1,6 @@
#include "modules/sni/host.hpp"
#include <spdlog/spdlog.h>
#include <fmt/ostream.h>
#include <spdlog/spdlog.h>
namespace waybar::modules::SNI {
@ -130,7 +130,8 @@ std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(const std::st
}
void Host::addRegisteredItem(std::string service) {
auto [bus_name, object_path] = getBusNameAndObjectPath(service);
std::string bus_name, object_path;
std::tie(bus_name, object_path) = getBusNameAndObjectPath(service);
auto it = std::find_if(items_.begin(), items_.end(), [&bus_name, &object_path](const auto& item) {
return bus_name == item->bus_name && object_path == item->object_path;
});

View File

@ -1,6 +1,6 @@
#include "modules/sni/item.hpp"
#include <glibmm/main.h>
#include <spdlog/spdlog.h>
#include "modules/sni/item.hpp"
template <>
struct fmt::formatter<Glib::ustring> : formatter<std::string> {
@ -128,6 +128,7 @@ void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
}
} else if (name == "Menu") {
menu = get_variant<std::string>(value);
makeMenu();
} else if (name == "ItemIsMenu") {
item_is_menu = get_variant<bool>(value);
}
@ -319,7 +320,7 @@ void Item::onMenuDestroyed(Item* self, GObject* old_menu_pointer) {
}
}
void Item::makeMenu(GdkEventButton* const& ev) {
void Item::makeMenu() {
if (gtk_menu == nullptr && !menu.empty()) {
dbus_menu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbus_menu != nullptr) {
@ -335,7 +336,7 @@ bool Item::handleClick(GdkEventButton* const& ev) {
auto parameters = Glib::VariantContainerBase::create_tuple(
{Glib::Variant<int>::create(ev->x), Glib::Variant<int>::create(ev->y)});
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
makeMenu(ev);
makeMenu();
if (gtk_menu != nullptr) {
#if GTK_CHECK_VERSION(3, 22, 0)
gtk_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(ev));

View File

@ -4,15 +4,16 @@
namespace waybar::modules::SNI {
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
: config_(config),
: AModule(config, "tray", id),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
watcher_(nb_hosts_),
host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
box_.set_name("tray");
spdlog::warn(
"For a functionnal tray you must have libappindicator-* installed and export "
"For a functional tray you must have libappindicator-* installed and export "
"XDG_CURRENT_DESKTOP=Unity");
box_.set_name("tray");
event_box_.add(box_);
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
@ -41,6 +42,4 @@ auto Tray::update() -> void {
}
}
Tray::operator Gtk::Widget&() { return box_; }
} // namespace waybar::modules::SNI

View File

@ -3,11 +3,8 @@
namespace waybar::modules::sway {
Mode::Mode(const std::string& id, const Json::Value& config) : ALabel(config, "{}") {
label_.set_name("mode");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
Mode::Mode(const std::string& id, const Json::Value& config)
: ALabel(config, "mode", id, "{}", 0, true) {
ipc_.subscribe(R"(["mode"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent));
// Launch worker
@ -17,9 +14,14 @@ Mode::Mode(const std::string& id, const Json::Value& config) : ALabel(config, "{
void Mode::onEvent(const struct Ipc::ipc_response& res) {
try {
auto payload = parser_.parse(res.payload);
std::lock_guard<std::mutex> lock(mutex_);
auto payload = parser_.parse(res.payload);
if (payload["change"] != "default") {
mode_ = Glib::Markup::escape_text(payload["change"].asString());
if (payload["pango_markup"].asBool()) {
mode_ = payload["change"].asString();
} else {
mode_ = Glib::Markup::escape_text(payload["change"].asString());
}
} else {
mode_.clear();
}

View File

@ -4,15 +4,7 @@
namespace waybar::modules::sway {
Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
: ALabel(config, "{}"), bar_(bar), windowId_(-1) {
label_.set_name("window");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
if (label_.get_max_width_chars() == -1) {
label_.set_hexpand(true);
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
}
: ALabel(config, "window", id, "{}", 0, true), bar_(bar), windowId_(-1) {
ipc_.subscribe(R"(["window","workspace"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Window::onEvent));
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Window::onCmd));
@ -28,33 +20,9 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
try {
std::lock_guard<std::mutex> lock(mutex_);
auto payload = parser_.parse(res.payload);
auto [nb, id, name, app_id] = getFocusedNode(payload);
if (!app_id_.empty()) {
bar_.window.get_style_context()->remove_class(app_id_);
}
if (nb == 0) {
bar_.window.get_style_context()->remove_class("solo");
if (!bar_.window.get_style_context()->has_class("empty")) {
bar_.window.get_style_context()->add_class("empty");
}
} else if (nb == 1) {
bar_.window.get_style_context()->remove_class("empty");
if (!bar_.window.get_style_context()->has_class("solo")) {
bar_.window.get_style_context()->add_class("solo");
}
if (!app_id.empty() && !bar_.window.get_style_context()->has_class(app_id)) {
bar_.window.get_style_context()->add_class(app_id);
}
} else {
bar_.window.get_style_context()->remove_class("solo");
bar_.window.get_style_context()->remove_class("empty");
}
app_id_ = app_id;
if (windowId_ != id || window_ != name) {
windowId_ = id;
window_ = name;
dp.emit();
}
auto output = payload["ouput"].isString() ? payload["output"].asString() : "";
std::tie(app_nb_, windowId_, window_, app_id_) = getFocusedNode(payload["nodes"], output);
dp.emit();
} catch (const std::exception& e) {
spdlog::error("Window: {}", e.what());
}
@ -71,6 +39,27 @@ void Window::worker() {
}
auto Window::update() -> void {
if (!old_app_id_.empty()) {
bar_.window.get_style_context()->remove_class(old_app_id_);
}
if (app_nb_ == 0) {
bar_.window.get_style_context()->remove_class("solo");
if (!bar_.window.get_style_context()->has_class("empty")) {
bar_.window.get_style_context()->add_class("empty");
}
} else if (app_nb_ == 1) {
bar_.window.get_style_context()->remove_class("empty");
if (!bar_.window.get_style_context()->has_class("solo")) {
bar_.window.get_style_context()->add_class("solo");
}
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_;
}
} else {
bar_.window.get_style_context()->remove_class("solo");
bar_.window.get_style_context()->remove_class("empty");
}
label_.set_markup(fmt::format(format_, window_));
if (tooltipEnabled()) {
label_.set_tooltip_text(window_);
@ -78,20 +67,28 @@ auto Window::update() -> void {
}
std::tuple<std::size_t, int, std::string, std::string> Window::getFocusedNode(
const Json::Value& nodes) {
for (auto const& node : nodes["nodes"]) {
if (node["focused"].asBool() && node["type"] == "con") {
if ((!config_["all-outputs"].asBool() && nodes["output"] == bar_.output->name) ||
const Json::Value& nodes, std::string& output) {
for (auto const& node : nodes) {
if (node["output"].isString()) {
output = node["output"].asString();
}
if (node["focused"].asBool() && (node["type"] == "con" || node["type"] == "floating_con")) {
if ((!config_["all-outputs"].asBool() && output == bar_.output->name) ||
config_["all-outputs"].asBool()) {
auto app_id = node["app_id"].isString() ? node["app_id"].asString()
: node["window_properties"]["instance"].asString();
return {nodes["nodes"].size(),
return {nodes.size(),
node["id"].asInt(),
Glib::Markup::escape_text(node["name"].asString()),
app_id};
}
}
auto [nb, id, name, app_id] = getFocusedNode(node);
auto [nb, id, name, app_id] = getFocusedNode(node["nodes"], output);
if (id > -1 && !name.empty()) {
return {nb, id, name, app_id};
}
// Search for floating node
std::tie(nb, id, name, app_id) = getFocusedNode(node["floating_nodes"], output);
if (id > -1 && !name.empty()) {
return {nb, id, name, app_id};
}

View File

@ -4,19 +4,19 @@
namespace waybar::modules::sway {
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
: bar_(bar),
config_(config),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
scrolling_(false) {
: AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()),
bar_(bar),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0) {
box_.set_name("workspaces");
if (!id.empty()) {
box_.get_style_context()->add_class(id);
}
event_box_.add(box_);
ipc_.subscribe(R"(["workspace"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Workspaces::onEvent));
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Workspaces::onCmd));
ipc_.sendCmd(IPC_GET_WORKSPACES);
if (!config["disable-bar-scroll"].asBool()) {
if (config["enable-bar-scroll"].asBool()) {
auto &window = const_cast<Bar &>(bar_).window;
window.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
@ -36,9 +36,9 @@ void Workspaces::onEvent(const struct Ipc::ipc_response &res) {
void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
if (res.type == IPC_GET_WORKSPACES) {
try {
auto payload = parser_.parse(res.payload);
if (payload.isArray()) {
{
std::lock_guard<std::mutex> lock(mutex_);
auto payload = parser_.parse(res.payload);
workspaces_.clear();
std::copy_if(payload.begin(),
payload.end(),
@ -80,6 +80,7 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
// Adding to all outputs
Json::Value v;
v["name"] = p_w_name;
v["target_output"] = "";
workspaces_.emplace_back(std::move(v));
}
}
@ -90,16 +91,11 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
return lhs["name"].asString() < rhs["name"].asString();
});
}
dp.emit();
}
dp.emit();
} catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what());
}
} else {
if (scrolling_) {
scrolling_ = false;
}
}
}
@ -154,6 +150,11 @@ auto Workspaces::update() -> void {
} else {
button.get_style_context()->remove_class("urgent");
}
if ((*it)["target_output"].isString()) {
button.get_style_context()->add_class("persistant");
} else {
button.get_style_context()->remove_class("persistant");
}
if (needReorder) {
box_.reorder_child(button, it - workspaces_.begin());
}
@ -175,8 +176,8 @@ auto Workspaces::update() -> void {
}
Gtk::Button &Workspaces::addButton(const Json::Value &node) {
auto pair = buttons_.emplace(node["name"].asString(), node["name"].asString());
auto &button = pair.first->second;
auto pair = buttons_.emplace(node["name"].asString(), node["name"].asString());
auto &&button = pair.first->second;
box_.pack_start(button, false, false, 0);
button.set_relief(Gtk::RELIEF_NONE);
button.signal_clicked().connect([this, node] {
@ -195,10 +196,6 @@ Gtk::Button &Workspaces::addButton(const Json::Value &node) {
spdlog::error("Workspaces: {}", e.what());
}
});
if (!config_["disable-scroll"].asBool()) {
button.add_events(Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK);
button.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
}
return button;
}
@ -217,45 +214,28 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node
}
bool Workspaces::handleScroll(GdkEventScroll *e) {
// Avoid concurrent scroll event
if (scrolling_) {
return false;
auto dir = AModule::getScrollDir(e);
if (dir == SCROLL_DIR::NONE) {
return true;
}
std::string name;
scrolling_ = true;
{
std::lock_guard<std::mutex> lock(mutex_);
auto it = std::find_if(workspaces_.begin(), workspaces_.end(), [](const auto &workspace) {
return workspace["focused"].asBool();
});
if (it == workspaces_.end()) {
scrolling_ = false;
return false;
return true;
}
switch (e->direction) {
case GDK_SCROLL_DOWN:
case GDK_SCROLL_RIGHT:
name = getCycleWorkspace(it, false);
break;
case GDK_SCROLL_UP:
case GDK_SCROLL_LEFT:
name = getCycleWorkspace(it, true);
break;
case GDK_SCROLL_SMOOTH:
gdouble delta_x, delta_y;
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), &delta_x, &delta_y);
if (delta_y < 0) {
name = getCycleWorkspace(it, true);
} else if (delta_y > 0) {
name = getCycleWorkspace(it, false);
}
break;
default:
break;
if (dir == SCROLL_DIR::DOWN || dir == SCROLL_DIR::RIGHT) {
name = getCycleWorkspace(it, false);
} else if (dir == SCROLL_DIR::UP || dir == SCROLL_DIR::LEFT) {
name = getCycleWorkspace(it, true);
} else {
return true;
}
if (name.empty() || name == (*it)["name"].asString()) {
scrolling_ = false;
return false;
if (name == (*it)["name"].asString()) {
return true;
}
}
try {
@ -305,6 +285,4 @@ void Workspaces::onButtonReady(const Json::Value &node, Gtk::Button &button) {
}
}
Workspaces::operator Gtk::Widget &() { return box_; }
} // namespace waybar::modules::sway

View File

@ -1,7 +1,7 @@
#include "modules/temperature.hpp"
waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config)
: ALabel(config, "{temperatureC}°C", 10) {
: ALabel(config, "temperature", id, "{temperatureC}°C", 10) {
if (config_["hwmon-path"].isString()) {
file_path_ = config_["hwmon-path"].asString();
} else {
@ -12,10 +12,6 @@ waybar::modules::Temperature::Temperature(const std::string& id, const Json::Val
if (!temp.is_open()) {
throw std::runtime_error("Can't open " + file_path_);
}
label_.set_name("temperature");
if (!id.empty()) {
label_.get_style_context()->add_class(id);
}
thread_ = [this] {
dp.emit();
thread_.sleep_for(interval_);