diff --git a/.travis.yml b/.travis.yml index a853829..fd94669 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ env: - distro: archlinux - distro: fedora - distro: alpine + - distro: opensuse before_install: - docker pull alexays/waybar:${distro} diff --git a/Dockerfiles/alpine b/Dockerfiles/alpine index 78a78b6..fec63c2 100644 --- a/Dockerfiles/alpine +++ b/Dockerfiles/alpine @@ -2,4 +2,4 @@ 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 scdoc +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 pugixml libnl3-dev pulseaudio-dev libmpdclient-dev scdoc diff --git a/Dockerfiles/archlinux b/Dockerfiles/archlinux index 9197fb8..b640ce7 100644 --- a/Dockerfiles/archlinux +++ b/Dockerfiles/archlinux @@ -3,4 +3,4 @@ FROM archlinux/base:latest RUN pacman -Syu --noconfirm && \ - pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp scdoc --noconfirm + pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc --noconfirm diff --git a/Dockerfiles/debian b/Dockerfiles/debian index 8d7a065..eedbcfb 100644 --- a/Dockerfiles/debian +++ b/Dockerfiles/debian @@ -3,5 +3,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 scdoc && \ + apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libpugixml-dev 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 diff --git a/Dockerfiles/fedora b/Dockerfiles/fedora index af88607..d75083c 100644 --- a/Dockerfiles/fedora +++ b/Dockerfiles/fedora @@ -1,7 +1,7 @@ # vim: ft=Dockerfile -FROM fedora:30 +FROM fedora:32 -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 && \ +RUN dnf install sway meson git libinput-devel wayland-devel wayland-protocols-devel pugixml-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 diff --git a/Dockerfiles/opensuse b/Dockerfiles/opensuse index c54777e..af1be95 100644 --- a/Dockerfiles/opensuse +++ b/Dockerfiles/opensuse @@ -4,4 +4,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 scdoc + zypper -n install git meson clang libinput10 libinput-devel libpugixml1 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 diff --git a/Makefile b/Makefile index bb6b334..d7182c1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: build build-debug run clean default install -default: run +default: build build: meson build diff --git a/README.md b/README.md index d8b7545..00e56e5 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ - Local time - Battery - Network +- Bluetooth - Pulseaudio - Disk - Memory @@ -62,7 +63,24 @@ libmpdclient [MPD module] On Ubuntu 19.10 you can install all the relevant dependencies using this command: ``` -sudo apt install libgtkmm-3.0-dev libjsoncpp-dev libinput-dev libsigc++-2.0-dev libpulse-dev libnl-3-dev libdbusmenu-gtk3-dev libnl-genl-3-dev libfmt-dev clang-tidy libmpdclient-dev libwayland-dev libgtk-3-dev gobject-introspection libgirepository1.0-dev scdoc +sudo apt install \ + clang-tidy \ + gobject-introspection \ + libdbusmenu-gtk3-dev \ + libfmt-dev \ + libgirepository1.0-dev \ + libgtk-3-dev \ + libgtkmm-3.0-dev \ + libinput-dev \ + libjsoncpp-dev \ + libmpdclient-dev \ + libnl-3-dev \ + libnl-genl-3-dev \ + libpulse-dev \ + libsigc++-2.0-dev \ + libspdlog-dev \ + libwayland-dev \ + scdoc ``` diff --git a/include/factory.hpp b/include/factory.hpp index 7d4d14e..b14b998 100644 --- a/include/factory.hpp +++ b/include/factory.hpp @@ -32,6 +32,7 @@ #include "bar.hpp" #include "modules/custom.hpp" #include "modules/temperature.hpp" +#include "modules/bluetooth.hpp" namespace waybar { diff --git a/include/modules/bluetooth.hpp b/include/modules/bluetooth.hpp new file mode 100644 index 0000000..04c213d --- /dev/null +++ b/include/modules/bluetooth.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include "ALabel.hpp" + +#include +#include "util/sleeper_thread.hpp" +#include "util/rfkill.hpp" + +namespace waybar::modules { + +class Bluetooth : public ALabel { + public: + Bluetooth(const std::string&, const Json::Value&); + ~Bluetooth() = default; + auto update() -> void; + + private: + std::string status_; + util::SleeperThread thread_; + util::SleeperThread intervall_thread_; + + util::Rfkill rfkill_; +}; + +} // namespace waybar::modules diff --git a/include/modules/memory.hpp b/include/modules/memory.hpp index be66611..59f0e78 100644 --- a/include/modules/memory.hpp +++ b/include/modules/memory.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "ALabel.hpp" #include "util/sleeper_thread.hpp" @@ -17,8 +18,7 @@ class Memory : public ALabel { static inline const std::string data_dir_ = "/proc/meminfo"; void parseMeminfo(); - unsigned long memtotal_; - unsigned long memfree_; + std::unordered_map meminfo_; util::SleeperThread thread_; }; diff --git a/include/modules/network.hpp b/include/modules/network.hpp index 91e4ddb..edb5aa6 100644 --- a/include/modules/network.hpp +++ b/include/modules/network.hpp @@ -11,6 +11,7 @@ #include #include "ALabel.hpp" #include "util/sleeper_thread.hpp" +#include "util/rfkill.hpp" namespace waybar::modules { @@ -71,6 +72,9 @@ class Network : public ALabel { util::SleeperThread thread_; util::SleeperThread thread_timer_; + util::SleeperThread thread_rfkill_; + + util::Rfkill rfkill_; }; } // namespace waybar::modules diff --git a/include/util/command.hpp b/include/util/command.hpp index 69b1fd4..f3dd4e1 100644 --- a/include/util/command.hpp +++ b/include/util/command.hpp @@ -72,7 +72,10 @@ inline struct res exec(std::string cmd) { if (!fp) return {-1, ""}; auto output = command::read(fp); auto stat = command::close(fp, pid); - return {WEXITSTATUS(stat), output}; + if (WIFEXITED(stat)) { + return {WEXITSTATUS(stat), output}; + } + return {-1, output}; } inline int32_t forkExec(std::string cmd) { @@ -88,6 +91,7 @@ inline int32_t forkExec(std::string cmd) { // Child executes the command if (!pid) { setpgid(pid, pid); + signal(SIGCHLD, SIG_DFL); execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); exit(0); } else { diff --git a/include/util/rfkill.hpp b/include/util/rfkill.hpp new file mode 100644 index 0000000..5dbf3ce --- /dev/null +++ b/include/util/rfkill.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace waybar::util { + +class Rfkill { + public:; + Rfkill(enum rfkill_type rfkill_type); + ~Rfkill() = default; + void waitForEvent(); + bool getState() const; + + private: + enum rfkill_type rfkill_type_; + int state_ = 0; +}; + +} // namespace waybar::util diff --git a/man/waybar-backlight.5.scd b/man/waybar-backlight.5.scd index 5f2bb82..e6116e3 100644 --- a/man/waybar-backlight.5.scd +++ b/man/waybar-backlight.5.scd @@ -10,29 +10,29 @@ The *backlight* module displays the current backlight level. # CONFIGURATION -*interval* ++ +*interval*: ++ typeof: integer ++ default: 2 ++ The interval in which information gets polled. -*format* ++ +*format*: ++ typeof: string ++ default: {percent}% ++ The format, how information should be displayed. On {} data gets inserted. -*max-length* ++ +*max-length*: ++ typeof: integer ++ The maximum length in characters the module should display. -*rotate* ++ +*rotate*: ++ typeof: integer ++ Positive value to rotate the text label. -*states* ++ +*states*: ++ typeof: array ++ A number of backlight states which get activated on certain brightness levels. -*on-click* ++ +*on-click*: ++ typeof: string ++ Command to execute when the module is clicked. @@ -40,19 +40,23 @@ The *backlight* module displays the current backlight level. typeof: string ++ Command to execute when middle-clicked on the module using mousewheel. -*on-click-right* ++ +*on-click-right*: ++ typeof: string ++ Command to execute when the module is right clicked. -*on-scroll-up* ++ +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + +*on-scroll-up*: ++ typeof: string ++ Command to execute when performing a scroll up on the module. -*on-scroll-down* ++ +*on-scroll-down*: ++ typeof: string Command to execute when performing a scroll down on the module. -*smooth-scrolling-threshold* ++ +*smooth-scrolling-threshold*: ++ typeof: double Threshold to be used when scrolling. diff --git a/man/waybar-battery.5.scd b/man/waybar-battery.5.scd index f96f85c..75d4108 100644 --- a/man/waybar-battery.5.scd +++ b/man/waybar-battery.5.scd @@ -10,29 +10,33 @@ The *battery* module displays the current capacity and state (eg. charging) of y # CONFIGURATION -*bat* ++ +*bat*: ++ typeof: string ++ The battery to monitor, as in /sys/class/power_supply/ instead of auto detect. -*adapter* ++ +*adapter*: ++ typeof: string ++ The adapter to monitor, as in /sys/class/power_supply/ instead of auto detect. -*interval* ++ +*full-at*: ++ + typeof: integer ++ + Define the max percentage of the battery, usefull for an old battery, e.g. 96 + +*interval*: ++ typeof: integer ++ default: 60 ++ The interval in which the information gets polled. -*states* ++ +*states*: ++ typeof: array ++ A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*. -*format* ++ +*format*: ++ typeof: string ++ default: {capacity}% ++ The format, how the time should be displayed. -*format-time* ++ +*format-time*: ++ typeof: string ++ default: {H} h {M} min ++ The format, how the time should be displayed. @@ -58,10 +62,14 @@ The *battery* module displays the current capacity and state (eg. charging) of y typeof: string ++ Command to execute when middle-clicked on the module using mousewheel. -*on-click-right* ++ +*on-click-right*: ++ typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. @@ -70,11 +78,11 @@ The *battery* module displays the current capacity and state (eg. charging) of y typeof: string ++ Command to execute when scrolling down on the module. -*smooth-scrolling-threshold* ++ +*smooth-scrolling-threshold*: ++ typeof: double ++ Threshold to be used when scrolling. -*tooltip* ++ +*tooltip*: ++ typeof: bool ++ default: true ++ Option to disable tooltip on hover. diff --git a/man/waybar-bluetooth.5.scd b/man/waybar-bluetooth.5.scd new file mode 100644 index 0000000..a07e544 --- /dev/null +++ b/man/waybar-bluetooth.5.scd @@ -0,0 +1,94 @@ +waybar-bluetooth(5) + +# NAME + +waybar - bluetooth module + +# DESCRIPTION + +The *bluetooth* module displays information about the status of the device's bluetooth device. + +# CONFIGURATION + +Addressed by *bluetooth* + +*interval*: ++ + typeof: integer ++ + default: 60 ++ + The interval in which the bluetooth state gets updated. + +*format*: ++ + typeof: string ++ + default: *{icon}* ++ + The format, how information should be displayed. This format is used when other formats aren't specified. + +*format-icons*: ++ + typeof: array/object ++ + Based on the device status, the corresponding icon gets selected. ++ + The order is *low* to *high*. Or by the state if it is an object. + +*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-middle*: ++ + typeof: string ++ + Command to execute when middle-clicked on the module using mousewheel. + +*on-click-right*: ++ + typeof: string ++ + Command to execute when you right clicked on the module. + +*on-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. + +# FORMAT REPLACEMENTS + +*{status}*: Status of the bluetooth device. + +*{icon}*: Icon, as defined in *format-icons*. + +# EXAMPLES + +``` +"bluetooth": { + "format": "{icon}", + "format-alt": "bluetooth: {status}", + "interval": 30, + "format-icons": { + "enabled": "", + "disabled": "" + } + "tooltip-format": "{status}" +} +``` + +# STYLE + +- *#bluetooth* diff --git a/man/waybar-clock.5.scd b/man/waybar-clock.5.scd index 6684d89..3610f19 100644 --- a/man/waybar-clock.5.scd +++ b/man/waybar-clock.5.scd @@ -51,6 +51,10 @@ The *clock* module displays the current date and time. typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-cpu.5.scd b/man/waybar-cpu.5.scd index 27dde96..cb83134 100644 --- a/man/waybar-cpu.5.scd +++ b/man/waybar-cpu.5.scd @@ -44,6 +44,10 @@ The *cpu* module displays the current cpu utilization. typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-custom.5.scd b/man/waybar-custom.5.scd index 0ae7f4c..121585a 100644 --- a/man/waybar-custom.5.scd +++ b/man/waybar-custom.5.scd @@ -33,6 +33,12 @@ Addressed by *custom/* You can update it manually with a signal. If no *interval* is defined, it is assumed that the out script loops it self. +*restart-interval*: ++ + typeof: integer ++ + The restart interval (in seconds). + Can't be used with the *interval* option, so only with continuous scripts. + Once the script exit, it'll be re-executed after the *restart-interval*. + *signal*: ++ typeof: integer ++ The signal number used to update the module. @@ -67,6 +73,10 @@ Addressed by *custom/* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-disk.5.scd b/man/waybar-disk.5.scd index 25d00b1..1a9320c 100644 --- a/man/waybar-disk.5.scd +++ b/man/waybar-disk.5.scd @@ -47,6 +47,10 @@ Addressed by *disk* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-idle-inhibitor.5.scd b/man/waybar-idle-inhibitor.5.scd index 1fba291..9d231d8 100644 --- a/man/waybar-idle-inhibitor.5.scd +++ b/man/waybar-idle-inhibitor.5.scd @@ -39,6 +39,10 @@ screensaving, also known as "presentation mode". typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-memory.5.scd b/man/waybar-memory.5.scd index 70718e1..81c6216 100644 --- a/man/waybar-memory.5.scd +++ b/man/waybar-memory.5.scd @@ -46,6 +46,10 @@ Addressed by *memory* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-mpd.5.scd b/man/waybar-mpd.5.scd index fc3b1b3..1ee7a98 100644 --- a/man/waybar-mpd.5.scd +++ b/man/waybar-mpd.5.scd @@ -89,6 +89,10 @@ Addressed by *mpd* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-network.5.scd b/man/waybar-network.5.scd index a557aa3..aa6eb3f 100644 --- a/man/waybar-network.5.scd +++ b/man/waybar-network.5.scd @@ -47,6 +47,10 @@ Addressed by *network* typeof: string ++ This format is used when the displayed interface is disconnected. +*format-disabled*: ++ + typeof: string ++ + This format is used when the displayed interface is disabled. + *format-icons*: ++ typeof: array/object ++ Based on the current signal strength, the corresponding icon gets selected. ++ @@ -72,6 +76,10 @@ Addressed by *network* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. @@ -105,6 +113,10 @@ Addressed by *network* typeof: string ++ This format is used when the displayed interface is disconnected. +*tooltip-format-disabled*: ++ + typeof: string ++ + This format is used when the displayed interface is disabled. + # FORMAT REPLACEMENTS *{ifname}*: Name of the network interface. @@ -142,6 +154,7 @@ Addressed by *network* "format-wifi": "{essid} ({signalStrength}%) ", "format-ethernet": "{ifname} ", "format-disconnected": "", //An empty format will hide the module. + "format-disconnected": "", "tooltip-format": "{ifname}", "tooltip-format-wifi": "{essid} ({signalStrength}%) ", "tooltip-format-ethernet": "{ifname} ", @@ -154,6 +167,7 @@ Addressed by *network* - *#network* - *#network.disconnected* +- *#network.disabled* - *#network.linked* - *#network.ethernet* - *#network.wifi* diff --git a/man/waybar-pulseaudio.5.scd b/man/waybar-pulseaudio.5.scd index 487888a..c3f50e0 100644 --- a/man/waybar-pulseaudio.5.scd +++ b/man/waybar-pulseaudio.5.scd @@ -67,6 +67,10 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. This replaces the default behaviour of volume control. diff --git a/man/waybar-sway-mode.5.scd b/man/waybar-sway-mode.5.scd index 85a25d1..958a1ed 100644 --- a/man/waybar-sway-mode.5.scd +++ b/man/waybar-sway-mode.5.scd @@ -37,6 +37,10 @@ Addressed by *sway/mode* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-sway-window.5.scd b/man/waybar-sway-window.5.scd index 6a9d4e3..4863a76 100644 --- a/man/waybar-sway-window.5.scd +++ b/man/waybar-sway-window.5.scd @@ -37,6 +37,10 @@ Addressed by *sway/window* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-sway-workspaces.5.scd b/man/waybar-sway-workspaces.5.scd index fe38d23..18fe6f4 100644 --- a/man/waybar-sway-workspaces.5.scd +++ b/man/waybar-sway-workspaces.5.scd @@ -19,7 +19,7 @@ Addressed by *sway/workspaces* *format*: ++ typeof: string ++ - default: {name} ++ + default: {value} ++ The format, how information should be displayed. *format-icons*: ++ @@ -60,9 +60,15 @@ Addressed by *sway/workspaces* default: empty ++ Lists workspaces that should always be shown, even when non existent +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + # FORMAT REPLACEMENTS -*{name}*: Name of the workspace, as defined by sway. +*{value}*: Name of the workspace, as defined by sway. + +*{name}*: Number stripped from workspace value. *{icon}*: Icon, as defined in *format-icons*. @@ -75,6 +81,7 @@ 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 +- *persistent*: Will be shown, when workspace is persistent one. # PERSISTENT WORKSPACES diff --git a/man/waybar-temperature.5.scd b/man/waybar-temperature.5.scd index f867686..7c25e88 100644 --- a/man/waybar-temperature.5.scd +++ b/man/waybar-temperature.5.scd @@ -20,6 +20,14 @@ Addressed by *temperature* typeof: string ++ The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*. +*hwmon-path-abs*: ++ + typeof: string ++ + The path of the hwmon-directory of the device, e.g. */sys/devices/pci0000:00/0000:00:18.3/hwmon*. (Note that the subdirectory *hwmon/hwmon#*, where *#* is a number is not part of the path!) Has to be used together with *input-filename*. + +*input-filename*: ++ + typeof: string ++ + The temperature filename of your *hwmon-path-abs*, e.g. *temp1_input* + *critical-threshold*: ++ typeof: integer ++ The threshold before it is considered critical (Celsius). @@ -62,6 +70,10 @@ Addressed by *temperature* typeof: string ++ Command to execute when you right clicked on the module. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + *on-scroll-up*: ++ typeof: string ++ Command to execute when scrolling up on the module. diff --git a/man/waybar-tray.5.scd b/man/waybar-tray.5.scd index bb4510d..cd0e93f 100644 --- a/man/waybar-tray.5.scd +++ b/man/waybar-tray.5.scd @@ -20,6 +20,10 @@ Addressed by *tray* typeof: integer ++ Defines the spacing between the tray icons. +*on-update*: ++ + typeof: string ++ + Command to execute when the module is updated. + # EXAMPLES ``` diff --git a/meson.build b/meson.build index b8185c2..0730ccd 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project( 'waybar', 'cpp', 'c', - version: '0.9.1', + version: '0.9.2', license: 'MIT', default_options : [ 'cpp_std=c++17', @@ -25,7 +25,7 @@ else cpp_link_args += ['-lstdc++fs'] endif -git = find_program('git', required: false) +git = find_program('git', native: true, required: false) if not git.found() add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp') @@ -108,6 +108,7 @@ src_files = files( 'src/ALabel.cpp', 'src/modules/memory.cpp', 'src/modules/battery.cpp', + 'src/modules/bluetooth.cpp', 'src/modules/clock.cpp', 'src/modules/custom.cpp', 'src/modules/cpu.cpp', @@ -116,7 +117,8 @@ src_files = files( 'src/modules/temperature.cpp', 'src/main.cpp', 'src/bar.cpp', - 'src/client.cpp' + 'src/client.cpp', + 'src/util/rfkill.cpp' ) if true # find_program('sway', required : false).found() diff --git a/resources/config b/resources/config index 237c787..832f76c 100644 --- a/resources/config +++ b/resources/config @@ -1,5 +1,5 @@ { - "layer": "top", // Waybar at top layer + // "layer": "top", // Waybar at top layer // "position": "bottom", // Waybar position (top|bottom|left|right) "height": 30, // Waybar height (to be removed for auto height) // "width": 1280, // Waybar width diff --git a/resources/waybar.service.in b/resources/waybar.service.in index 1c086bf..03262a3 100644 --- a/resources/waybar.service.in +++ b/resources/waybar.service.in @@ -2,6 +2,7 @@ Description=Highly customizable Wayland bar for Sway and Wlroots based compositors. Documentation=https://github.com/Alexays/Waybar/wiki/ PartOf=wayland-session.target +After=wayland-session.target [Service] Type=dbus diff --git a/src/ALabel.cpp b/src/ALabel.cpp index 3d9f2b2..e251f0d 100644 --- a/src/ALabel.cpp +++ b/src/ALabel.cpp @@ -31,7 +31,7 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st } auto ALabel::update() -> void { - // Nothing here + AModule::update(); } std::string ALabel::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) { diff --git a/src/AModule.cpp b/src/AModule.cpp index 354d1bf..3066bfc 100644 --- a/src/AModule.cpp +++ b/src/AModule.cpp @@ -29,7 +29,10 @@ AModule::~AModule() { } auto AModule::update() -> void { - // Nothing here + // Run user-provided update handler if configured + if (config_["on-update"].isString()) { + pid_.push_back(util::command::forkExec(config_["on-update"].asString())); + } } bool AModule::handleToggle(GdkEventButton* const& e) { diff --git a/src/bar.cpp b/src/bar.cpp index 7b9e930..431a564 100644 --- a/src/bar.cpp +++ b/src/bar.cpp @@ -175,6 +175,11 @@ void waybar::Bar::initGtkLayerShell() { gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right); gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_TOP, margins_.top); gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, margins_.bottom); + + if (width_ > 1 && height_ > 1) { + /* configure events are not emitted if the bar is using initial size */ + setExclusiveZone(width_, height_); + } } #endif diff --git a/src/factory.cpp b/src/factory.cpp index 8f7cea7..16a6903 100644 --- a/src/factory.cpp +++ b/src/factory.cpp @@ -66,6 +66,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const { if (ref == "temperature") { return new waybar::modules::Temperature(id, config_[name]); } + if (ref == "bluetooth") { + return new waybar::modules::Bluetooth(id, config_[name]); + } if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) { return new waybar::modules::Custom(ref.substr(7), id, config_[name]); } diff --git a/src/modules/backlight.cpp b/src/modules/backlight.cpp index b38f260..6349dbb 100644 --- a/src/modules/backlight.cpp +++ b/src/modules/backlight.cpp @@ -187,6 +187,8 @@ auto waybar::modules::Backlight::update() -> void { } previous_best_ = best == nullptr ? std::nullopt : std::optional{*best}; previous_format_ = format_; + // Call parent update + ALabel::update(); } template diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp index dfd6753..bad3355 100644 --- a/src/modules/battery.cpp +++ b/src/modules/battery.cpp @@ -115,6 +115,16 @@ const std::tuple waybar::modules::Battery::getInfos time_remaining = -(float)(total_energy_full - total_energy) / total_power; } uint16_t capacity = total / batteries_.size(); + // Handle full-at + if (config_["full-at"].isUInt()) { + auto full_at = config_["full-at"].asUInt(); + if (full_at < 100) { + capacity = static_cast(capacity / full_at) * 100; + if (capacity > full_at) { + capacity = full_at; + } + } + } return {capacity, time_remaining, status}; } catch (const std::exception& e) { spdlog::error("Battery: {}", e.what()); @@ -192,4 +202,6 @@ auto waybar::modules::Battery::update() -> void { fmt::arg("icon", getIcon(capacity, state)), fmt::arg("time", formatTimeRemaining(time_remaining)))); } + // Call parent update + ALabel::update(); } diff --git a/src/modules/bluetooth.cpp b/src/modules/bluetooth.cpp new file mode 100644 index 0000000..b390976 --- /dev/null +++ b/src/modules/bluetooth.cpp @@ -0,0 +1,45 @@ +#include "modules/bluetooth.hpp" +#include "util/rfkill.hpp" +#include +#include + +waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config) + : ALabel(config, "bluetooth", id, "{icon}", 10), + status_("disabled"), + rfkill_{RFKILL_TYPE_BLUETOOTH} { + thread_ = [this] { + dp.emit(); + rfkill_.waitForEvent(); + }; + intervall_thread_ = [this] { + auto now = std::chrono::system_clock::now(); + auto timeout = std::chrono::floor(now + interval_); + auto diff = std::chrono::seconds(timeout.time_since_epoch().count() % interval_.count()); + thread_.sleep_until(timeout - diff); + dp.emit(); + }; +} + +auto waybar::modules::Bluetooth::update() -> void { + if (rfkill_.getState()) { + status_ = "disabled"; + } else { + status_ = "enabled"; + } + + label_.set_markup( + fmt::format( + format_, + fmt::arg("status", status_), + fmt::arg("icon", getIcon(0, status_)))); + + if (tooltipEnabled()) { + if (config_["tooltip-format"].isString()) { + auto tooltip_format = config_["tooltip-format"].asString(); + auto tooltip_text = fmt::format(tooltip_format, status_); + label_.set_tooltip_text(tooltip_text); + } else { + label_.set_tooltip_text(status_); + } + } +} diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp index 7fa0ad6..20aa1ce 100644 --- a/src/modules/clock.cpp +++ b/src/modules/clock.cpp @@ -54,6 +54,8 @@ auto waybar::modules::Clock::update() -> void { label_.set_tooltip_markup(text); } } + // Call parent update + ALabel::update(); } auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::string { diff --git a/src/modules/cpu.cpp b/src/modules/cpu.cpp index 298f7a4..a0f646f 100644 --- a/src/modules/cpu.cpp +++ b/src/modules/cpu.cpp @@ -18,6 +18,8 @@ auto waybar::modules::Cpu::update() -> void { } label_.set_markup(fmt::format(format_, fmt::arg("load", cpu_load), fmt::arg("usage", cpu_usage))); getState(cpu_usage); + // Call parent update + ALabel::update(); } uint16_t waybar::modules::Cpu::getCpuLoad() { diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp index ca09508..5a64ce2 100644 --- a/src/modules/custom.cpp +++ b/src/modules/custom.cpp @@ -49,19 +49,24 @@ void waybar::modules::Custom::continuousWorker() { thread_ = [&] { char* buff = nullptr; size_t len = 0; + bool restart = false; if (getline(&buff, &len, fp_) == -1) { int exit_code = 1; if (fp_) { exit_code = WEXITSTATUS(util::command::close(fp_, pid_)); fp_ = nullptr; } - thread_.stop(); if (exit_code != 0) { output_ = {exit_code, ""}; dp.emit(); spdlog::error("{} stopped unexpectedly, is it endless?", name_); } - return; + if (config_["restart-interval"].isUInt()) { + restart = true; + } else { + thread_.stop(); + return; + } } std::string output = buff; @@ -71,6 +76,14 @@ void waybar::modules::Custom::continuousWorker() { } output_ = {0, output}; dp.emit(); + if (restart) { + pid_ = -1; + fp_ = util::command::open(cmd, pid_); + if (!fp_) { + throw std::runtime_error("Unable to open " + cmd); + } + thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt())); + } }; } @@ -128,6 +141,8 @@ auto waybar::modules::Custom::update() -> void { event_box_.show(); } } + // Call parent update + ALabel::update(); } void waybar::modules::Custom::parseOutputRaw() { diff --git a/src/modules/disk.cpp b/src/modules/disk.cpp index 811fe72..87240de 100644 --- a/src/modules/disk.cpp +++ b/src/modules/disk.cpp @@ -73,4 +73,6 @@ auto waybar::modules::Disk::update() -> void { )); } event_box_.show(); + // Call parent update + ALabel::update(); } diff --git a/src/modules/idle_inhibitor.cpp b/src/modules/idle_inhibitor.cpp index e5460ad..d94e957 100644 --- a/src/modules/idle_inhibitor.cpp +++ b/src/modules/idle_inhibitor.cpp @@ -32,6 +32,8 @@ auto waybar::modules::IdleInhibitor::update() -> void { if (tooltipEnabled()) { label_.set_tooltip_text(status_); } + // Call parent update + ALabel::update(); } bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) { diff --git a/src/modules/memory.cpp b/src/modules/memory.cpp index eeb92bf..8e54d27 100644 --- a/src/modules/memory.cpp +++ b/src/modules/memory.cpp @@ -10,11 +10,23 @@ waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config auto waybar::modules::Memory::update() -> void { parseMeminfo(); - if (memtotal_ > 0 && memfree_ >= 0) { - 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); + + unsigned long memtotal = meminfo_["MemTotal"]; + unsigned long memfree; + if (meminfo_.count("MemAvailable")) { + // New kernels (3.4+) have an accurate available memory field. + memfree = meminfo_["MemAvailable"]; + } else { + // Old kernel; give a best-effort approximation of available memory. + memfree = meminfo_["MemFree"] + meminfo_["Buffers"] + meminfo_["Cached"] + + meminfo_["SReclaimable"] - meminfo_["Shmem"]; + } + + if (memtotal > 0 && memfree >= 0) { + 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_, @@ -30,10 +42,11 @@ auto waybar::modules::Memory::update() -> void { } else { event_box_.hide(); } + // Call parent update + ALabel::update(); } void waybar::modules::Memory::parseMeminfo() { - int64_t memfree = -1, membuffer = -1, memcache = -1, memavail = -1; std::ifstream info(data_dir_); if (!info.is_open()) { throw std::runtime_error("Can't open " + data_dir_); @@ -44,23 +57,9 @@ void waybar::modules::Memory::parseMeminfo() { if (posDelim == std::string::npos) { continue; } + std::string name = line.substr(0, posDelim); int64_t value = std::stol(line.substr(posDelim + 1)); - - if (name.compare("MemTotal") == 0) { - memtotal_ = value; - } else if (name.compare("MemAvailable") == 0) { - memavail = value; - } else if (name.compare("MemFree") == 0) { - memfree = value; - } else if (name.compare("Buffers") == 0) { - membuffer = value; - } else if (name.compare("Cached") == 0) { - memcache = value; - } - if (memtotal_ > 0 && (memavail >= 0 || (memfree > -1 && membuffer > -1 && memcache > -1))) { - break; - } + meminfo_[name] = value; } - memfree_ = memavail >= 0 ? memavail : memfree + membuffer + memcache; } diff --git a/src/modules/mpd.cpp b/src/modules/mpd.cpp index 13ab9f0..e37b687 100644 --- a/src/modules/mpd.cpp +++ b/src/modules/mpd.cpp @@ -56,6 +56,9 @@ auto waybar::modules::MPD::update() -> void { } setLabel(); + + // Call parent update + ALabel::update(); } std::thread waybar::modules::MPD::event_listener() { diff --git a/src/modules/network.cpp b/src/modules/network.cpp index cd675c8..0639d3e 100644 --- a/src/modules/network.cpp +++ b/src/modules/network.cpp @@ -4,7 +4,7 @@ #include #include #include "util/format.hpp" - +#include "util/rfkill.hpp" namespace { @@ -86,7 +86,8 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf cidr_(-1), signal_strength_dbm_(0), signal_strength_(0), - frequency_(0) { + frequency_(0), + rfkill_{RFKILL_TYPE_WLAN} { 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) { @@ -196,6 +197,7 @@ void waybar::modules::Network::createInfoSocket() { } void waybar::modules::Network::worker() { + // update via here not working thread_timer_ = [this] { { std::lock_guard lock(mutex_); @@ -206,6 +208,16 @@ void waybar::modules::Network::worker() { } thread_timer_.sleep_for(interval_); }; + thread_rfkill_ = [this] { + rfkill_.waitForEvent(); + { + std::lock_guard lock(mutex_); + if (ifid_ > 0) { + getInfo(); + dp.emit(); + } + } + }; thread_ = [this] { std::array events{}; @@ -222,7 +234,11 @@ void waybar::modules::Network::worker() { } const std::string waybar::modules::Network::getNetworkState() const { - if (ifid_ == -1) return "disconnected"; + if (ifid_ == -1) { + if (rfkill_.getState()) + return "disabled"; + return "disconnected"; + } if (ipaddr_.empty()) return "linked"; if (essid_.empty()) return "ethernet"; return "wifi"; @@ -315,6 +331,9 @@ auto waybar::modules::Network::update() -> void { label_.set_tooltip_text(text); } } + + // Call parent update + ALabel::update(); } // Based on https://gist.github.com/Yawning/c70d804d4b8ae78cc698 diff --git a/src/modules/pulseaudio.cpp b/src/modules/pulseaudio.cpp index 3e9a95e..571a78e 100644 --- a/src/modules/pulseaudio.cpp +++ b/src/modules/pulseaudio.cpp @@ -21,7 +21,7 @@ waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value if (context_ == nullptr) { throw std::runtime_error("pa_context_new() failed."); } - if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOAUTOSPAWN, nullptr) < 0) { + if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) { auto err = fmt::format("pa_context_connect() failed: {}", pa_strerror(pa_context_errno(context_))); throw std::runtime_error(err); @@ -215,7 +215,11 @@ auto waybar::modules::Pulseaudio::update() -> void { } else { label_.get_style_context()->remove_class("bluetooth"); } - if (muted_ ) { + if (muted_) { + // Check muted bluetooth format exist, otherwise fallback to default muted format + if (format_name != "format" && !config_[format_name + "-muted"].isString()) { + format_name = "format"; + } format_name = format_name + "-muted"; label_.get_style_context()->add_class("muted"); } else { @@ -241,4 +245,7 @@ auto waybar::modules::Pulseaudio::update() -> void { if (tooltipEnabled()) { label_.set_tooltip_text(desc_); } + + // Call parent update + ALabel::update(); } diff --git a/src/modules/sni/tray.cpp b/src/modules/sni/tray.cpp index e16837f..ae3702c 100644 --- a/src/modules/sni/tray.cpp +++ b/src/modules/sni/tray.cpp @@ -40,6 +40,8 @@ auto Tray::update() -> void { } else { box_.show_all(); } + // Call parent update + AModule::update(); } } // namespace waybar::modules::SNI diff --git a/src/modules/sway/mode.cpp b/src/modules/sway/mode.cpp index 632709d..605271c 100644 --- a/src/modules/sway/mode.cpp +++ b/src/modules/sway/mode.cpp @@ -47,6 +47,8 @@ auto Mode::update() -> void { } event_box_.show(); } + // Call parent update + ALabel::update(); } } // namespace waybar::modules::sway diff --git a/src/modules/sway/window.cpp b/src/modules/sway/window.cpp index c139180..f10bf1c 100644 --- a/src/modules/sway/window.cpp +++ b/src/modules/sway/window.cpp @@ -60,6 +60,8 @@ auto Window::update() -> void { if (tooltipEnabled()) { label_.set_tooltip_text(window_); } + // Call parent update + ALabel::update(); } std::tuple Window::getFocusedNode( diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp index fe87f5e..91df113 100644 --- a/src/modules/sway/workspaces.cpp +++ b/src/modules/sway/workspaces.cpp @@ -157,12 +157,13 @@ auto Workspaces::update() -> void { if (needReorder) { box_.reorder_child(button, it - workspaces_.begin()); } - std::string output = getIcon((*it)["name"].asString(), *it); + std::string output = (*it)["name"].asString(); if (config_["format"].isString()) { auto format = config_["format"].asString(); output = fmt::format(format, - fmt::arg("icon", output), - fmt::arg("name", trimWorkspaceName((*it)["name"].asString())), + fmt::arg("icon", getIcon(output, *it)), + fmt::arg("value", output), + fmt::arg("name", trimWorkspaceName(output)), fmt::arg("index", (*it)["num"].asString())); } if (!config_["disable-markup"].asBool()) { @@ -172,6 +173,8 @@ auto Workspaces::update() -> void { } onButtonReady(*it, button); } + // Call parent update + AModule::update(); } Gtk::Button &Workspaces::addButton(const Json::Value &node) { @@ -205,6 +208,8 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node if (config_["format-icons"][key].isString() && node[key].asBool()) { return config_["format-icons"][key].asString(); } + } else if (config_["format_icons"]["persistent"].isString() && node["target_output"].isString()) { + return config_["format-icons"]["persistent"].asString(); } else if (config_["format-icons"][key].isString()) { return config_["format-icons"][key].asString(); } diff --git a/src/modules/temperature.cpp b/src/modules/temperature.cpp index 78391a0..d8307d7 100644 --- a/src/modules/temperature.cpp +++ b/src/modules/temperature.cpp @@ -1,9 +1,12 @@ #include "modules/temperature.hpp" +#include waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config) : ALabel(config, "temperature", id, "{temperatureC}°C", 10) { if (config_["hwmon-path"].isString()) { file_path_ = config_["hwmon-path"].asString(); + } else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) { + file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString())).path().u8string() + "/" + config_["input-filename"].asString(); } else { auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0; file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone); @@ -33,6 +36,8 @@ auto waybar::modules::Temperature::update() -> void { fmt::arg("temperatureC", temperature_c), fmt::arg("temperatureF", temperature_f), fmt::arg("icon", getIcon(temperature_c, "", max_temp)))); + // Call parent update + ALabel::update(); } std::tuple waybar::modules::Temperature::getTemperature() { diff --git a/src/util/rfkill.cpp b/src/util/rfkill.cpp new file mode 100644 index 0000000..df77598 --- /dev/null +++ b/src/util/rfkill.cpp @@ -0,0 +1,83 @@ +/* https://git.kernel.org/pub/scm/linux/kernel/git/jberg/rfkill.git/ + * + * Copyright 2009 Johannes Berg + * Copyright 2009 Marcel Holtmann + * Copyright 2009 Tim Gardner + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "util/rfkill.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +waybar::util::Rfkill::Rfkill(const enum rfkill_type rfkill_type) + : rfkill_type_(rfkill_type) { +} + +void waybar::util::Rfkill::waitForEvent() { + struct rfkill_event event; + struct pollfd p; + ssize_t len; + int fd, n; + + fd = open("/dev/rfkill", O_RDONLY); + if (fd < 0) { + throw std::runtime_error("Can't open RFKILL control device"); + return; + } + + memset(&p, 0, sizeof(p)); + p.fd = fd; + p.events = POLLIN | POLLHUP; + + while (1) { + n = poll(&p, 1, -1); + if (n < 0) { + throw std::runtime_error("Failed to poll RFKILL control device"); + break; + } + + if (n == 0) + continue; + + len = read(fd, &event, sizeof(event)); + if (len < 0) { + throw std::runtime_error("Reading of RFKILL events failed"); + break; + } + + if (len != RFKILL_EVENT_SIZE_V1) { + throw std::runtime_error("Wrong size of RFKILL event"); + continue; + } + + if(event.type == rfkill_type_ && event.op == RFKILL_OP_CHANGE) { + state_ = event.soft || event.hard; + break; + } + } + + close(fd); + return; +} + + +bool waybar::util::Rfkill::getState() const { + return state_; +}