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..7bd9d76 100644
--- a/Dockerfiles/fedora
+++ b/Dockerfiles/fedora
@@ -2,6 +2,6 @@
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 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 3e14e57..be45818 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,9 @@ libsigc++
fmt
wayland
wlroots
+libgtk-3-dev [gtk-layer-shell]
+gobject-introspection [gtk-layer-shell]
+libgirepository1.0-dev [gtk-layer-shell]
libpulse [Pulseaudio module]
libnl [Network module]
sway [Sway modules]
@@ -56,6 +59,30 @@ libdbusmenu-gtk3 [Tray module]
libmpdclient [MPD module]
```
+On Ubuntu 19.10 you can install all the relevant dependencies using this command:
+
+```
+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
+```
+
+
Contributions welcome! - have fun :)
The style guidelines is [Google's](https://google.github.io/styleguide/cppguide.html)
diff --git a/include/bar.hpp b/include/bar.hpp
index 7566b08..fb0cd59 100644
--- a/include/bar.hpp
+++ b/include/bar.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include
#include
#include
#include
@@ -15,10 +16,11 @@ namespace waybar {
class Factory;
struct waybar_output {
- struct wl_output * output = nullptr;
- std::string name;
- uint32_t wl_name;
- struct zxdg_output_v1 *xdg_output = nullptr;
+ Glib::RefPtr monitor;
+ std::string name;
+
+ std::unique_ptr xdg_output = {
+ nullptr, &zxdg_output_v1_destroy};
};
class Bar {
@@ -30,13 +32,12 @@ class Bar {
auto toggle() -> void;
void handleSignal(int);
- struct waybar_output * output;
- Json::Value config;
- Gtk::Window window;
- struct wl_surface * surface;
- struct zwlr_layer_surface_v1 *layer_surface;
- bool visible = true;
- bool vertical = false;
+ struct waybar_output *output;
+ Json::Value config;
+ Gtk::Window window;
+ struct wl_surface * surface;
+ bool visible = true;
+ bool vertical = false;
private:
static constexpr const char *MIN_HEIGHT_MSG =
@@ -51,7 +52,9 @@ class Bar {
uint32_t, uint32_t);
static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *);
- void destroyOutput();
+#ifdef HAVE_GTK_LAYER_SHELL
+ void initGtkLayerShell();
+#endif
void onConfigure(GdkEventConfigure *ev);
void onRealize();
void onMap(GdkEventAny *ev);
@@ -68,6 +71,9 @@ class Bar {
int bottom = 0;
int left = 0;
} margins_;
+ struct zwlr_layer_surface_v1 *layer_surface_;
+ // use gtk-layer-shell instead of handling layer surfaces directly
+ bool use_gls_ = false;
uint32_t width_ = 0;
uint32_t height_ = 1;
uint8_t anchor_;
diff --git a/include/client.hpp b/include/client.hpp
index 715ae58..39b6ae3 100644
--- a/include/client.hpp
+++ b/include/client.hpp
@@ -30,26 +30,24 @@ class Client {
const std::string &style) const;
void bindInterfaces();
const std::string getValidPath(const std::vector &paths) const;
- void handleOutput(std::unique_ptr &output);
- bool isValidOutput(const Json::Value &config, std::unique_ptr &output);
+ void handleOutput(struct waybar_output &output);
+ bool isValidOutput(const Json::Value &config, struct waybar_output &output);
auto setupConfig(const std::string &config_file) -> void;
auto setupCss(const std::string &css_file) -> void;
- std::unique_ptr &getOutput(uint32_t wl_name);
- std::vector getOutputConfigs(std::unique_ptr &output);
+ struct waybar_output &getOutput(void *);
+ std::vector getOutputConfigs(struct waybar_output &output);
static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name,
const char *interface, uint32_t version);
static void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name);
- static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t, int32_t);
- static void handleLogicalSize(void *, struct zxdg_output_v1 *, int32_t, int32_t);
- static void handleDone(void *, struct zxdg_output_v1 *);
- static void handleName(void *, struct zxdg_output_v1 *, const char *);
- static void handleDescription(void *, struct zxdg_output_v1 *, const char *);
+ static void handleOutputName(void *, struct zxdg_output_v1 *, const char *);
+ void handleMonitorAdded(Glib::RefPtr monitor);
+ void handleMonitorRemoved(Glib::RefPtr monitor);
- Json::Value config_;
- Glib::RefPtr style_context_;
- Glib::RefPtr css_provider_;
- std::vector> outputs_;
+ Json::Value config_;
+ Glib::RefPtr style_context_;
+ Glib::RefPtr css_provider_;
+ std::list outputs_;
};
} // namespace waybar
diff --git a/include/modules/clock.hpp b/include/modules/clock.hpp
index aa9a0a2..e3873a6 100644
--- a/include/modules/clock.hpp
+++ b/include/modules/clock.hpp
@@ -6,11 +6,17 @@
#else
#include
#endif
+#include
#include "ALabel.hpp"
#include "util/sleeper_thread.hpp"
namespace waybar::modules {
+struct waybar_time {
+ std::locale locale;
+ date::zoned_seconds ztime;
+};
+
class Clock : public ALabel {
public:
Clock(const std::string&, const Json::Value&);
@@ -19,6 +25,15 @@ class Clock : public ALabel {
private:
util::SleeperThread thread_;
+ std::locale locale_;
+ const date::time_zone* time_zone_;
+ bool fixed_time_zone_;
+ date::year_month_day cached_calendar_ymd_;
+ std::string cached_calendar_text_;
+
+ auto calendar_text(const waybar_time& wtime) -> std::string;
+ auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void;
+ auto first_day_of_week() -> date::weekday;
};
} // namespace waybar::modules
diff --git a/include/modules/memory.hpp b/include/modules/memory.hpp
index be66611..5b0f51b 100644
--- a/include/modules/memory.hpp
+++ b/include/modules/memory.hpp
@@ -17,8 +17,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/mpd.hpp b/include/modules/mpd.hpp
index d69618a..d08b28b 100644
--- a/include/modules/mpd.hpp
+++ b/include/modules/mpd.hpp
@@ -36,6 +36,7 @@ class MPD : public ALabel {
bool stopped();
bool playing();
+ bool paused();
const std::string module_name_;
diff --git a/include/modules/pulseaudio.hpp b/include/modules/pulseaudio.hpp
index d575f62..541747c 100644
--- a/include/modules/pulseaudio.hpp
+++ b/include/modules/pulseaudio.hpp
@@ -34,14 +34,17 @@ class Pulseaudio : public ALabel {
pa_cvolume pa_volume_;
bool muted_;
std::string port_name_;
+ std::string form_factor_;
std::string desc_;
std::string monitor_;
+ std::string default_sink_name_;
// SOURCE
uint32_t source_idx_{0};
uint16_t source_volume_;
bool source_muted_;
std::string source_port_name_;
std::string source_desc_;
+ std::string default_source_name_;
};
} // namespace waybar::modules
diff --git a/include/modules/sni/tray.hpp b/include/modules/sni/tray.hpp
index e0aced1..aaa1e4f 100644
--- a/include/modules/sni/tray.hpp
+++ b/include/modules/sni/tray.hpp
@@ -21,7 +21,7 @@ class Tray : public AModule {
static inline std::size_t nb_hosts_ = 0;
Gtk::Box box_;
- SNI::Watcher watcher_;
+ SNI::Watcher::singleton watcher_;
SNI::Host host_;
};
diff --git a/include/modules/sni/watcher.hpp b/include/modules/sni/watcher.hpp
index 599380a..5a55d2d 100644
--- a/include/modules/sni/watcher.hpp
+++ b/include/modules/sni/watcher.hpp
@@ -7,10 +7,24 @@
namespace waybar::modules::SNI {
class Watcher {
+ private:
+ Watcher();
+
public:
- Watcher(std::size_t id);
~Watcher();
+ using singleton = std::shared_ptr;
+ static singleton getInstance() {
+ static std::weak_ptr weak;
+
+ std::shared_ptr strong = weak.lock();
+ if (!strong) {
+ strong = std::shared_ptr(new Watcher());
+ weak = strong;
+ }
+ return strong;
+ }
+
private:
typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType;
@@ -34,7 +48,6 @@ class Watcher {
void updateRegisteredItems(SnWatcher *obj);
uint32_t bus_name_id_;
- uint32_t watcher_id_;
GSList * hosts_ = nullptr;
GSList * items_ = nullptr;
SnWatcher *watcher_ = nullptr;
diff --git a/include/modules/sway/ipc/client.hpp b/include/modules/sway/ipc/client.hpp
index 629556f..7df5362 100644
--- a/include/modules/sway/ipc/client.hpp
+++ b/include/modules/sway/ipc/client.hpp
@@ -8,6 +8,7 @@
#include
#include
#include "ipc.hpp"
+#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@@ -28,6 +29,7 @@ class Ipc {
void sendCmd(uint32_t type, const std::string &payload = "");
void subscribe(const std::string &payload);
void handleEvent();
+ void setWorker(std::function &&func);
protected:
static inline const std::string ipc_magic_ = "i3-ipc";
@@ -38,9 +40,10 @@ class Ipc {
struct ipc_response send(int fd, uint32_t type, const std::string &payload = "");
struct ipc_response recv(int fd);
- int fd_;
- int fd_event_;
- std::mutex mutex_;
+ int fd_;
+ int fd_event_;
+ std::mutex mutex_;
+ util::SleeperThread thread_;
};
} // namespace waybar::modules::sway
diff --git a/include/modules/sway/mode.hpp b/include/modules/sway/mode.hpp
index f0cf74c..a1a88b0 100644
--- a/include/modules/sway/mode.hpp
+++ b/include/modules/sway/mode.hpp
@@ -6,7 +6,6 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
-#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@@ -18,14 +17,11 @@ class Mode : public ALabel, public sigc::trackable {
private:
void onEvent(const struct Ipc::ipc_response&);
- void worker();
std::string mode_;
util::JsonParser parser_;
std::mutex mutex_;
-
- util::SleeperThread thread_;
- Ipc ipc_;
+ Ipc ipc_;
};
} // namespace waybar::modules::sway
diff --git a/include/modules/sway/window.hpp b/include/modules/sway/window.hpp
index 5bb129d..40aaa1a 100644
--- a/include/modules/sway/window.hpp
+++ b/include/modules/sway/window.hpp
@@ -7,7 +7,6 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
-#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@@ -20,7 +19,6 @@ class Window : public ALabel, public sigc::trackable {
private:
void onEvent(const struct Ipc::ipc_response&);
void onCmd(const struct Ipc::ipc_response&);
- void worker();
std::tuple getFocusedNode(const Json::Value& nodes,
std::string& output);
void getTree();
@@ -33,9 +31,7 @@ class Window : public ALabel, public sigc::trackable {
std::size_t app_nb_;
util::JsonParser parser_;
std::mutex mutex_;
-
- util::SleeperThread thread_;
- Ipc ipc_;
+ Ipc ipc_;
};
} // namespace waybar::modules::sway
diff --git a/include/modules/sway/workspaces.hpp b/include/modules/sway/workspaces.hpp
index 498acc9..fef24bf 100644
--- a/include/modules/sway/workspaces.hpp
+++ b/include/modules/sway/workspaces.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include
#include
#include
#include
@@ -8,7 +9,6 @@
#include "client.hpp"
#include "modules/sway/ipc/client.hpp"
#include "util/json.hpp"
-#include "util/sleeper_thread.hpp"
namespace waybar::modules::sway {
@@ -21,7 +21,6 @@ class Workspaces : public AModule, public sigc::trackable {
private:
void onCmd(const struct Ipc::ipc_response&);
void onEvent(const struct Ipc::ipc_response&);
- void worker();
bool filterButtons();
Gtk::Button& addButton(const Json::Value&);
void onButtonReady(const Json::Value&, Gtk::Button&);
@@ -38,9 +37,7 @@ class Workspaces : public AModule, public sigc::trackable {
util::JsonParser parser_;
std::unordered_map buttons_;
std::mutex mutex_;
-
- util::SleeperThread thread_;
- Ipc ipc_;
+ Ipc ipc_;
};
} // namespace waybar::modules::sway
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/man/waybar-backlight.5.scd b/man/waybar-backlight.5.scd
index 2d97199..5f2bb82 100644
--- a/man/waybar-backlight.5.scd
+++ b/man/waybar-backlight.5.scd
@@ -36,6 +36,10 @@ The *backlight* module displays the current backlight level.
typeof: string ++
Command to execute when the module is clicked.
+*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 the module is right clicked.
diff --git a/man/waybar-battery.5.scd b/man/waybar-battery.5.scd
index 94a99e4..8bcd2e8 100644
--- a/man/waybar-battery.5.scd
+++ b/man/waybar-battery.5.scd
@@ -18,6 +18,10 @@ The *battery* module displays the current capacity and state (eg. charging) of y
typeof: string ++
The adapter to monitor, as in /sys/class/power_supply/ instead of auto detect.
+*full-at* ++
+ typeof: integer ++
+ Define the max percentage of the battery, usefull for an old battery, e.g. 96
+
*interval* ++
typeof: integer ++
default: 60 ++
@@ -37,32 +41,36 @@ The *battery* module displays the current capacity and state (eg. charging) of y
default: {H} h {M} min ++
The format, how the time should be displayed.
-*format-icons*
- typeof: array/object
+*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* ++
+*max-length*: ++
typeof: integer++
The maximum length in character the module should display.
-*rotate* ++
+*rotate*: ++
typeof: integer++
Positive value to rotate the text label.
-*on-click* ++
+*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* ++
+*on-scroll-up*: ++
typeof: string ++
Command to execute when scrolling up on the module.
-*on-scroll-down* ++
+*on-scroll-down*: ++
typeof: string ++
Command to execute when scrolling down on the module.
diff --git a/man/waybar-clock.5.scd b/man/waybar-clock.5.scd
index d979a67..6684d89 100644
--- a/man/waybar-clock.5.scd
+++ b/man/waybar-clock.5.scd
@@ -18,7 +18,18 @@ The *clock* module displays the current date and time.
*format*: ++
typeof: string ++
default: {:%H:%M} ++
- The format, how the date and time should be displayed.
+ The format, how the date and time should be displayed. ++
+ It uses the format of the date library. See https://howardhinnant.github.io/date/date.html#to_stream_formatting for details.
+
+*timezone*: ++
+ typeof: string ++
+ default: inferred local timezone ++
+ The timezone to display the time in, e.g. America/New_York.
+
+*locale*: ++
+ typeof: string ++
+ default: inferred from current locale ++
+ A locale to be used to display the time. Intended to render times in custom timezones with the proper language and format.
*max-length*: ++
typeof: integer ++
@@ -32,6 +43,10 @@ The *clock* module displays the current date and time.
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.
@@ -50,6 +65,10 @@ The *clock* module displays the current date and time.
View all valid format options in *strftime(3)*.
+# FORMAT REPLACEMENTS
+
+*{calendar}*: Current month calendar
+
# EXAMPLES
```
diff --git a/man/waybar-cpu.5.scd b/man/waybar-cpu.5.scd
index e4e5250..27dde96 100644
--- a/man/waybar-cpu.5.scd
+++ b/man/waybar-cpu.5.scd
@@ -36,6 +36,10 @@ The *cpu* module displays the current cpu utilization.
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.
diff --git a/man/waybar-custom.5.scd b/man/waybar-custom.5.scd
index a427be3..905dbc1 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.
@@ -59,6 +65,10 @@ Addressed by *custom/*
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.
diff --git a/man/waybar-disk.5.scd b/man/waybar-disk.5.scd
index 2a69cf4..25d00b1 100644
--- a/man/waybar-disk.5.scd
+++ b/man/waybar-disk.5.scd
@@ -39,6 +39,10 @@ Addressed by *disk*
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.
diff --git a/man/waybar-idle-inhibitor.5.scd b/man/waybar-idle-inhibitor.5.scd
index 74e2192..1fba291 100644
--- a/man/waybar-idle-inhibitor.5.scd
+++ b/man/waybar-idle-inhibitor.5.scd
@@ -31,6 +31,10 @@ screensaving, also known as "presentation mode".
typeof: string ++
Command to execute when clicked on the module. A click also toggles the state
+*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.
diff --git a/man/waybar-memory.5.scd b/man/waybar-memory.5.scd
index a9dfb3a..70718e1 100644
--- a/man/waybar-memory.5.scd
+++ b/man/waybar-memory.5.scd
@@ -38,6 +38,10 @@ Addressed by *memory*
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.
diff --git a/man/waybar-mpd.5.scd b/man/waybar-mpd.5.scd
index 155e7b3..fc3b1b3 100644
--- a/man/waybar-mpd.5.scd
+++ b/man/waybar-mpd.5.scd
@@ -13,110 +13,118 @@ The *mpd* module displays information about a running "Music Player Daemon" inst
Addressed by *mpd*
*server*: ++
- typeof: string ++
- The network address or Unix socket path of the MPD server. If empty, connect to the default host.
+ 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.
+ 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
+ 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
+ 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`
+ 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
+ typeof: string ++
+ default: "{album} - {artist} - {title}" ++
+ Information displayed when a song is playing.
*format-stopped*: ++
- typeof: string ++
- default: "stopped" ++
- Information displayed when the player is stopped.
+ typeof: string ++
+ default: "stopped" ++
+ Information displayed when the player is stopped.
+
+*format-paused*: ++
+ typeof: string ++
+ This format is used when a song is paused.
*format-disconnected*: ++
- typeof: string ++
- default: "disconnected" ++
- Information displayed when the MPD server can't be reached.
+ 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.
+ typeof: bool ++
+ default: true ++
+ Option to disable tooltip on hover.
*tooltip-format*: ++
- typeof: string ++
- default: "MPD (connected)" ++
- Tooltip information displayed when connected to MPD.
+ 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.
+ 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.
+ typeof: integer ++
+ Positive value to rotate the text label.
*max-length*: ++
- typeof: integer ++
- The maximum length in character the module should display.
+ typeof: integer ++
+ The maximum length in character the module should display.
*on-click*: ++
- typeof: string ++
- Command to execute when clicked on the module.
+ 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.
+ 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.
+ 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.
+ typeof: string ++
+ Command to execute when scrolling down on the module.
*smooth-scrolling-threshold*: ++
- typeof: double ++
- Threshold to be used when scrolling.
+ 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": "..." }*)
+ 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": "..." }*)
+ 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": "..." }*)
+ 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": "..." }*)
+ 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": "..." }*)
+ typeof: object ++
+ default: {} ++
+ Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*)
# FORMAT REPLACEMENTS
diff --git a/man/waybar-network.5.scd b/man/waybar-network.5.scd
index ed8451f..a557aa3 100644
--- a/man/waybar-network.5.scd
+++ b/man/waybar-network.5.scd
@@ -21,6 +21,11 @@ Addressed by *network*
default: 60 ++
The interval in which the network information gets polled (e.g. signal strength).
+*family*: ++
+ typeof: string ++
+ default: *ipv4* ++
+ The address family that is used for the format replacement {ipaddr} and to determine if a network connection is present.
+
*format*: ++
typeof: string ++
default: *{ifname}* ++
@@ -42,6 +47,11 @@ Addressed by *network*
typeof: string ++
This format is used when the displayed interface is disconnected.
+*format-icons*: ++
+ typeof: array/object ++
+ Based on the current signal strength, 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.
@@ -54,6 +64,10 @@ Addressed by *network*
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.
@@ -117,6 +131,8 @@ Addressed by *network*
*{bandwidthDownOctets}*: Instant down speed in octets/seconds.
+*{icon}*: Icon, as defined in *format-icons*.
+
# EXAMPLES
```
diff --git a/man/waybar-pulseaudio.5.scd b/man/waybar-pulseaudio.5.scd
index 2b11778..487888a 100644
--- a/man/waybar-pulseaudio.5.scd
+++ b/man/waybar-pulseaudio.5.scd
@@ -59,6 +59,10 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
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.
@@ -96,16 +100,17 @@ 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*
+- *headphone*
- *speaker*
- *hdmi*
- *headset*
-- *handsfree*
+- *hands-free*
- *portable*
- *car*
- *hifi*
- *phone*
+
# EXAMPLES
```
diff --git a/man/waybar-sway-mode.5.scd b/man/waybar-sway-mode.5.scd
index 64d9a3e..85a25d1 100644
--- a/man/waybar-sway-mode.5.scd
+++ b/man/waybar-sway-mode.5.scd
@@ -29,6 +29,10 @@ Addressed by *sway/mode*
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.
diff --git a/man/waybar-sway-window.5.scd b/man/waybar-sway-window.5.scd
index 75a974c..6a9d4e3 100644
--- a/man/waybar-sway-window.5.scd
+++ b/man/waybar-sway-window.5.scd
@@ -29,6 +29,10 @@ Addressed by *sway/window*
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.
diff --git a/man/waybar-sway-workspaces.5.scd b/man/waybar-sway-workspaces.5.scd
index fe38d23..f9ef31d 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*: ++
@@ -62,7 +62,9 @@ Addressed by *sway/workspaces*
# 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 +77,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 8177969..eeae546 100644
--- a/man/waybar-temperature.5.scd
+++ b/man/waybar-temperature.5.scd
@@ -13,71 +13,83 @@ The *temperature* module displays the current temperature from a thermal zone.
Addressed by *temperature*
*thermal-zone*: ++
- typeof: integer ++
- The thermal zone, as in */sys/class/thermal/*.
+ 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/*.
+ 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 (Celcius).
+ typeof: integer ++
+ The threshold before it is considered critical (Celsius).
*interval*: ++
- typeof: integer ++
- default: 10 ++
- The interval in which the information gets polled.
+ 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
+ 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.
+ typeof: string ++
+ default: {temperatureC}°C ++
+ The format (Celsius/Fahrenheit) 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*.
+ typeof: array ++
+ Based on the current temperature (Celsius) 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.
+ typeof: integer ++
+ Positive value to rotate the text label.
*max-length*: ++
- typeof: integer ++
- The maximum length in characters the module should display.
+ typeof: integer ++
+ The maximum length in characters the module should display.
*on-click*: ++
- typeof: string ++
- Command to execute when you clicked on the module.
+ typeof: string ++
+ Command to execute when you 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.
+ 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.
+ 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.
+ typeof: string ++
+ Command to execute when scrolling down on the module.
*smooth-scrolling-threshold*: ++
- typeof: double ++
- Threshold to be used when scrolling.
+ typeof: double ++
+ Threshold to be used when scrolling.
*tooltip*: ++
- typeof: bool ++
- default: true ++
- Option to disable tooltip on hover.
+ typeof: bool ++
+ default: true ++
+ Option to disable tooltip on hover.
# FORMAT REPLACEMENTS
-*{temperatureC}*: Temperature in Celcius.
+*{temperatureC}*: Temperature in Celsius.
*{temperatureF}*: Temperature in Fahrenheit.
diff --git a/man/waybar.5.scd b/man/waybar.5.scd
index 3278c63..758d90a 100644
--- a/man/waybar.5.scd
+++ b/man/waybar.5.scd
@@ -23,7 +23,8 @@ Also a minimal example configuration can be found on the at the bottom of this m
*layer* ++
typeof: string ++
default: bottom ++
- Decide if the bar is displayed in front of the windows or behind them.
+ Decide if the bar is displayed in front (*top*) of the windows or behind (*bottom*)
+ them.
*output* ++
typeof: string|array ++
@@ -66,6 +67,12 @@ Also a minimal example configuration can be found on the at the bottom of this m
typeof: string ++
Optional name added as a CSS class, for styling multiple waybars.
+*gtk-layer-shell* ++
+ typeof: bool ++
+ default: true ++
+ Option to disable the use of gtk-layer-shell for popups.
+ Only functional if compiled with gtk-layer-shell support.
+
# MODULE FORMAT
You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat).
diff --git a/meson.build b/meson.build
index a9d44ee..1dab13d 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
project(
'waybar', 'cpp', 'c',
- version: '0.8.0',
+ version: '0.9.2',
license: 'MIT',
default_options : [
'cpp_std=c++17',
@@ -9,6 +9,8 @@ project(
],
)
+compiler = meson.get_compiler('cpp')
+
cpp_args = []
cpp_link_args = []
@@ -16,13 +18,14 @@ if get_option('libcxx')
cpp_args += ['-stdlib=libc++']
cpp_link_args += ['-stdlib=libc++', '-lc++abi']
- cpp_link_args += ['-lc++fs']
+ if compiler.has_link_argument('-lc++fs')
+ cpp_link_args += ['-lc++fs']
+ endif
else
cpp_link_args += ['-lstdc++fs']
endif
-compiler = meson.get_compiler('cpp')
-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')
@@ -42,6 +45,22 @@ if not compiler.has_header('filesystem')
endif
endif
+code = '''
+#include
+#include
+int main(int argc, char** argv) {
+ locale_t locale = newlocale(LC_ALL, "en_US.UTF-8", nullptr);
+ char* str;
+ str = nl_langinfo_l(_NL_TIME_WEEK_1STDAY, locale);
+ str = nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, locale);
+ freelocale(locale);
+ return 0;
+}
+'''
+if compiler.links(code, name : 'nl_langinfo with _NL_TIME_WEEK_1STDAY, _NL_TIME_FIRST_WEEKDAY')
+ add_project_arguments('-DHAVE_LANGINFO_1STDAY', language: 'cpp')
+endif
+
add_global_arguments(cpp_args, language : 'cpp')
add_global_link_arguments(cpp_link_args, language : 'cpp')
@@ -52,7 +71,7 @@ spdlog = dependency('spdlog', version : ['>=1.3.1'], fallback : ['spdlog', 'spdl
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_protos = dependency('wayland-protocols')
-gtkmm = dependency('gtkmm-3.0')
+gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
giounix = dependency('gio-unix-2.0', required: get_option('dbusmenu-gtk'))
jsoncpp = dependency('jsoncpp')
@@ -62,7 +81,11 @@ libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
libpulse = dependency('libpulse', required: get_option('pulseaudio'))
libudev = dependency('libudev', required: get_option('libudev'))
libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
+gtk_layer_shell = dependency('gtk-layer-shell-0',
+ required: get_option('gtk-layer-shell'),
+ fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep'])
systemd = dependency('systemd', required: get_option('systemd'))
+tz_dep = dependency('date', default_options : [ 'use_system_tzdb=true' ], fallback: [ 'date', 'tz_dep' ])
prefix = get_option('prefix')
conf_data = configuration_data()
@@ -136,6 +159,10 @@ if libmpdclient.found()
src_files += 'src/modules/mpd.cpp'
endif
+if gtk_layer_shell.found()
+ add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp')
+endif
+
subdir('protocol')
executable(
@@ -158,7 +185,9 @@ executable(
libnlgen,
libpulse,
libudev,
- libmpdclient
+ libmpdclient,
+ gtk_layer_shell,
+ tz_dep
],
include_directories: [include_directories('include')],
install: true,
diff --git a/meson_options.txt b/meson_options.txt
index 1b86b57..8d442c7 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -7,3 +7,4 @@ option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable supp
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
option('mpd', type: 'feature', value: 'auto', description: 'Enable support for the Music Player Daemon')
option('out', type: 'string', value : '/', description: 'output prefix directory')
+option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use gtk-layer-shell library for popups support')
diff --git a/protocol/dbus-status-notifier-item.xml b/protocol/dbus-status-notifier-item.xml
index e46eb3c..c33cd84 100644
--- a/protocol/dbus-status-notifier-item.xml
+++ b/protocol/dbus-status-notifier-item.xml
@@ -31,7 +31,9 @@
+
@@ -44,4 +46,4 @@
-
\ No newline at end of file
+
diff --git a/resources/config b/resources/config
index 4e39239..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
@@ -64,7 +64,8 @@
"spacing": 10
},
"clock": {
- "tooltip-format": "{:%Y-%m-%d | %H:%M}",
+ // "timezone": "America/New_York",
+ "tooltip-format": "{:%Y %B}\n{calendar}",
"format-alt": "{:%Y-%m-%d}"
},
"cpu": {
@@ -121,8 +122,8 @@
"format-source": "{volume}% ",
"format-source-muted": "",
"format-icons": {
- "headphones": "",
- "handsfree": "",
+ "headphone": "",
+ "hands-free": "",
"headset": "",
"phone": "",
"portable": "",
diff --git a/resources/custom_modules/mediaplayer.py b/resources/custom_modules/mediaplayer.py
index 4d75a25..cf3df4b 100755
--- a/resources/custom_modules/mediaplayer.py
+++ b/resources/custom_modules/mediaplayer.py
@@ -38,6 +38,8 @@ def on_metadata(player, metadata, manager):
elif player.get_artist() != '' and player.get_title() != '':
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
title=player.get_title())
+ else:
+ track_info = player.get_title()
if player.props.status != 'Playing' and track_info:
track_info = ' ' + track_info
@@ -77,7 +79,7 @@ def signal_handler(sig, frame):
def parse_arguments():
parser = argparse.ArgumentParser()
- # Increase verbosity with every occurance of -v
+ # Increase verbosity with every occurence of -v
parser.add_argument('-v', '--verbose', action='count', default=0)
# Define for which player we're listening
@@ -123,4 +125,3 @@ def main():
if __name__ == '__main__':
main()
-
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/bar.cpp b/src/bar.cpp
index fc88511..431a564 100644
--- a/src/bar.cpp
+++ b/src/bar.cpp
@@ -1,3 +1,7 @@
+#ifdef HAVE_GTK_LAYER_SHELL
+#include
+#endif
+
#include "bar.hpp"
#include "client.hpp"
#include "factory.hpp"
@@ -8,7 +12,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
config(w_config),
window{Gtk::WindowType::WINDOW_TOPLEVEL},
surface(nullptr),
- layer_surface(nullptr),
+ layer_surface_(nullptr),
anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP),
left_(Gtk::ORIENTATION_HORIZONTAL, 0),
center_(Gtk::ORIENTATION_HORIZONTAL, 0),
@@ -28,11 +32,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
height_ = config["height"].isUInt() ? config["height"].asUInt() : height_;
width_ = config["width"].isUInt() ? config["width"].asUInt() : width_;
- 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_);
-
if (config["position"] == "bottom") {
anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
} else if (config["position"] == "left") {
@@ -98,6 +97,17 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config)
margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps};
}
+#ifdef HAVE_GTK_LAYER_SHELL
+ use_gls_ = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true;
+ if (use_gls_) {
+ initGtkLayerShell();
+ }
+#endif
+
+ 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_);
setupWidgets();
if (window.get_realized()) {
@@ -131,11 +141,48 @@ void waybar::Bar::onConfigure(GdkEventConfigure* ev) {
tmp_width = ev->width;
}
}
- if (tmp_width != width_ || tmp_height != height_) {
+ if (use_gls_) {
+ width_ = tmp_width;
+ height_ = tmp_height;
+ spdlog::debug("Set surface size {}x{} for output {}", width_, height_, output->name);
+ setExclusiveZone(tmp_width, tmp_height);
+ } else if (tmp_width != width_ || tmp_height != height_) {
setSurfaceSize(tmp_width, tmp_height);
}
}
+#ifdef HAVE_GTK_LAYER_SHELL
+void waybar::Bar::initGtkLayerShell() {
+ auto gtk_window = window.gobj();
+ // this has to be executed before GtkWindow.realize
+ gtk_layer_init_for_window(gtk_window);
+ gtk_layer_set_keyboard_interactivity(gtk_window, FALSE);
+ auto layer = config["layer"] == "top" ? GTK_LAYER_SHELL_LAYER_TOP : GTK_LAYER_SHELL_LAYER_BOTTOM;
+ gtk_layer_set_layer(gtk_window, layer);
+ gtk_layer_set_monitor(gtk_window, output->monitor->gobj());
+ gtk_layer_set_namespace(gtk_window, "waybar");
+
+ gtk_layer_set_anchor(
+ gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
+ gtk_layer_set_anchor(
+ gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT);
+ gtk_layer_set_anchor(
+ gtk_window, GTK_LAYER_SHELL_EDGE_TOP, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP);
+ gtk_layer_set_anchor(
+ gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM);
+
+ gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left);
+ 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
+
void waybar::Bar::onRealize() {
auto gdk_window = window.get_window()->gobj();
gdk_wayland_window_set_use_custom_surface(gdk_window);
@@ -145,16 +192,22 @@ void waybar::Bar::onMap(GdkEventAny* ev) {
auto gdk_window = window.get_window()->gobj();
surface = gdk_wayland_window_get_wl_surface(gdk_window);
+ if (use_gls_) {
+ return;
+ }
+
auto client = waybar::Client::inst();
+ // owned by output->monitor; no need to destroy
+ auto wl_output = gdk_wayland_monitor_get_wl_output(output->monitor->gobj());
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");
+ layer_surface_ = zwlr_layer_shell_v1_get_layer_surface(
+ client->layer_shell, surface, wl_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_keyboard_interactivity(layer_surface_, false);
+ zwlr_layer_surface_v1_set_anchor(layer_surface_, anchor_);
zwlr_layer_surface_v1_set_margin(
- layer_surface, margins_.top, margins_.right, margins_.bottom, margins_.left);
+ layer_surface_, margins_.top, margins_.right, margins_.bottom, margins_.left);
setSurfaceSize(width_, height_);
setExclusiveZone(width_, height_);
@@ -162,7 +215,7 @@ void waybar::Bar::onMap(GdkEventAny* ev) {
.configure = layerSurfaceHandleConfigure,
.closed = layerSurfaceHandleClosed,
};
- zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
+ zwlr_layer_surface_v1_add_listener(layer_surface_, &layer_surface_listener, this);
wl_surface_commit(surface);
wl_display_roundtrip(client->wl_display);
@@ -182,7 +235,15 @@ void waybar::Bar::setExclusiveZone(uint32_t width, uint32_t height) {
}
}
spdlog::debug("Set exclusive zone {} for output {}", zone, output->name);
- zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone);
+
+#ifdef HAVE_GTK_LAYER_SHELL
+ if (use_gls_) {
+ gtk_layer_set_exclusive_zone(window.gobj(), zone);
+ } else
+#endif
+ {
+ zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_, zone);
+ }
}
void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) {
@@ -198,7 +259,7 @@ void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) {
width += margins_.right + margins_.left;
}
spdlog::debug("Set surface size {}x{} for output {}", width, height, output->name);
- zwlr_layer_surface_v1_set_size(layer_surface, width, height);
+ zwlr_layer_surface_v1_set_size(layer_surface_, width, height);
}
// Converting string to button code rn as to avoid doing it later
@@ -282,9 +343,9 @@ 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(data);
- if (o->layer_surface) {
- zwlr_layer_surface_v1_destroy(o->layer_surface);
- o->layer_surface = nullptr;
+ if (o->layer_surface_) {
+ zwlr_layer_surface_v1_destroy(o->layer_surface_);
+ o->layer_surface_ = nullptr;
}
o->modules_left_.clear();
o->modules_center_.clear();
diff --git a/src/client.cpp b/src/client.cpp
index 34efdf1..f7c70e0 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -1,4 +1,5 @@
#include "client.hpp"
+#include
#include
#include
#include
@@ -33,11 +34,6 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint
if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
client->layer_shell = static_cast(
wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version));
- } else if (strcmp(interface, wl_output_interface.name) == 0) {
- auto wl_output = static_cast(
- wl_registry_bind(registry, name, &wl_output_interface, version));
- client->outputs_.emplace_back(new struct waybar_output({wl_output, "", name, nullptr}));
- client->handleOutput(client->outputs_.back());
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 &&
version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
client->xdg_output_manager = static_cast(wl_registry_bind(
@@ -50,91 +46,51 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint
void waybar::Client::handleGlobalRemove(void * data, struct wl_registry * /*registry*/,
uint32_t name) {
- auto client = static_cast(data);
- for (auto it = client->bars.begin(); it != client->bars.end();) {
- if ((*it)->output->wl_name == name) {
- auto output_name = (*it)->output->name;
- (*it)->window.close();
- it = client->bars.erase(it);
- spdlog::info("Bar removed from output: {}", output_name);
- } else {
- ++it;
- }
- }
- auto it = std::find_if(client->outputs_.begin(),
- client->outputs_.end(),
- [&name](const auto &output) { return output->wl_name == name; });
- if (it != client->outputs_.end()) {
- 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);
- }
+ // Nothing here
}
-void waybar::Client::handleOutput(std::unique_ptr &output) {
+void waybar::Client::handleOutput(struct waybar_output &output) {
static const struct zxdg_output_v1_listener xdgOutputListener = {
- .logical_position = handleLogicalPosition,
- .logical_size = handleLogicalSize,
- .done = handleDone,
- .name = handleName,
- .description = handleDescription,
+ .logical_position = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {},
+ .logical_size = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {},
+ .done = [](void *, struct zxdg_output_v1 *) {},
+ .name = &handleOutputName,
+ .description = [](void *, struct zxdg_output_v1 *, const char *) {},
};
- output->xdg_output = zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, output->output);
- zxdg_output_v1_add_listener(output->xdg_output, &xdgOutputListener, &output->wl_name);
+ // owned by output->monitor; no need to destroy
+ auto wl_output = gdk_wayland_monitor_get_wl_output(output.monitor->gobj());
+ output.xdg_output.reset(zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, wl_output));
+ zxdg_output_v1_add_listener(output.xdg_output.get(), &xdgOutputListener, &output);
}
-void waybar::Client::handleLogicalPosition(void * /*data*/,
- struct zxdg_output_v1 * /*zxdg_output_v1*/,
- int32_t /*x*/, int32_t /*y*/) {
- // Nothing here
-}
-
-void waybar::Client::handleLogicalSize(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/,
- int32_t /*width*/, int32_t /*height*/) {
- // Nothing here
-}
-
-void waybar::Client::handleDone(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/) {
- // Nothing here
-}
-
-bool waybar::Client::isValidOutput(const Json::Value & config,
- std::unique_ptr &output) {
+bool waybar::Client::isValidOutput(const Json::Value &config, struct waybar_output &output) {
bool found = true;
if (config["output"].isArray()) {
bool in_array = false;
for (auto const &output_conf : config["output"]) {
- if (output_conf.isString() && output_conf.asString() == output->name) {
+ if (output_conf.isString() && output_conf.asString() == output.name) {
in_array = true;
break;
}
}
found = in_array;
}
- if (config["output"].isString() && config["output"].asString() != output->name) {
+ if (config["output"].isString() && config["output"].asString() != output.name) {
found = false;
}
return found;
}
-std::unique_ptr &waybar::Client::getOutput(uint32_t wl_name) {
- auto it = std::find_if(outputs_.begin(), outputs_.end(), [&wl_name](const auto &output) {
- return output->wl_name == wl_name;
- });
+struct waybar::waybar_output &waybar::Client::getOutput(void *addr) {
+ auto it = std::find_if(
+ outputs_.begin(), outputs_.end(), [&addr](const auto &output) { return &output == addr; });
if (it == outputs_.end()) {
throw std::runtime_error("Unable to find valid output");
}
return *it;
}
-std::vector waybar::Client::getOutputConfigs(
- std::unique_ptr &output) {
+std::vector waybar::Client::getOutputConfigs(struct waybar_output &output) {
std::vector configs;
if (config_.isArray()) {
for (auto const &config : config_) {
@@ -148,27 +104,23 @@ std::vector waybar::Client::getOutputConfigs(
return configs;
}
-void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_output*/,
- const char *name) {
- auto wl_name = *static_cast(data);
+void waybar::Client::handleOutputName(void * data, struct zxdg_output_v1 * /*xdg_output*/,
+ const char *name) {
auto client = waybar::Client::inst();
try {
- auto &output = client->getOutput(wl_name);
- output->name = name;
+ auto &output = client->getOutput(data);
+ output.name = name;
+ spdlog::debug("Output detected: {} ({} {})",
+ name,
+ output.monitor->get_manufacturer(),
+ output.monitor->get_model());
auto configs = client->getOutputConfigs(output);
if (configs.empty()) {
- 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;
- }
+ output.xdg_output.reset();
} else {
wl_display_roundtrip(client->wl_display);
for (const auto &config : configs) {
- client->bars.emplace_back(std::make_unique(output.get(), config));
+ client->bars.emplace_back(std::make_unique(&output, config));
Glib::RefPtr screen = client->bars.back()->window.get_screen();
client->style_context_->add_provider_for_screen(
screen, client->css_provider_, GTK_STYLE_PROVIDER_PRIORITY_USER);
@@ -179,9 +131,25 @@ void waybar::Client::handleName(void * data, struct zxdg_output_v1 * /*xdg_
}
}
-void waybar::Client::handleDescription(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/,
- const char * /*description*/) {
- // Nothing here
+void waybar::Client::handleMonitorAdded(Glib::RefPtr monitor) {
+ auto &output = outputs_.emplace_back();
+ output.monitor = monitor;
+ handleOutput(output);
+}
+
+void waybar::Client::handleMonitorRemoved(Glib::RefPtr monitor) {
+ spdlog::debug("Output removed: {} {}", monitor->get_manufacturer(), monitor->get_model());
+ for (auto it = bars.begin(); it != bars.end();) {
+ if ((*it)->output->monitor == monitor) {
+ auto output_name = (*it)->output->name;
+ (*it)->window.close();
+ it = bars.erase(it);
+ spdlog::info("Bar removed from output: {}", output_name);
+ } else {
+ ++it;
+ }
+ }
+ outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; });
}
std::tuple waybar::Client::getConfigs(
@@ -240,6 +208,14 @@ void waybar::Client::bindInterfaces() {
if (layer_shell == nullptr || xdg_output_manager == nullptr) {
throw std::runtime_error("Failed to acquire required resources.");
}
+ // add existing outputs and subscribe to updates
+ for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) {
+ auto monitor = gdk_display->get_monitor(i);
+ handleMonitorAdded(monitor);
+ }
+ gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, &Client::handleMonitorAdded));
+ gdk_display->signal_monitor_removed().connect(
+ sigc::mem_fun(*this, &Client::handleMonitorRemoved));
}
int waybar::Client::main(int argc, char *argv[]) {
diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp
index 632abd9..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());
@@ -163,7 +173,12 @@ auto waybar::modules::Battery::update() -> void {
}
label_.set_tooltip_text(tooltip_text);
}
+ // Transform to lowercase
std::transform(status.begin(), status.end(), status.begin(), ::tolower);
+ // Replace space with dash
+ std::transform(status.begin(), status.end(), status.begin(), [](char ch) {
+ return ch == ' ' ? '-' : ch;
+ });
auto format = format_;
auto state = getState(capacity, true);
if (!old_status_.empty()) {
diff --git a/src/modules/clock.cpp b/src/modules/clock.cpp
index 4e05868..20aa1ce 100644
--- a/src/modules/clock.cpp
+++ b/src/modules/clock.cpp
@@ -1,8 +1,28 @@
#include "modules/clock.hpp"
-#include
+#include
+#include
+#ifdef HAVE_LANGINFO_1STDAY
+#include
+#include
+#endif
+
+using waybar::modules::waybar_time;
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
- : ALabel(config, "clock", id, "{:%H:%M}", 60) {
+ : ALabel(config, "clock", id, "{:%H:%M}", 60)
+ , fixed_time_zone_(false)
+{
+ if (config_["timezone"].isString()) {
+ time_zone_ = date::locate_zone(config_["timezone"].asString());
+ fixed_time_zone_ = true;
+ }
+
+ if (config_["locale"].isString()) {
+ locale_ = std::locale(config_["locale"].asString());
+ } else {
+ locale_ = std::locale("");
+ }
+
thread_ = [this] {
dp.emit();
auto now = std::chrono::system_clock::now();
@@ -13,21 +33,115 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
}
auto waybar::modules::Clock::update() -> void {
- tzset(); // Update timezone information
- auto now = std::chrono::system_clock::now();
- auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
- auto text = fmt::format(format_, localtime);
+ if (!fixed_time_zone_) {
+ // Time zone can change. Be sure to pick that.
+ time_zone_ = date::current_zone();
+ }
+ auto now = std::chrono::system_clock::now();
+ waybar_time wtime = {locale_,
+ date::make_zoned(time_zone_, date::floor(now))};
+
+ auto text = fmt::format(format_, wtime);
label_.set_markup(text);
if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) {
+ const auto calendar = calendar_text(wtime);
auto tooltip_format = config_["tooltip-format"].asString();
- auto tooltip_text = fmt::format(tooltip_format, localtime);
- label_.set_tooltip_text(tooltip_text);
+ auto tooltip_text = fmt::format(tooltip_format, wtime, fmt::arg("calendar", calendar));
+ label_.set_tooltip_markup(tooltip_text);
} else {
- label_.set_tooltip_text(text);
+ label_.set_tooltip_markup(text);
}
}
// Call parent update
ALabel::update();
}
+
+auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::string {
+ const auto daypoint = date::floor(wtime.ztime.get_local_time());
+ const auto ymd = date::year_month_day(daypoint);
+ if (cached_calendar_ymd_ == ymd) {
+ return cached_calendar_text_;
+ }
+
+ const date::year_month ym(ymd.year(), ymd.month());
+ const auto curr_day = ymd.day();
+
+ std::stringstream os;
+ const auto first_dow = first_day_of_week();
+ weekdays_header(first_dow, os);
+
+ // First week prefixed with spaces if needed.
+ auto wd = date::weekday(ym/1);
+ auto empty_days = (wd - first_dow).count();
+ if (empty_days > 0) {
+ os << std::string(empty_days * 3 - 1, ' ');
+ }
+ auto last_day = (ym/date::literals::last).day();
+ for (auto d = date::day(1); d <= last_day; ++d, ++wd) {
+ if (wd != first_dow) {
+ os << ' ';
+ } else if (unsigned(d) != 1) {
+ os << '\n';
+ }
+ if (d == curr_day) {
+ os << "" << date::format("%e", d) << "";
+ } else {
+ os << date::format("%e", d);
+ }
+ }
+
+ auto result = os.str();
+ cached_calendar_ymd_ = ymd;
+ cached_calendar_text_ = result;
+ return result;
+}
+
+auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void {
+ auto wd = first_dow;
+ do {
+ if (wd != first_dow) os << ' ';
+ Glib::ustring wd_ustring(date::format(locale_, "%a", wd));
+ auto wd_len = wd_ustring.length();
+ if (wd_len > 2) {
+ wd_ustring = wd_ustring.substr(0, 2);
+ wd_len = 2;
+ }
+ const std::string pad(2 - wd_len, ' ');
+ os << pad << wd_ustring;
+ } while (++wd != first_dow);
+ os << "\n";
+}
+
+#ifdef HAVE_LANGINFO_1STDAY
+template
+using deleter_from_fn = std::integral_constant;
+
+template
+using deleting_unique_ptr = std::unique_ptr>;
+#endif
+
+// Computations done similarly to Linux cal utility.
+auto waybar::modules::Clock::first_day_of_week() -> date::weekday {
+#ifdef HAVE_LANGINFO_1STDAY
+ deleting_unique_ptr::type, freelocale>
+ posix_locale{newlocale(LC_ALL, locale_.name().c_str(), nullptr)};
+ if (posix_locale) {
+ const int i = (std::intptr_t) nl_langinfo_l(_NL_TIME_WEEK_1STDAY, posix_locale.get());
+ auto ymd = date::year(i / 10000)/(i / 100 % 100)/(i % 100);
+ auto wd = date::weekday(ymd);
+ uint8_t j = *nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, posix_locale.get());
+ return wd + date::days(j - 1);
+ }
+#endif
+ return date::Sunday;
+}
+
+template <>
+struct fmt::formatter : fmt::formatter {
+ template
+ auto format(const waybar_time& t, FormatContext& ctx) {
+ return format_to(ctx.out(), "{}", date::format(t.locale, fmt::to_string(tm_format), t.ztime));
+ }
+};
diff --git a/src/modules/custom.cpp b/src/modules/custom.cpp
index 7a66447..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()));
+ }
};
}
diff --git a/src/modules/memory.cpp b/src/modules/memory.cpp
index c5b8b40..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_,
@@ -35,7 +47,6 @@ auto waybar::modules::Memory::update() -> void {
}
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_);
@@ -46,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 6dca5ee..e37b687 100644
--- a/src/modules/mpd.cpp
+++ b/src/modules/mpd.cpp
@@ -143,7 +143,9 @@ void waybar::modules::MPD::setLabel() {
if (playing()) {
label_.get_style_context()->add_class("playing");
label_.get_style_context()->remove_class("paused");
- } else {
+ } else if (paused()) {
+ format =
+ config_["format-paused"].isString() ? config_["format-paused"].asString() : config_["format"].asString();
label_.get_style_context()->add_class("paused");
label_.get_style_context()->remove_class("playing");
}
@@ -349,3 +351,5 @@ bool waybar::modules::MPD::stopped() {
}
bool waybar::modules::MPD::playing() { return connection_ != nullptr && state_ == MPD_STATE_PLAY; }
+
+bool waybar::modules::MPD::paused() { return connection_ != nullptr && state_ == MPD_STATE_PAUSE; }
diff --git a/src/modules/network.cpp b/src/modules/network.cpp
index 54a92ba..a98e18d 100644
--- a/src/modules/network.cpp
+++ b/src/modules/network.cpp
@@ -2,6 +2,7 @@
#include
#include
#include
+#include
#include "util/format.hpp"
@@ -278,8 +279,13 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")),
fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / interval_.count(), "o/s")),
fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / interval_.count(), "o/s")));
- if (text != label_.get_label()) {
+ if (text.compare(label_.get_label()) != 0) {
label_.set_markup(text);
+ if (text.empty()) {
+ event_box_.hide();
+ } else {
+ event_box_.show();
+ }
}
if (tooltipEnabled()) {
if (tooltip_format.empty() && config_["tooltip-format"].isString()) {
@@ -437,7 +443,6 @@ out:
}
void waybar::modules::Network::getInterfaceAddress() {
- unsigned int cidrRaw;
struct ifaddrs *ifaddr, *ifa;
cidr_ = 0;
int success = getifaddrs(&ifaddr);
@@ -449,18 +454,34 @@ void waybar::modules::Network::getInterfaceAddress() {
if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_ &&
ifa->ifa_name == ifname_) {
char ipaddr[INET6_ADDRSTRLEN];
- ipaddr_ = inet_ntop(family_,
- &reinterpret_cast(ifa->ifa_addr)->sin_addr,
- ipaddr,
- INET6_ADDRSTRLEN);
char netmask[INET6_ADDRSTRLEN];
- auto net_addr = reinterpret_cast(ifa->ifa_netmask);
- netmask_ = inet_ntop(family_, &net_addr->sin_addr, netmask, INET6_ADDRSTRLEN);
- cidrRaw = net_addr->sin_addr.s_addr;
unsigned int cidr = 0;
- while (cidrRaw) {
- cidr += cidrRaw & 1;
- cidrRaw >>= 1;
+ if (family_ == AF_INET) {
+ ipaddr_ = inet_ntop(AF_INET,
+ &reinterpret_cast(ifa->ifa_addr)->sin_addr,
+ ipaddr,
+ INET_ADDRSTRLEN);
+ auto net_addr = reinterpret_cast(ifa->ifa_netmask);
+ netmask_ = inet_ntop(AF_INET, &net_addr->sin_addr, netmask, INET_ADDRSTRLEN);
+ unsigned int cidrRaw = net_addr->sin_addr.s_addr;
+ while (cidrRaw) {
+ cidr += cidrRaw & 1;
+ cidrRaw >>= 1;
+ }
+ } else {
+ ipaddr_ = inet_ntop(AF_INET6,
+ &reinterpret_cast(ifa->ifa_addr)->sin6_addr,
+ ipaddr,
+ INET6_ADDRSTRLEN);
+ auto net_addr = reinterpret_cast(ifa->ifa_netmask);
+ netmask_ = inet_ntop(AF_INET6, &net_addr->sin6_addr, netmask, INET6_ADDRSTRLEN);
+ for (size_t i = 0; i < sizeof(net_addr->sin6_addr.s6_addr); ++i) {
+ unsigned char cidrRaw = net_addr->sin6_addr.s6_addr[i];
+ while (cidrRaw) {
+ cidr += cidrRaw & 1;
+ cidrRaw >>= 1;
+ }
+ }
}
cidr_ = cidr;
break;
diff --git a/src/modules/pulseaudio.cpp b/src/modules/pulseaudio.cpp
index 06c0ad8..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);
@@ -52,7 +52,8 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) {
pa_context_set_subscribe_callback(c, subscribeCb, data);
pa_context_subscribe(
c,
- static_cast(static_cast(PA_SUBSCRIPTION_MASK_SINK) |
+ static_cast(static_cast(PA_SUBSCRIPTION_MASK_SERVER) |
+ static_cast(PA_SUBSCRIPTION_MASK_SINK) |
static_cast(PA_SUBSCRIPTION_MASK_SOURCE)),
nullptr,
nullptr);
@@ -109,7 +110,9 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context * conte
if (operation != PA_SUBSCRIPTION_EVENT_CHANGE) {
return;
}
- if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
+ if (facility == PA_SUBSCRIPTION_EVENT_SERVER) {
+ pa_context_get_server_info(context, serverInfoCb, data);
+ } else if (facility == PA_SUBSCRIPTION_EVENT_SINK) {
pa_context_get_sink_info_by_index(context, idx, sinkInfoCb, data);
} else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE) {
pa_context_get_source_info_by_index(context, idx, sourceInfoCb, data);
@@ -131,15 +134,15 @@ void waybar::modules::Pulseaudio::volumeModifyCb(pa_context *c, int success, voi
*/
void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const pa_source_info *i,
int /*eol*/, void *data) {
- if (i != nullptr) {
- auto self = static_cast(data);
+ auto pa = static_cast(data);
+ if (i != nullptr && pa->default_source_name_ == i->name) {
auto source_volume = static_cast(pa_cvolume_avg(&(i->volume))) / float{PA_VOLUME_NORM};
- self->source_volume_ = std::round(source_volume * 100.0F);
- self->source_idx_ = i->index;
- self->source_muted_ = i->mute != 0;
- self->source_desc_ = i->description;
- self->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown";
- self->dp.emit();
+ pa->source_volume_ = std::round(source_volume * 100.0F);
+ pa->source_idx_ = i->index;
+ pa->source_muted_ = i->mute != 0;
+ pa->source_desc_ = i->description;
+ pa->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown";
+ pa->dp.emit();
}
}
@@ -147,9 +150,9 @@ void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const p
* Called when the requested sink information is ready.
*/
void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i,
- int /*eol*/, void * data) {
- if (i != nullptr) {
- auto pa = static_cast(data);
+ int /*eol*/, void *data) {
+ auto pa = static_cast(data);
+ if (i != nullptr && pa->default_sink_name_ == i->name) {
pa->pa_volume_ = i->volume;
float volume = static_cast(pa_cvolume_avg(&(pa->pa_volume_))) / float{PA_VOLUME_NORM};
pa->sink_idx_ = i->index;
@@ -158,6 +161,9 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_
pa->desc_ = i->description;
pa->monitor_ = i->monitor_source_name;
pa->port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown";
+ if (auto ff = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_FORM_FACTOR)) {
+ pa->form_factor_ = ff;
+ }
pa->dp.emit();
}
}
@@ -168,16 +174,20 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_
*/
void waybar::modules::Pulseaudio::serverInfoCb(pa_context *context, const pa_server_info *i,
void *data) {
+ auto pa = static_cast(data);
+ pa->default_sink_name_ = i->default_sink_name;
+ pa->default_source_name_ = i->default_source_name;
+
pa_context_get_sink_info_by_name(context, i->default_sink_name, sinkInfoCb, data);
pa_context_get_source_info_by_name(context, i->default_source_name, sourceInfoCb, data);
}
static const std::array ports = {
- "headphones",
+ "headphone",
"speaker",
"hdmi",
"headset",
- "handsfree",
+ "hands-free",
"portable",
"car",
"hifi",
@@ -185,7 +195,7 @@ static const std::array ports = {
};
const std::string waybar::modules::Pulseaudio::getPortIcon() const {
- std::string nameLC = port_name_;
+ std::string nameLC = port_name_ + form_factor_;
std::transform(nameLC.begin(), nameLC.end(), nameLC.begin(), ::tolower);
for (auto const &port : ports) {
if (nameLC.find(port) != std::string::npos) {
@@ -197,21 +207,27 @@ const std::string waybar::modules::Pulseaudio::getPortIcon() const {
auto waybar::modules::Pulseaudio::update() -> void {
auto format = 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 (!alt_) {
+ 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_) {
+ // 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 {
+ label_.get_style_context()->remove_class("muted");
+ }
+ format =
+ config_[format_name].isString() ? config_[format_name].asString() : format;
}
- if (muted_ ) {
- format_name = format_name + "-muted";
- label_.get_style_context()->add_class("muted");
- } else {
- label_.get_style_context()->remove_class("muted");
- }
- 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()) {
diff --git a/src/modules/sni/item.cpp b/src/modules/sni/item.cpp
index bcc66e2..b298e44 100644
--- a/src/modules/sni/item.cpp
+++ b/src/modules/sni/item.cpp
@@ -265,7 +265,11 @@ void Item::updateImage() {
if (pixbuf->gobj() != nullptr) {
// An icon specified by path and filename may be the wrong size for
// the tray
- pixbuf = pixbuf->scale_simple(icon_size, icon_size, Gdk::InterpType::INTERP_BILINEAR);
+ // Keep the aspect ratio and scale to make the height equal to icon_size
+ // If people have non square icons, assume they want it to grow in width not height
+ int width = icon_size * pixbuf->get_width() / pixbuf->get_height();
+
+ pixbuf = pixbuf->scale_simple(width, icon_size, Gdk::InterpType::INTERP_BILINEAR);
image.set(pixbuf);
}
} else {
diff --git a/src/modules/sni/tray.cpp b/src/modules/sni/tray.cpp
index a698a97..e16837f 100644
--- a/src/modules/sni/tray.cpp
+++ b/src/modules/sni/tray.cpp
@@ -6,7 +6,7 @@ namespace waybar::modules::SNI {
Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config)
: AModule(config, "tray", id),
box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0),
- watcher_(nb_hosts_),
+ watcher_(SNI::Watcher::getInstance()),
host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1)) {
spdlog::warn(
diff --git a/src/modules/sni/watcher.cpp b/src/modules/sni/watcher.cpp
index 1db3708..73b3eac 100644
--- a/src/modules/sni/watcher.cpp
+++ b/src/modules/sni/watcher.cpp
@@ -3,14 +3,13 @@
using namespace waybar::modules::SNI;
-Watcher::Watcher(std::size_t id)
+Watcher::Watcher()
: bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher",
sigc::mem_fun(*this, &Watcher::busAcquired),
Gio::DBus::SlotNameAcquired(), Gio::DBus::SlotNameLost(),
Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE)),
- watcher_id_(id),
watcher_(sn_watcher_skeleton_new()) {}
Watcher::~Watcher() {
@@ -23,6 +22,7 @@ Watcher::~Watcher() {
g_slist_free_full(items_, gfWatchFree);
items_ = nullptr;
}
+ Gio::DBus::unown_name(bus_name_id_);
auto iface = G_DBUS_INTERFACE_SKELETON(watcher_);
g_dbus_interface_skeleton_unexport(iface);
}
@@ -34,7 +34,7 @@ void Watcher::busAcquired(const Glib::RefPtr& conn, Glib:
if (error != nullptr) {
// Don't print an error when a watcher is already present
if (error->code != 2) {
- spdlog::error("Watcher {}: {}", watcher_id_, error->message);
+ spdlog::error("Watcher: {}", error->message);
}
g_error_free(error);
return;
diff --git a/src/modules/sway/ipc/client.cpp b/src/modules/sway/ipc/client.cpp
index eae6c76..58aed60 100644
--- a/src/modules/sway/ipc/client.cpp
+++ b/src/modules/sway/ipc/client.cpp
@@ -10,19 +10,23 @@ Ipc::Ipc() {
}
Ipc::~Ipc() {
- // To fail the IPC header
- write(fd_, "close-sway-ipc", 14);
- write(fd_event_, "close-sway-ipc", 14);
+ thread_.stop();
+
if (fd_ > 0) {
+ // To fail the IPC header
+ write(fd_, "close-sway-ipc", 14);
close(fd_);
fd_ = -1;
}
if (fd_event_ > 0) {
+ write(fd_event_, "close-sway-ipc", 14);
close(fd_event_);
fd_event_ = -1;
}
}
+void Ipc::setWorker(std::function&& func) { thread_ = func; }
+
const std::string Ipc::getSocketPath() const {
const char* env = getenv("SWAYSOCK");
if (env != nullptr) {
diff --git a/src/modules/sway/mode.cpp b/src/modules/sway/mode.cpp
index 33e4f72..605271c 100644
--- a/src/modules/sway/mode.cpp
+++ b/src/modules/sway/mode.cpp
@@ -8,7 +8,13 @@ Mode::Mode(const std::string& id, const Json::Value& config)
ipc_.subscribe(R"(["mode"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent));
// Launch worker
- worker();
+ ipc_.setWorker([this] {
+ try {
+ ipc_.handleEvent();
+ } catch (const std::exception& e) {
+ spdlog::error("Mode: {}", e.what());
+ }
+ });
dp.emit();
}
@@ -31,16 +37,6 @@ void Mode::onEvent(const struct Ipc::ipc_response& res) {
}
}
-void Mode::worker() {
- thread_ = [this] {
- try {
- ipc_.handleEvent();
- } catch (const std::exception& e) {
- spdlog::error("Mode: {}", e.what());
- }
- };
-}
-
auto Mode::update() -> void {
if (mode_.empty()) {
event_box_.hide();
diff --git a/src/modules/sway/window.cpp b/src/modules/sway/window.cpp
index 1f90eba..f10bf1c 100644
--- a/src/modules/sway/window.cpp
+++ b/src/modules/sway/window.cpp
@@ -11,7 +11,13 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
// Get Initial focused window
getTree();
// Launch worker
- worker();
+ ipc_.setWorker([this] {
+ try {
+ ipc_.handleEvent();
+ } catch (const std::exception& e) {
+ spdlog::error("Window: {}", e.what());
+ }
+ });
}
void Window::onEvent(const struct Ipc::ipc_response& res) { getTree(); }
@@ -28,16 +34,6 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
}
}
-void Window::worker() {
- thread_ = [this] {
- try {
- ipc_.handleEvent();
- } catch (const std::exception& e) {
- spdlog::error("Window: {}", e.what());
- }
- };
-}
-
auto Window::update() -> void {
if (!old_app_id_.empty()) {
bar_.window.get_style_context()->remove_class(old_app_id_);
diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp
index d0c8cc3..91df113 100644
--- a/src/modules/sway/workspaces.cpp
+++ b/src/modules/sway/workspaces.cpp
@@ -22,7 +22,13 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value
window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll));
}
// Launch worker
- worker();
+ ipc_.setWorker([this] {
+ try {
+ ipc_.handleEvent();
+ } catch (const std::exception &e) {
+ spdlog::error("Workspaces: {}", e.what());
+ }
+ });
}
void Workspaces::onEvent(const struct Ipc::ipc_response &res) {
@@ -102,16 +108,6 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
}
}
-void Workspaces::worker() {
- thread_ = [this] {
- try {
- ipc_.handleEvent();
- } catch (const std::exception &e) {
- spdlog::error("Workspaces: {}", e.what());
- }
- };
-}
-
bool Workspaces::filterButtons() {
bool needReorder = false;
for (auto it = buttons_.begin(); it != buttons_.end();) {
@@ -161,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()) {
@@ -211,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 5508fd2..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);
diff --git a/subprojects/date.wrap b/subprojects/date.wrap
new file mode 100644
index 0000000..ea73f0f
--- /dev/null
+++ b/subprojects/date.wrap
@@ -0,0 +1,9 @@
+[wrap-file]
+source_url=https://github.com/HowardHinnant/date/archive/v2.4.1.tar.gz
+source_filename=date-2.4.1.tar.gz
+source_hash=98907d243397483bd7ad889bf6c66746db0d7d2a39cc9aacc041834c40b65b98
+directory=date-2.4.1
+
+patch_url = https://github.com/mesonbuild/hinnant-date/releases/download/2.4.1-1/hinnant-date.zip
+patch_filename = hinnant-date-2.4.1-1-wrap.zip
+patch_hash = 2061673a6f8e6d63c3a40df4da58fa2b3de2835fd9b3e74649e8279599f3a8f6
diff --git a/subprojects/fmt.wrap b/subprojects/fmt.wrap
index b60b22a..eb79283 100644
--- a/subprojects/fmt.wrap
+++ b/subprojects/fmt.wrap
@@ -5,6 +5,6 @@ source_url = https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz
source_filename = fmt-5.3.0.tar.gz
source_hash = defa24a9af4c622a7134076602070b45721a43c51598c8456ec6f2c4dbb51c89
-patch_url = https://wrapdb.mesonbuild.com/v1/projects/fmt/5.3.0/1/get_zip
+patch_url = https://github.com/mesonbuild/fmt/releases/download/5.3.0-1/fmt.zip
patch_filename = fmt-5.3.0-1-wrap.zip
patch_hash = 18f21a3b8833949c35d4ac88a7059577d5fa24b98786e4b1b2d3d81bb811440f
\ No newline at end of file
diff --git a/subprojects/gtk-layer-shell.wrap b/subprojects/gtk-layer-shell.wrap
new file mode 100644
index 0000000..b826ab9
--- /dev/null
+++ b/subprojects/gtk-layer-shell.wrap
@@ -0,0 +1,5 @@
+[wrap-file]
+directory = gtk-layer-shell-0.1.0
+source_filename = gtk-layer-shell-0.1.0.tar.gz
+source_hash = f7569e27ae30b1a94c3ad6c955cf56240d6bc272b760d9d266ce2ccdb94a5cf0
+source_url = https://github.com/wmww/gtk-layer-shell/archive/v0.1.0/gtk-layer-shell-0.1.0.tar.gz
diff --git a/subprojects/spdlog.wrap b/subprojects/spdlog.wrap
index 9dac4d8..750036b 100644
--- a/subprojects/spdlog.wrap
+++ b/subprojects/spdlog.wrap
@@ -5,6 +5,6 @@ source_url = https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz
source_filename = v1.3.1.tar.gz
source_hash = 160845266e94db1d4922ef755637f6901266731c4cb3b30b45bf41efa0e6ab70
-patch_url = https://wrapdb.mesonbuild.com/v1/projects/spdlog/1.3.1/1/get_zip
+patch_url = https://github.com/mesonbuild/spdlog/releases/download/1.3.1-1/spdlog.zip
patch_filename = spdlog-1.3.1-1-wrap.zip
patch_hash = 715a0229781019b853d409cc0bf891ee4b9d3a17bec0cf87f4ad30b28bbecc87