Compare commits

..

44 Commits

Author SHA1 Message Date
9eb6c4e296 chore: v0.9.16 2022-11-24 20:34:12 +01:00
748c6125d0 Merge pull request #1810 from pinselimo/revert-1120 2022-11-24 15:20:29 +01:00
235861fd3d button: Remove AButton class 2022-11-24 13:08:16 +01:00
5e9bbe5c76 modules: Revert button to label 2022-11-24 13:08:16 +01:00
74fa131ebe Merge pull request #1809 from herlev/hyprland-named-workspace-crash 2022-11-24 07:46:17 +01:00
2c7cb0e9d4 Fix crashes when using named workspaces in Hyprland
The first crash occurs when trying to parse the
ID of a workspace as an uint, since named
workspaces has negative IDs. This is fixed by
using ints for workspace IDs instead of uints.

The second crash occurs when converting a
workspace name that isn't a number to an integer.
This is fixed by wrapping std::stoi in a try
block and only sorting by number, when both names
can successfully be converted to integers.
2022-11-24 02:16:44 +01:00
ce8ae5bf17 Merge pull request #1748 from lilydjwg/fix-zombies
fixes https://github.com/Alexays/Waybar/issues/1713
2022-11-23 21:31:47 +01:00
062e7bb9b4 Merge pull request #1797 from smoak/wireplumber-support 2022-11-22 12:44:39 +01:00
c2f98d07ef feat: wireplumber support
Adds basic support for showing volume via wireplumber. Allows specifying
the node-id or falling back to the default Audio/Sink node id if node-id
is not set. If tooltip on hover is enabled, will show `{node_name}` by
default otherwise `tooltip-format`.

Format replacements:

`{volume}` - Volume in percentage
`{node_name}` - The node's nickname (`node.nick` property)
2022-11-16 23:23:07 -08:00
833dcc1bb8 Merge pull request #1795 from schmidma/bluez-output-detection 2022-11-16 19:07:46 +01:00
8c24e26f0e Recognize outputs with 'bluez' in monitor name as bluetooth class 2022-11-16 19:01:12 +01:00
56b4a11a9c Merge pull request #1793 from Dordovel/master 2022-11-16 07:41:29 +01:00
1111763251 added path settings 2022-11-16 08:04:18 +03:00
769858fbb4 fix call parent event handle, added commang to open user folder 2022-11-15 16:15:26 +03:00
2695815bcc Merge pull request #1787 from Dordovel/master 2022-11-15 08:41:12 +01:00
49afb87e34 Merge branch 'Alexays:master' into master 2022-11-13 16:17:04 +03:00
5250123dcb Merge pull request #1788 from grfrederic/normalize-battery-capacity 2022-11-12 23:41:00 +01:00
c0b3e9ee35 normalize capacity by number of batteries 2022-11-12 22:39:53 +01:00
454ba610f4 clicking on the user label opens the default file manager 2022-11-11 15:15:12 +03:00
3718902b9d Merge pull request #1785 from ElJeffe/hyprland_monitor_remove 2022-11-10 09:21:52 +01:00
9f0a14c22b make linter happy 2022-11-10 09:19:49 +01:00
781da93f3d Merge pull request #1780 from ElJeffe/hyprland_monitor_remove 2022-11-09 23:09:30 +01:00
8f4f67f69f Do not crash when a monitor is removed 2022-11-09 09:34:19 +01:00
8be5bab8ad Merge pull request #1734 from baltitenger/backlight-hide-when-powered-off
closes https://github.com/Alexays/Waybar/issues/393
2022-11-07 14:09:54 +01:00
d02e23c759 feat(backlight): hide if the display is powered off 2022-11-07 13:57:21 +01:00
d2b22c6ec5 fix: lint 2022-11-07 09:23:47 +01:00
ed898cd211 Merge pull request #1773 from kj/backlight-format-states 2022-11-07 09:23:17 +01:00
1a1c617520 Merge pull request #1772 from kj/fix-states-documentation 2022-11-07 09:13:41 +01:00
253222d31c Make backlight module respect format-<state> config 2022-11-07 21:06:16 +13:00
51e6fc6250 Fix states documentation 2022-11-07 20:30:01 +13:00
af1668dfd0 Merge pull request #1770 from Scrumplex/fix-mpd-double-encode 2022-11-06 09:52:31 +01:00
cf5877073a fix: don't escape mpd label twice
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2022-11-05 20:23:00 +01:00
bd567800c9 Merge pull request #1769 from ericliou/master 2022-11-04 22:01:36 +01:00
6477e539d0 Battery: Plugged status has higher priority 2022-11-04 20:01:53 +00:00
242e19a07d Merge pull request #1767 from b1rger/fix-typos 2022-11-04 15:07:31 +01:00
0e53c37d6b Fix typos in manual pages 2022-11-04 15:03:10 +01:00
3030850b22 refactor: inherit disabled button 2022-11-04 08:39:59 +01:00
92cc01f401 fix: label default style 2022-11-03 15:53:45 +01:00
d48eebd4d3 fix: use GTK_STYLE_PROVIDER_PRIORITY_APPLICATION 2022-11-03 14:10:18 +01:00
eb705533b5 feat: jsoncpp wrap 2022-11-03 14:08:22 +01:00
3cf027fc56 fix: button default style 2022-11-03 14:04:29 +01:00
09120caf17 Merge pull request #1762 from jpalus/jsoncpp-version 2022-11-03 11:02:19 +01:00
73495df377 build: require jsoncpp >= 1.9.2
with #1719 Waybar started using Json::Value.as() available since jsoncpp
1.9.2.
2022-11-03 10:59:03 +01:00
31137c30fb fix custom module leaves zombie processes behind when bars are removed
fixes #1713.
2022-10-27 18:12:14 +08:00
68 changed files with 701 additions and 466 deletions

View File

@ -1,35 +0,0 @@
#pragma once
#include <glibmm/markup.h>
#include <gtkmm/button.h>
#include <gtkmm/cssprovider.h>
#include <gtkmm/label.h>
#include <json/json.h>
#include "AModule.hpp"
namespace waybar {
class AButton : public AModule {
public:
AButton(const Json::Value &, const std::string &, const std::string &, const std::string &format,
uint16_t interval = 0, bool ellipsize = false, bool enable_click = false,
bool enable_scroll = false);
virtual ~AButton() = default;
virtual auto update() -> void;
virtual std::string getIcon(uint16_t, const std::string &alt = "", uint16_t max = 0);
virtual std::string getIcon(uint16_t, const std::vector<std::string> &alts, uint16_t max = 0);
protected:
Gtk::Button button_ = Gtk::Button(name_);
Gtk::Label *label_ = (Gtk::Label *)button_.get_child();
std::string format_;
const std::chrono::seconds interval_;
bool alt_ = false;
std::string default_format_;
virtual bool handleToggle(GdkEventButton *const &e);
virtual std::string getState(uint8_t value, bool lesser = false);
};
} // namespace waybar

View File

@ -72,6 +72,9 @@
#ifdef HAVE_LIBJACK #ifdef HAVE_LIBJACK
#include "modules/jack.hpp" #include "modules/jack.hpp"
#endif #endif
#ifdef HAVE_LIBWIREPLUMBER
#include "modules/wireplumber.hpp"
#endif
#include "bar.hpp" #include "bar.hpp"
#include "modules/custom.hpp" #include "modules/custom.hpp"
#include "modules/temperature.hpp" #include "modules/temperature.hpp"

View File

@ -5,7 +5,7 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
@ -14,16 +14,18 @@ struct udev_device;
namespace waybar::modules { namespace waybar::modules {
class Backlight : public AButton { class Backlight : public ALabel {
class BacklightDev { class BacklightDev {
public: public:
BacklightDev() = default; BacklightDev() = default;
BacklightDev(std::string name, int actual, int max); BacklightDev(std::string name, int actual, int max, bool powered);
std::string_view name() const; std::string_view name() const;
int get_actual() const; int get_actual() const;
void set_actual(int actual); void set_actual(int actual);
int get_max() const; int get_max() const;
void set_max(int max); void set_max(int max);
bool get_powered() const;
void set_powered(bool powered);
friend inline bool operator==(const BacklightDev &lhs, const BacklightDev &rhs) { friend inline bool operator==(const BacklightDev &lhs, const BacklightDev &rhs) {
return lhs.name_ == rhs.name_ && lhs.actual_ == rhs.actual_ && lhs.max_ == rhs.max_; return lhs.name_ == rhs.name_ && lhs.actual_ == rhs.actual_ && lhs.max_ == rhs.max_;
} }
@ -32,6 +34,7 @@ class Backlight : public AButton {
std::string name_; std::string name_;
int actual_ = 1; int actual_ = 1;
int max_ = 1; int max_ = 1;
bool powered_ = true;
}; };
public: public:

View File

@ -15,7 +15,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
@ -26,7 +26,7 @@ namespace fs = std::experimental::filesystem;
namespace fs = std::filesystem; namespace fs = std::filesystem;
#endif #endif
class Battery : public AButton { class Battery : public ALabel {
public: public:
Battery(const std::string&, const Json::Value&); Battery(const std::string&, const Json::Value&);
~Battery(); ~Battery();

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "AButton.hpp" #include "ALabel.hpp"
#ifdef WANT_RFKILL #ifdef WANT_RFKILL
#include "util/rfkill.hpp" #include "util/rfkill.hpp"
#endif #endif
@ -12,7 +12,7 @@
namespace waybar::modules { namespace waybar::modules {
class Bluetooth : public AButton { class Bluetooth : public ALabel {
struct ControllerInfo { struct ControllerInfo {
std::string path; std::string path;
std::string address; std::string address;

View File

@ -2,7 +2,7 @@
#include <date/tz.h> #include <date/tz.h>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar { namespace waybar {
@ -14,7 +14,7 @@ namespace modules {
const std::string kCalendarPlaceholder = "calendar"; const std::string kCalendarPlaceholder = "calendar";
const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list"; const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list";
class Clock : public AButton { class Clock : public ALabel {
public: public:
Clock(const std::string&, const Json::Value&); Clock(const std::string&, const Json::Value&);
~Clock() = default; ~Clock() = default;

View File

@ -9,12 +9,12 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Cpu : public AButton { class Cpu : public ALabel {
public: public:
Cpu(const std::string&, const Json::Value&); Cpu(const std::string&, const Json::Value&);
~Cpu() = default; ~Cpu() = default;

View File

@ -5,14 +5,14 @@
#include <csignal> #include <csignal>
#include <string> #include <string>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/command.hpp" #include "util/command.hpp"
#include "util/json.hpp" #include "util/json.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Custom : public AButton { class Custom : public ALabel {
public: public:
Custom(const std::string&, const std::string&, const Json::Value&); Custom(const std::string&, const std::string&, const Json::Value&);
~Custom(); ~Custom();

View File

@ -5,13 +5,13 @@
#include <fstream> #include <fstream>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/format.hpp" #include "util/format.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Disk : public AButton { class Disk : public ALabel {
public: public:
Disk(const std::string&, const Json::Value&); Disk(const std::string&, const Json::Value&);
~Disk() = default; ~Disk() = default;

View File

@ -1,17 +1,25 @@
#pragma once #pragma once
#include <deque>
#include <functional> #include <functional>
#include <list>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <thread> #include <thread>
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
class EventHandler {
public:
virtual void onEvent(const std::string& ev) = 0;
virtual ~EventHandler() = default;
};
class IPC { class IPC {
public: public:
IPC() { startIPC(); } IPC() { startIPC(); }
void registerForIPC(const std::string&, std::function<void(const std::string&)>); void registerForIPC(const std::string&, EventHandler*);
void unregisterForIPC(EventHandler*);
std::string getSocket1Reply(const std::string& rq); std::string getSocket1Reply(const std::string& rq);
@ -20,7 +28,7 @@ class IPC {
void parseIPC(const std::string&); void parseIPC(const std::string&);
std::mutex callbackMutex; std::mutex callbackMutex;
std::deque<std::pair<std::string, std::function<void(const std::string&)>>> callbacks; std::list<std::pair<std::string, EventHandler*>> callbacks;
}; };
inline std::unique_ptr<IPC> gIPC; inline std::unique_ptr<IPC> gIPC;

View File

@ -1,16 +1,16 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "AButton.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "modules/hyprland/backend.hpp" #include "modules/hyprland/backend.hpp"
#include "util/json.hpp" #include "util/json.hpp"
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
class Language : public waybar::AButton { class Language : public waybar::ALabel, public EventHandler {
public: public:
Language(const std::string&, const waybar::Bar&, const Json::Value&); Language(const std::string&, const waybar::Bar&, const Json::Value&);
~Language() = default; ~Language();
auto update() -> void; auto update() -> void;

View File

@ -9,16 +9,16 @@
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
class Window : public waybar::ALabel { class Window : public waybar::ALabel, public EventHandler {
public: public:
Window(const std::string&, const waybar::Bar&, const Json::Value&); Window(const std::string&, const waybar::Bar&, const Json::Value&);
~Window() = default; ~Window();
auto update() -> void; auto update() -> void;
private: private:
uint getActiveWorkspaceID(std::string); int getActiveWorkspaceID(std::string);
std::string getLastWindowTitle(uint); std::string getLastWindowTitle(int);
void onEvent(const std::string&); void onEvent(const std::string&);
bool separate_outputs; bool separate_outputs;

View File

@ -2,13 +2,13 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "AButton.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
namespace waybar::modules { namespace waybar::modules {
class IdleInhibitor : public AButton { class IdleInhibitor : public ALabel {
sigc::connection timeout_; sigc::connection timeout_;
public: public:

View File

@ -4,12 +4,12 @@
#include <memory> #include <memory>
#include "AButton.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
namespace waybar::modules { namespace waybar::modules {
class Inhibitor : public AButton { class Inhibitor : public ALabel {
public: public:
Inhibitor(const std::string&, const waybar::Bar&, const Json::Value&); Inhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
~Inhibitor() override; ~Inhibitor() override;

View File

@ -5,12 +5,12 @@
#include <fstream> #include <fstream>
#include <unordered_map> #include <unordered_map>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Memory : public AButton { class Memory : public ALabel {
public: public:
Memory(const std::string&, const Json::Value&); Memory(const std::string&, const Json::Value&);
~Memory() = default; ~Memory() = default;

View File

@ -7,12 +7,12 @@
#include <condition_variable> #include <condition_variable>
#include <thread> #include <thread>
#include "AButton.hpp" #include "ALabel.hpp"
#include "modules/mpd/state.hpp" #include "modules/mpd/state.hpp"
namespace waybar::modules { namespace waybar::modules {
class MPD : public AButton { class MPD : public ALabel {
friend class detail::Context; friend class detail::Context;
// State machine // State machine

View File

@ -7,7 +7,7 @@
#include <condition_variable> #include <condition_variable>
#include <thread> #include <thread>
#include "AButton.hpp" #include "ALabel.hpp"
namespace waybar::modules { namespace waybar::modules {
class MPD; class MPD;

View File

@ -10,7 +10,7 @@
#include <optional> #include <optional>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
#ifdef WANT_RFKILL #ifdef WANT_RFKILL
#include "util/rfkill.hpp" #include "util/rfkill.hpp"
@ -18,7 +18,7 @@
namespace waybar::modules { namespace waybar::modules {
class Network : public AButton { class Network : public ALabel {
public: public:
Network(const std::string&, const Json::Value&); Network(const std::string&, const Json::Value&);
~Network(); ~Network();

View File

@ -7,11 +7,11 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include "AButton.hpp" #include "ALabel.hpp"
namespace waybar::modules { namespace waybar::modules {
class Pulseaudio : public AButton { class Pulseaudio : public ALabel {
public: public:
Pulseaudio(const std::string&, const Json::Value&); Pulseaudio(const std::string&, const Json::Value&);
~Pulseaudio(); ~Pulseaudio();

View File

@ -2,12 +2,12 @@
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Clock : public AButton { class Clock : public ALabel {
public: public:
Clock(const std::string&, const Json::Value&); Clock(const std::string&, const Json::Value&);
~Clock() = default; ~Clock() = default;

View File

@ -4,12 +4,12 @@
#include <vector> #include <vector>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Sndio : public AButton { class Sndio : public ALabel {
public: public:
Sndio(const std::string &, const Json::Value &); Sndio(const std::string &, const Json::Value &);
~Sndio(); ~Sndio();

View File

@ -6,7 +6,7 @@
#include <map> #include <map>
#include <string> #include <string>
#include "AButton.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
@ -14,7 +14,7 @@
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Language : public AButton, public sigc::trackable { class Language : public ALabel, public sigc::trackable {
public: public:
Language(const std::string& id, const Json::Value& config); Language(const std::string& id, const Json::Value& config);
~Language() = default; ~Language() = default;

View File

@ -2,7 +2,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include "AButton.hpp" #include "ALabel.hpp"
#include "bar.hpp" #include "bar.hpp"
#include "client.hpp" #include "client.hpp"
#include "modules/sway/ipc/client.hpp" #include "modules/sway/ipc/client.hpp"
@ -10,7 +10,7 @@
namespace waybar::modules::sway { namespace waybar::modules::sway {
class Mode : public AButton, public sigc::trackable { class Mode : public ALabel, public sigc::trackable {
public: public:
Mode(const std::string&, const Json::Value&); Mode(const std::string&, const Json::Value&);
~Mode() = default; ~Mode() = default;

View File

@ -4,12 +4,12 @@
#include <fstream> #include <fstream>
#include "AButton.hpp" #include "ALabel.hpp"
#include "util/sleeper_thread.hpp" #include "util/sleeper_thread.hpp"
namespace waybar::modules { namespace waybar::modules {
class Temperature : public AButton { class Temperature : public ALabel {
public: public:
Temperature(const std::string&, const Json::Value&); Temperature(const std::string&, const Json::Value&);
~Temperature() = default; ~Temperature() = default;

View File

@ -14,18 +14,18 @@ class User : public AIconLabel {
~User() = default; ~User() = default;
auto update() -> void; auto update() -> void;
bool handleToggle(GdkEventButton* const& e) override;
private: private:
util::SleeperThread thread_; util::SleeperThread thread_;
Glib::RefPtr<Gdk::Pixbuf> pixbuf_;
static constexpr inline int defaultUserImageWidth_ = 20; static constexpr inline int defaultUserImageWidth_ = 20;
static constexpr inline int defaultUserImageHeight_ = 20; static constexpr inline int defaultUserImageHeight_ = 20;
long uptime_as_seconds(); long uptime_as_seconds();
std::string get_user_login(); std::string get_user_login() const;
std::string get_user_home_dir(); std::string get_user_home_dir() const;
std::string get_default_user_avatar_path(); std::string get_default_user_avatar_path() const;
void init_default_user_avatar(int width, int height); void init_default_user_avatar(int width, int height);
void init_user_avatar(const std::string& path, int width, int height); void init_user_avatar(const std::string& path, int width, int height);
void init_avatar(const Json::Value& config); void init_avatar(const Json::Value& config);

View File

@ -0,0 +1,39 @@
#pragma once
#include <fmt/format.h>
#include <wp/wp.h>
#include <algorithm>
#include <array>
#include "ALabel.hpp"
namespace waybar::modules {
class Wireplumber : public ALabel {
public:
Wireplumber(const std::string&, const Json::Value&);
~Wireplumber();
auto update() -> void;
private:
void loadRequiredApiModules();
void prepare();
void activatePlugins();
static void updateVolume(waybar::modules::Wireplumber* self);
static void updateNodeName(waybar::modules::Wireplumber* self);
static uint32_t getDefaultNodeId(waybar::modules::Wireplumber* self);
static void onPluginActivated(WpObject* p, GAsyncResult* res, waybar::modules::Wireplumber* self);
static void onObjectManagerInstalled(waybar::modules::Wireplumber* self);
WpCore* wp_core_;
GPtrArray* apis_;
WpObjectManager* om_;
uint32_t pending_plugins_;
bool muted_;
double volume_;
uint32_t node_id_{0};
std::string node_name_;
};
} // namespace waybar::modules

View File

@ -37,8 +37,8 @@ The *backlight* module displays the current backlight level.
Positive value to rotate the text label. Positive value to rotate the text label.
*states*: ++ *states*: ++
typeof: array ++ typeof: object ++
A number of backlight states which get activated on certain brightness levels. A number of backlight states which get activated on certain brightness levels. See *waybar-states(5)*.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++

View File

@ -33,7 +33,7 @@ The *battery* module displays the current capacity and state (eg. charging) of y
The interval in which the information gets polled. The interval in which the information gets polled.
*states*: ++ *states*: ++
typeof: array ++ typeof: object ++
A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*. A number of battery states which get activated on certain capacity levels. See *waybar-states(5)*.
*format*: ++ *format*: ++

View File

@ -137,7 +137,7 @@ Addressed by *bluetooth*
*{device_alias}*: Alias of the displayed device. *{device_alias}*: Alias of the displayed device.
*{device_enumerate}*: Show a list of all connected devices, each on a seperate line. Define the format of each device with the *tooltip-format-enumerate-connected* ++ *{device_enumerate}*: Show a list of all connected devices, each on a separate line. Define the format of each device with the *tooltip-format-enumerate-connected* ++
and/or *tooltip-format-enumerate-connected-battery* config options. Can only be used in the tooltip related format options. and/or *tooltip-format-enumerate-connected-battery* config options. Can only be used in the tooltip related format options.
# EXPERIMENTAL BATTERY PERCENTAGE FEATURE # EXPERIMENTAL BATTERY PERCENTAGE FEATURE

View File

@ -42,7 +42,7 @@ The *cpu* module displays the current cpu utilization.
Positive value to rotate the text label. Positive value to rotate the text label.
*states*: ++ *states*: ++
typeof: array ++ typeof: object ++
A number of cpu usage states which get activated on certain usage levels. See *waybar-states(5)*. A number of cpu usage states which get activated on certain usage levels. See *waybar-states(5)*.
*on-click*: ++ *on-click*: ++

View File

@ -32,7 +32,7 @@ Addressed by *disk*
Positive value to rotate the text label. Positive value to rotate the text label.
*states*: ++ *states*: ++
typeof: array ++ typeof: object ++
A number of disk utilization states which get activated on certain percentage thresholds (percentage_used). See *waybar-states(5)*. A number of disk utilization states which get activated on certain percentage thresholds (percentage_used). See *waybar-states(5)*.
*max-length*: ++ *max-length*: ++

View File

@ -23,7 +23,7 @@ Feral Gamemode optimizations.
*tooltip*: ++ *tooltip*: ++
typeof: bool ++ typeof: bool ++
defualt: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*tooltip-format*: ++ *tooltip-format*: ++

View File

@ -6,7 +6,7 @@ waybar - inhibitor module
# DESCRIPTION # DESCRIPTION
The *inhibitor* module allows to take an inhibitor lock that logind provides. The *inhibitor* module allows one to take an inhibitor lock that logind provides.
See *systemd-inhibit*(1) for more information. See *systemd-inhibit*(1) for more information.
# CONFIGURATION # CONFIGURATION

View File

@ -32,7 +32,7 @@ Addressed by *memory*
Positive value to rotate the text label. Positive value to rotate the text label.
*states*: ++ *states*: ++
typeof: array ++ typeof: object ++
A number of memory utilization states which get activated on certain percentage thresholds. See *waybar-states(5)*. A number of memory utilization states which get activated on certain percentage thresholds. See *waybar-states(5)*.
*max-length*: ++ *max-length*: ++

View File

@ -43,8 +43,8 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
Positive value to rotate the text label. Positive value to rotate the text label.
*states*: ++ *states*: ++
typeof: array ++ typeof: object ++
A number of volume states which get activated on certain volume levels. See *waybar-states(5)* A number of volume states which get activated on certain volume levels. See *waybar-states(5)*.
*max-length*: ++ *max-length*: ++
typeof: integer ++ typeof: integer ++

View File

@ -7,14 +7,13 @@ apply a class when the value matches the declared state value.
# STATES # STATES
- Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*). Every entry (*state*) consists of a *<name>* (typeof: *string*) and a *<value>* (typeof: *integer*).
- The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state. - The state can be addressed as a CSS class in the *style.css*. The name of the CSS class is the *<name>* of the state.
Each class gets activated when the current capacity is equal or below the configured *<value>*. Each class gets activated when the current value is equal to or less than the configured *<value>* for the *battery* module, or equal to or greater than the configured *<value>* for all other modules.
- Also each state can have its own *format*. - Also, each state can have its own *format*.
Those can be configured via *format-<name>*. Those can be configured via *format-<name>*, or if you want to differentiate a bit more, as *format-<status>-<state>*.
Or if you want to differentiate a bit more even as *format-<status>-<state>*.
# EXAMPLE # EXAMPLE

View File

@ -33,7 +33,7 @@ compatible devices in the tooltip.
*tooltip*: ++ *tooltip*: ++
typeof: bool ++ typeof: bool ++
defualt: true ++ default: true ++
Option to disable tooltip on hover. Option to disable tooltip on hover.
*tooltip-spacing*: ++ *tooltip-spacing*: ++

View File

@ -0,0 +1,87 @@
waybar-wireplumber(5)
# NAME
waybar - WirePlumber module
# DESCRIPTION
The *wireplumber* module displays the current volume reported by WirePlumber.
# CONFIGURATION
*format*: ++
typeof: string ++
default: *{volume}%* ++
The format, how information should be displayed. This format is used when other formats aren't specified.
*format-muted*: ++
typeof: string ++
This format is used when the sound is muted.
*tooltip*: ++
typeof: bool ++
default: *true* ++
Option to disable tooltip on hover.
*tooltip-format*: ++
typeof: string ++
default: *{node_name}* ++
The format of information displayed in the tooltip.
*rotate*: ++
typeof: integer ++
Positive value to rotate the text label.
*states*: ++
typeof: object ++
A number of volume states which get activated on certain volume levels. See *waybar-states(5)*.
*max-length*: ++
typeof: integer ++
The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++
typeof: string ++
Command to execute when clicked on the module.
*on-click-middle*: ++
typeof: string ++
Command to execute when middle-clicked on the module using mousewheel.
*on-click-right*: ++
typeof: string ++
Command to execute when you right clicked on the module.
*on-update*: ++
typeof: string ++
Command to execute when the module is updated.
# FORMAT REPLACEMENTS
*{volume}*: Volume in percentage.
*{node_name}*: The node's nickname as reported by WirePlumber (*node.nick* property)
# EXAMPLES
```
"wireplumber": {
"format": "{volume}%",
"format-muted": "",
"on-click": "helvum"
}
```
# STYLE
- *#wireplumber*
- *#wireplumber.muted*

View File

@ -1,6 +1,6 @@
project( project(
'waybar', 'cpp', 'c', 'waybar', 'cpp', 'c',
version: '0.9.15', version: '0.9.16',
license: 'MIT', license: 'MIT',
meson_version: '>= 0.49.0', meson_version: '>= 0.49.0',
default_options : [ default_options : [
@ -87,7 +87,7 @@ wayland_protos = dependency('wayland-protocols')
gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0']) gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0'])
dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk')) dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk'))
giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled() or get_option('upower_glib').enabled())) giounix = dependency('gio-unix-2.0', required: (get_option('dbusmenu-gtk').enabled() or get_option('logind').enabled() or get_option('upower_glib').enabled()))
jsoncpp = dependency('jsoncpp') jsoncpp = dependency('jsoncpp', version : ['>=1.9.2'], fallback : ['jsoncpp', 'jsoncpp_dep'])
sigcpp = dependency('sigc++-2.0') sigcpp = dependency('sigc++-2.0')
libinotify = dependency('libinotify', required: false) libinotify = dependency('libinotify', required: false)
libepoll = dependency('epoll-shim', required: false) libepoll = dependency('epoll-shim', required: false)
@ -101,6 +101,7 @@ libevdev = dependency('libevdev', required: get_option('libevdev'))
libmpdclient = dependency('libmpdclient', required: get_option('mpd')) libmpdclient = dependency('libmpdclient', required: get_option('mpd'))
xkbregistry = dependency('xkbregistry') xkbregistry = dependency('xkbregistry')
libjack = dependency('jack', required: get_option('jack')) libjack = dependency('jack', required: get_option('jack'))
libwireplumber = dependency('wireplumber-0.4', required: get_option('wireplumber'))
libsndio = compiler.find_library('sndio', required: get_option('sndio')) libsndio = compiler.find_library('sndio', required: get_option('sndio'))
if libsndio.found() if libsndio.found()
@ -145,7 +146,6 @@ endif
src_files = files( src_files = files(
'src/factory.cpp', 'src/factory.cpp',
'src/AModule.cpp', 'src/AModule.cpp',
'src/AButton.cpp',
'src/ALabel.cpp', 'src/ALabel.cpp',
'src/AIconLabel.cpp', 'src/AIconLabel.cpp',
'src/modules/custom.cpp', 'src/modules/custom.cpp',
@ -247,6 +247,11 @@ if libjack.found()
src_files += 'src/modules/jack.cpp' src_files += 'src/modules/jack.cpp'
endif endif
if libwireplumber.found()
add_project_arguments('-DHAVE_LIBWIREPLUMBER', language: 'cpp')
src_files += 'src/modules/wireplumber.cpp'
endif
if dbusmenu_gtk.found() if dbusmenu_gtk.found()
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp') add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
src_files += files( src_files += files(
@ -330,6 +335,7 @@ executable(
upower_glib, upower_glib,
libpulse, libpulse,
libjack, libjack,
libwireplumber,
libudev, libudev,
libinotify, libinotify,
libepoll, libepoll,

View File

@ -16,3 +16,4 @@ option('logind', type: 'feature', value: 'auto', description: 'Enable support fo
option('tests', type: 'feature', value: 'auto', description: 'Enable tests') option('tests', type: 'feature', value: 'auto', description: 'Enable tests')
option('experimental', type : 'boolean', value : false, description: 'Enable experimental features') option('experimental', type : 'boolean', value : false, description: 'Enable experimental features')
option('jack', type: 'feature', value: 'auto', description: 'Enable support for JACK') option('jack', type: 'feature', value: 'auto', description: 'Enable support for JACK')
option('wireplumber', type: 'feature', value: 'auto', description: 'Enable support for WirePlumber')

View File

@ -81,6 +81,7 @@ button:hover {
#backlight, #backlight,
#network, #network,
#pulseaudio, #pulseaudio,
#wireplumber,
#custom-media, #custom-media,
#tray, #tray,
#mode, #mode,
@ -176,6 +177,15 @@ label:focus {
color: #2a5c45; color: #2a5c45;
} }
#wireplumber {
background-color: #fff0f5;
color: #000000;
}
#wireplumber.muted {
background-color: #f53c3c;
}
#custom-media { #custom-media {
background-color: #66cc99; background-color: #66cc99;
color: #2a5c45; color: #2a5c45;

View File

@ -1,160 +0,0 @@
#include "AButton.hpp"
#include <fmt/format.h>
#include <util/command.hpp>
namespace waybar {
AButton::AButton(const Json::Value& config, const std::string& name, const std::string& id,
const std::string& format, uint16_t interval, bool ellipsize, bool enable_click,
bool enable_scroll)
: AModule(config, name, id, config["format-alt"].isString() || enable_click, enable_scroll),
format_(config_["format"].isString() ? config_["format"].asString() : format),
interval_(config_["interval"] == "once"
? std::chrono::seconds(100000000)
: std::chrono::seconds(
config_["interval"].isUInt() ? config_["interval"].asUInt() : interval)),
default_format_(format_) {
button_.set_name(name);
button_.set_relief(Gtk::RELIEF_NONE);
/* https://github.com/Alexays/Waybar/issues/1731 */
auto css = Gtk::CssProvider::create();
css->load_from_data("button { min-width: 0; }");
button_.get_style_context()->add_provider(css, GTK_STYLE_PROVIDER_PRIORITY_USER);
if (!id.empty()) {
button_.get_style_context()->add_class(id);
}
event_box_.add(button_);
if (config_["max-length"].isUInt()) {
label_->set_max_width_chars(config_["max-length"].asInt());
label_->set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
label_->set_single_line_mode(true);
} else if (ellipsize && label_->get_max_width_chars() == -1) {
label_->set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
label_->set_single_line_mode(true);
}
if (config_["min-length"].isUInt()) {
label_->set_width_chars(config_["min-length"].asUInt());
}
uint rotate = 0;
if (config_["rotate"].isUInt()) {
rotate = config["rotate"].asUInt();
label_->set_angle(rotate);
}
if (config_["align"].isDouble()) {
auto align = config_["align"].asFloat();
if (rotate == 90 || rotate == 270) {
label_->set_yalign(align);
} else {
label_->set_xalign(align);
}
}
if (!(config_["on-click"].isString() || config_["on-click-middle"].isString() ||
config_["on-click-backward"].isString() || config_["on-click-forward"].isString() ||
config_["on-click-right"].isString() || config_["format-alt"].isString() || enable_click)) {
button_.set_sensitive(false);
} else {
button_.signal_pressed().connect([this] {
GdkEventButton* e = (GdkEventButton*)gdk_event_new(GDK_BUTTON_PRESS);
e->button = 1;
handleToggle(e);
});
}
}
auto AButton::update() -> void { AModule::update(); }
std::string AButton::getIcon(uint16_t percentage, const std::string& alt, uint16_t max) {
auto format_icons = config_["format-icons"];
if (format_icons.isObject()) {
if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) {
format_icons = format_icons[alt];
} else {
format_icons = format_icons["default"];
}
}
if (format_icons.isArray()) {
auto size = format_icons.size();
auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1);
format_icons = format_icons[idx];
}
if (format_icons.isString()) {
return format_icons.asString();
}
return "";
}
std::string AButton::getIcon(uint16_t percentage, const std::vector<std::string>& alts,
uint16_t max) {
auto format_icons = config_["format-icons"];
if (format_icons.isObject()) {
std::string _alt = "default";
for (const auto& alt : alts) {
if (!alt.empty() && (format_icons[alt].isString() || format_icons[alt].isArray())) {
_alt = alt;
break;
}
}
format_icons = format_icons[_alt];
}
if (format_icons.isArray()) {
auto size = format_icons.size();
auto idx = std::clamp(percentage / ((max == 0 ? 100 : max) / size), 0U, size - 1);
format_icons = format_icons[idx];
}
if (format_icons.isString()) {
return format_icons.asString();
}
return "";
}
bool waybar::AButton::handleToggle(GdkEventButton* const& e) {
if (config_["format-alt-click"].isUInt() && e->button == config_["format-alt-click"].asUInt()) {
alt_ = !alt_;
if (alt_ && config_["format-alt"].isString()) {
format_ = config_["format-alt"].asString();
} else {
format_ = default_format_;
}
}
return AModule::handleToggle(e);
}
std::string AButton::getState(uint8_t value, bool lesser) {
if (!config_["states"].isObject()) {
return "";
}
// Get current state
std::vector<std::pair<std::string, uint8_t>> states;
if (config_["states"].isObject()) {
for (auto it = config_["states"].begin(); it != config_["states"].end(); ++it) {
if (it->isUInt() && it.key().isString()) {
states.emplace_back(it.key().asString(), it->asUInt());
}
}
}
// Sort states
std::sort(states.begin(), states.end(), [&lesser](auto& a, auto& b) {
return lesser ? a.second < b.second : a.second > b.second;
});
std::string valid_state;
for (auto const& state : states) {
if ((lesser ? value <= state.second : value >= state.second) && valid_state.empty()) {
button_.get_style_context()->add_class(state.first);
valid_state = state.first;
} else {
button_.get_style_context()->remove_class(state.first);
}
}
return valid_state;
}
} // namespace waybar

View File

@ -137,6 +137,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
if (ref == "jack") { if (ref == "jack") {
return new waybar::modules::JACK(id, config_[name]); return new waybar::modules::JACK(id, config_[name]);
} }
#endif
#ifdef HAVE_LIBWIREPLUMBER
if (ref == "wireplumber") {
return new waybar::modules::Wireplumber(id, config_[name]);
}
#endif #endif
if (ref == "temperature") { if (ref == "temperature") {
return new waybar::modules::Temperature(id, config_[name]); return new waybar::modules::Temperature(id, config_[name]);

View File

@ -73,8 +73,9 @@ void check_nn(const void *ptr, const char *message = "ptr was null") {
} }
} // namespace } // namespace
waybar::modules::Backlight::BacklightDev::BacklightDev(std::string name, int actual, int max) waybar::modules::Backlight::BacklightDev::BacklightDev(std::string name, int actual, int max,
: name_(std::move(name)), actual_(actual), max_(max) {} bool powered)
: name_(std::move(name)), actual_(actual), max_(max), powered_(powered) {}
std::string_view waybar::modules::Backlight::BacklightDev::name() const { return name_; } std::string_view waybar::modules::Backlight::BacklightDev::name() const { return name_; }
@ -86,8 +87,12 @@ int waybar::modules::Backlight::BacklightDev::get_max() const { return max_; }
void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; } void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; }
bool waybar::modules::Backlight::BacklightDev::get_powered() const { return powered_; }
void waybar::modules::Backlight::BacklightDev::set_powered(bool powered) { powered_ = powered; }
waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config) waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config)
: AButton(config, "backlight", id, "{percent}%", 2), : ALabel(config, "backlight", id, "{percent}%", 2),
preferred_device_(config["device"].isString() ? config["device"].asString() : "") { preferred_device_(config["device"].isString() ? config["device"].asString() : "") {
// Get initial state // Get initial state
{ {
@ -172,21 +177,26 @@ auto waybar::modules::Backlight::update() -> void {
return; return;
} }
const uint8_t percent = if (best->get_powered()) {
best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max()); event_box_.show();
label_->set_markup(fmt::format(format_, fmt::arg("percent", std::to_string(percent)), const uint8_t percent =
fmt::arg("icon", getIcon(percent)))); best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max());
getState(percent); label_.set_markup(fmt::format(format_, fmt::arg("percent", std::to_string(percent)),
fmt::arg("icon", getIcon(percent))));
getState(percent);
} else {
event_box_.hide();
}
} else { } else {
if (!previous_best_.has_value()) { if (!previous_best_.has_value()) {
return; return;
} }
label_->set_markup(""); label_.set_markup("");
} }
previous_best_ = best == nullptr ? std::nullopt : std::optional{*best}; previous_best_ = best == nullptr ? std::nullopt : std::optional{*best};
previous_format_ = format_; previous_format_ = format_;
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
template <class ForwardIt> template <class ForwardIt>
@ -215,6 +225,7 @@ void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last,
const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr); const char *actual = udev_device_get_sysattr_value(dev, actual_brightness_attr);
const char *max = udev_device_get_sysattr_value(dev, "max_brightness"); const char *max = udev_device_get_sysattr_value(dev, "max_brightness");
const char *power = udev_device_get_sysattr_value(dev, "bl_power");
auto found = auto found =
std::find_if(first, last, [name](const auto &device) { return device.name() == name; }); std::find_if(first, last, [name](const auto &device) { return device.name() == name; });
@ -225,10 +236,14 @@ void waybar::modules::Backlight::upsert_device(ForwardIt first, ForwardIt last,
if (max != nullptr) { if (max != nullptr) {
found->set_max(std::stoi(max)); found->set_max(std::stoi(max));
} }
if (power != nullptr) {
found->set_powered(std::stoi(power) == 0);
}
} else { } else {
const int actual_int = actual == nullptr ? 0 : std::stoi(actual); const int actual_int = actual == nullptr ? 0 : std::stoi(actual);
const int max_int = max == nullptr ? 0 : std::stoi(max); const int max_int = max == nullptr ? 0 : std::stoi(max);
*inserter = BacklightDev{name, actual_int, max_int}; const bool power_bool = power == nullptr ? true : std::stoi(power) == 0;
*inserter = BacklightDev{name, actual_int, max_int, power_bool};
++inserter; ++inserter;
} }
} }

View File

@ -6,7 +6,7 @@
#include <iostream> #include <iostream>
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config) waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
: AButton(config, "battery", id, "{capacity}%", 60) { : ALabel(config, "battery", id, "{capacity}%", 60) {
#if defined(__linux__) #if defined(__linux__)
battery_watch_fd_ = inotify_init1(IN_CLOEXEC); battery_watch_fd_ = inotify_init1(IN_CLOEXEC);
if (battery_watch_fd_ == -1) { if (battery_watch_fd_ == -1) {
@ -470,7 +470,9 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
} }
} }
if (!adapter_.empty() && status == "Discharging") { // Give `Plugged` higher priority over `Not charging`.
// So in a setting where TLP is used, `Plugged` is shown when the threshold is reached
if (!adapter_.empty() && (status == "Discharging" || status == "Not charging")) {
bool online; bool online;
std::string current_status; std::string current_status;
std::ifstream(adapter_ / "online") >> online; std::ifstream(adapter_ / "online") >> online;
@ -493,7 +495,7 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
float calculated_capacity{0.0f}; float calculated_capacity{0.0f};
if (total_capacity_exists) { if (total_capacity_exists) {
if (total_capacity > 0.0f) if (total_capacity > 0.0f)
calculated_capacity = (float)total_capacity; calculated_capacity = (float)total_capacity / batteries_.size();
else if (total_energy_full_exists && total_energy_exists) { else if (total_energy_full_exists && total_energy_exists) {
if (total_energy_full > 0.0f) if (total_energy_full > 0.0f)
calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full); calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
@ -611,14 +613,14 @@ auto waybar::modules::Battery::update() -> void {
} else if (config_["tooltip-format"].isString()) { } else if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
button_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("timeTo", tooltip_text_default), label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("timeTo", tooltip_text_default),
fmt::arg("power", power), fmt::arg("capacity", capacity), fmt::arg("power", power), fmt::arg("capacity", capacity),
fmt::arg("time", time_remaining_formatted))); fmt::arg("time", time_remaining_formatted)));
} }
if (!old_status_.empty()) { if (!old_status_.empty()) {
button_.get_style_context()->remove_class(old_status_); label_.get_style_context()->remove_class(old_status_);
} }
button_.get_style_context()->add_class(status); label_.get_style_context()->add_class(status);
old_status_ = status; old_status_ = status;
if (!state.empty() && config_["format-" + status + "-" + state].isString()) { if (!state.empty() && config_["format-" + status + "-" + state].isString()) {
format = config_["format-" + status + "-" + state].asString(); format = config_["format-" + status + "-" + state].asString();
@ -632,10 +634,10 @@ auto waybar::modules::Battery::update() -> void {
} else { } else {
event_box_.show(); event_box_.show();
auto icons = std::vector<std::string>{status + "-" + state, status, state}; auto icons = std::vector<std::string>{status + "-" + state, status, state};
label_->set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("power", power), label_.set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("power", power),
fmt::arg("icon", getIcon(capacity, icons)), fmt::arg("icon", getIcon(capacity, icons)),
fmt::arg("time", time_remaining_formatted))); fmt::arg("time", time_remaining_formatted)));
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }

View File

@ -80,7 +80,7 @@ auto getUcharProperty(GDBusProxy* proxy, const char* property_name) -> unsigned
} // namespace } // namespace
waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config) waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config)
: AButton(config, "bluetooth", id, " {status}", 10), : ALabel(config, "bluetooth", id, " {status}", 10),
#ifdef WANT_RFKILL #ifdef WANT_RFKILL
rfkill_{RFKILL_TYPE_BLUETOOTH}, rfkill_{RFKILL_TYPE_BLUETOOTH},
#endif #endif
@ -190,10 +190,10 @@ auto waybar::modules::Bluetooth::update() -> void {
format_.empty() ? event_box_.hide() : event_box_.show(); format_.empty() ? event_box_.hide() : event_box_.show();
auto update_style_context = [this](const std::string& style_class, bool in_next_state) { auto update_style_context = [this](const std::string& style_class, bool in_next_state) {
if (in_next_state && !button_.get_style_context()->has_class(style_class)) { if (in_next_state && !label_.get_style_context()->has_class(style_class)) {
button_.get_style_context()->add_class(style_class); label_.get_style_context()->add_class(style_class);
} else if (!in_next_state && button_.get_style_context()->has_class(style_class)) { } else if (!in_next_state && label_.get_style_context()->has_class(style_class)) {
button_.get_style_context()->remove_class(style_class); label_.get_style_context()->remove_class(style_class);
} }
}; };
update_style_context("discoverable", cur_controller_.discoverable); update_style_context("discoverable", cur_controller_.discoverable);
@ -205,7 +205,7 @@ auto waybar::modules::Bluetooth::update() -> void {
update_style_context(state, true); update_style_context(state, true);
state_ = state; state_ = state;
label_->set_markup(fmt::format( label_.set_markup(fmt::format(
format_, fmt::arg("status", state_), fmt::arg("num_connections", connected_devices_.size()), format_, fmt::arg("status", state_), fmt::arg("num_connections", connected_devices_.size()),
fmt::arg("controller_address", cur_controller_.address), fmt::arg("controller_address", cur_controller_.address),
fmt::arg("controller_address_type", cur_controller_.address_type), fmt::arg("controller_address_type", cur_controller_.address_type),
@ -246,7 +246,7 @@ auto waybar::modules::Bluetooth::update() -> void {
device_enumerate_.erase(0, 1); device_enumerate_.erase(0, 1);
} }
} }
button_.set_tooltip_text(fmt::format( label_.set_tooltip_text(fmt::format(
tooltip_format, fmt::arg("status", state_), tooltip_format, fmt::arg("status", state_),
fmt::arg("num_connections", connected_devices_.size()), fmt::arg("num_connections", connected_devices_.size()),
fmt::arg("controller_address", cur_controller_.address), fmt::arg("controller_address", cur_controller_.address),
@ -260,7 +260,7 @@ auto waybar::modules::Bluetooth::update() -> void {
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
// NOTE: only for when the org.bluez.Battery1 interface is added/removed after/before a device is // NOTE: only for when the org.bluez.Battery1 interface is added/removed after/before a device is

View File

@ -18,7 +18,7 @@
using waybar::waybar_time; using waybar::waybar_time;
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: AButton(config, "clock", id, "{:%H:%M}", 60, false, false, true), : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
current_time_zone_idx_(0), current_time_zone_idx_(0),
is_calendar_in_tooltip_(false), is_calendar_in_tooltip_(false),
is_timezoned_list_in_tooltip_(false) { is_timezoned_list_in_tooltip_(false) {
@ -107,7 +107,7 @@ auto waybar::modules::Clock::update() -> void {
} else { } else {
text = fmt::format(format_, wtime); text = fmt::format(format_, wtime);
} }
label_->set_markup(text); label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
@ -119,12 +119,12 @@ auto waybar::modules::Clock::update() -> void {
text = text =
fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines), fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines),
fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines)); fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines));
button_.set_tooltip_markup(text); label_.set_tooltip_markup(text);
} }
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) { bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) {

View File

@ -10,7 +10,7 @@
#endif #endif
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config) waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
: AButton(config, "cpu", id, "{usage}%", 10) { : ALabel(config, "cpu", id, "{usage}%", 10) {
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
thread_.sleep_for(interval_); thread_.sleep_for(interval_);
@ -23,7 +23,7 @@ auto waybar::modules::Cpu::update() -> void {
auto [cpu_usage, tooltip] = getCpuUsage(); auto [cpu_usage, tooltip] = getCpuUsage();
auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency(); auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency();
if (tooltipEnabled()) { if (tooltipEnabled()) {
button_.set_tooltip_text(tooltip); label_.set_tooltip_text(tooltip);
} }
auto format = format_; auto format = format_;
auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0]; auto total_usage = cpu_usage.empty() ? 0 : cpu_usage[0];
@ -52,11 +52,11 @@ auto waybar::modules::Cpu::update() -> void {
auto icon_format = fmt::format("icon{}", core_i); auto icon_format = fmt::format("icon{}", core_i);
store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons))); store.push_back(fmt::arg(icon_format.c_str(), getIcon(cpu_usage[i], icons)));
} }
label_->set_markup(fmt::vformat(format, store)); label_.set_markup(fmt::vformat(format, store));
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
double waybar::modules::Cpu::getCpuLoad() { double waybar::modules::Cpu::getCpuLoad() {

View File

@ -4,7 +4,7 @@
waybar::modules::Custom::Custom(const std::string& name, const std::string& id, waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
const Json::Value& config) const Json::Value& config)
: AButton(config, "custom-" + name, id, "{}"), : ALabel(config, "custom-" + name, id, "{}"),
name_(name), name_(name),
id_(id), id_(id),
percentage_(0), percentage_(0),
@ -21,6 +21,7 @@ waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
waybar::modules::Custom::~Custom() { waybar::modules::Custom::~Custom() {
if (pid_ != -1) { if (pid_ != -1) {
killpg(pid_, SIGTERM); killpg(pid_, SIGTERM);
waitpid(pid_, NULL, 0);
pid_ = -1; pid_ = -1;
} }
} }
@ -103,13 +104,13 @@ void waybar::modules::Custom::handleEvent() {
} }
bool waybar::modules::Custom::handleScroll(GdkEventScroll* e) { bool waybar::modules::Custom::handleScroll(GdkEventScroll* e) {
auto ret = AButton::handleScroll(e); auto ret = ALabel::handleScroll(e);
handleEvent(); handleEvent();
return ret; return ret;
} }
bool waybar::modules::Custom::handleToggle(GdkEventButton* const& e) { bool waybar::modules::Custom::handleToggle(GdkEventButton* const& e) {
auto ret = AButton::handleToggle(e); auto ret = ALabel::handleToggle(e);
handleEvent(); handleEvent();
return ret; return ret;
} }
@ -131,33 +132,33 @@ auto waybar::modules::Custom::update() -> void {
if (str.empty()) { if (str.empty()) {
event_box_.hide(); event_box_.hide();
} else { } else {
label_->set_markup(str); label_.set_markup(str);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (text_ == tooltip_) { if (text_ == tooltip_) {
if (button_.get_tooltip_markup() != str) { if (label_.get_tooltip_markup() != str) {
button_.set_tooltip_markup(str); label_.set_tooltip_markup(str);
} }
} else { } else {
if (button_.get_tooltip_markup() != tooltip_) { if (label_.get_tooltip_markup() != tooltip_) {
button_.set_tooltip_markup(tooltip_); label_.set_tooltip_markup(tooltip_);
} }
} }
} }
auto classes = button_.get_style_context()->list_classes(); auto classes = label_.get_style_context()->list_classes();
for (auto const& c : classes) { for (auto const& c : classes) {
if (c == id_) continue; if (c == id_) continue;
button_.get_style_context()->remove_class(c); label_.get_style_context()->remove_class(c);
} }
for (auto const& c : class_) { for (auto const& c : class_) {
button_.get_style_context()->add_class(c); label_.get_style_context()->add_class(c);
} }
button_.get_style_context()->add_class("flat"); label_.get_style_context()->add_class("flat");
button_.get_style_context()->add_class("text-button"); label_.get_style_context()->add_class("text-button");
event_box_.show(); event_box_.show();
} }
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
void waybar::modules::Custom::parseOutputRaw() { void waybar::modules::Custom::parseOutputRaw() {

View File

@ -3,7 +3,7 @@
using namespace waybar::util; using namespace waybar::util;
waybar::modules::Disk::Disk(const std::string& id, const Json::Value& config) waybar::modules::Disk::Disk(const std::string& id, const Json::Value& config)
: AButton(config, "disk", id, "{}%", 30), path_("/") { : ALabel(config, "disk", id, "{}%", 30), path_("/") {
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
thread_.sleep_for(interval_); thread_.sleep_for(interval_);
@ -58,7 +58,7 @@ auto waybar::modules::Disk::update() -> void {
event_box_.hide(); event_box_.hide();
} else { } else {
event_box_.show(); event_box_.show();
label_->set_markup( label_.set_markup(
fmt::format(format, stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free), fmt::format(format, stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free),
fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks),
fmt::arg("used", used), fmt::arg("percentage_used", percentage_used), fmt::arg("used", used), fmt::arg("percentage_used", percentage_used),
@ -70,12 +70,12 @@ auto waybar::modules::Disk::update() -> void {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
button_.set_tooltip_text( label_.set_tooltip_text(
fmt::format(tooltip_format, stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free), fmt::format(tooltip_format, stats.f_bavail * 100 / stats.f_blocks, fmt::arg("free", free),
fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks), fmt::arg("percentage_free", stats.f_bavail * 100 / stats.f_blocks),
fmt::arg("used", used), fmt::arg("percentage_used", percentage_used), fmt::arg("used", used), fmt::arg("percentage_used", percentage_used),
fmt::arg("total", total), fmt::arg("path", path_))); fmt::arg("total", total), fmt::arg("path", path_)));
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }

View File

@ -95,15 +95,37 @@ void IPC::parseIPC(const std::string& ev) {
for (auto& [eventname, handler] : callbacks) { for (auto& [eventname, handler] : callbacks) {
if (eventname == request) { if (eventname == request) {
handler(ev); handler->onEvent(ev);
} }
} }
} }
void IPC::registerForIPC(const std::string& ev, std::function<void(const std::string&)> fn) { void IPC::registerForIPC(const std::string& ev, EventHandler* ev_handler) {
if (!ev_handler) {
return;
}
callbackMutex.lock(); callbackMutex.lock();
callbacks.emplace_back(std::make_pair(ev, fn)); callbacks.emplace_back(std::make_pair(ev, ev_handler));
callbackMutex.unlock();
}
void IPC::unregisterForIPC(EventHandler* ev_handler) {
if (!ev_handler) {
return;
}
callbackMutex.lock();
for (auto it = callbacks.begin(); it != callbacks.end();) {
auto it_current = it;
it++;
auto& [eventname, handler] = *it_current;
if (handler == ev_handler) {
callbacks.erase(it_current);
}
}
callbackMutex.unlock(); callbackMutex.unlock();
} }

View File

@ -11,7 +11,7 @@
namespace waybar::modules::hyprland { namespace waybar::modules::hyprland {
Language::Language(const std::string& id, const Bar& bar, const Json::Value& config) Language::Language(const std::string& id, const Bar& bar, const Json::Value& config)
: AButton(config, "language", id, "{}", 0, true), bar_(bar) { : ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
modulesReady = true; modulesReady = true;
if (!gIPC.get()) { if (!gIPC.get()) {
@ -21,24 +21,30 @@ Language::Language(const std::string& id, const Bar& bar, const Json::Value& con
// get the active layout when open // get the active layout when open
initLanguage(); initLanguage();
button_.hide(); label_.hide();
AButton::update(); ALabel::update();
// register for hyprland ipc // register for hyprland ipc
gIPC->registerForIPC("activelayout", [&](const std::string& ev) { this->onEvent(ev); }); gIPC->registerForIPC("activelayout", this);
}
Language::~Language() {
gIPC->unregisterForIPC(this);
// wait for possible event handler to finish
std::lock_guard<std::mutex> lg(mutex_);
} }
auto Language::update() -> void { auto Language::update() -> void {
std::lock_guard<std::mutex> lg(mutex_); std::lock_guard<std::mutex> lg(mutex_);
if (!format_.empty()) { if (!format_.empty()) {
button_.show(); label_.show();
label_->set_markup(layoutName_); label_.set_markup(layoutName_);
} else { } else {
button_.hide(); label_.hide();
} }
AButton::update(); ALabel::update();
} }
void Language::onEvent(const std::string& ev) { void Language::onEvent(const std::string& ev) {

View File

@ -25,7 +25,13 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
ALabel::update(); ALabel::update();
// register for hyprland ipc // register for hyprland ipc
gIPC->registerForIPC("activewindow", [&](const std::string& ev) { this->onEvent(ev); }); gIPC->registerForIPC("activewindow", this);
}
Window::~Window() {
gIPC->unregisterForIPC(this);
// wait for possible event handler to finish
std::lock_guard<std::mutex> lg(mutex_);
} }
auto Window::update() -> void { auto Window::update() -> void {
@ -43,24 +49,26 @@ auto Window::update() -> void {
ALabel::update(); ALabel::update();
} }
uint Window::getActiveWorkspaceID(std::string monitorName) { int Window::getActiveWorkspaceID(std::string monitorName) {
auto cmd = waybar::util::command::exec("hyprctl monitors -j"); auto cmd = waybar::util::command::exec("hyprctl monitors -j");
assert(cmd.exit_code == 0); assert(cmd.exit_code == 0);
Json::Value json = parser_.parse(cmd.out); Json::Value json = parser_.parse(cmd.out);
assert(json.isArray()); assert(json.isArray());
auto monitor = std::find_if(json.begin(), json.end(), auto monitor = std::find_if(json.begin(), json.end(),
[&](Json::Value monitor) { return monitor["name"] == monitorName; }); [&](Json::Value monitor) { return monitor["name"] == monitorName; });
assert(monitor != std::end(json)); if (monitor == std::end(json)) {
return (*monitor)["activeWorkspace"]["id"].as<uint>(); return 0;
}
return (*monitor)["activeWorkspace"]["id"].as<int>();
} }
std::string Window::getLastWindowTitle(uint workspaceID) { std::string Window::getLastWindowTitle(int workspaceID) {
auto cmd = waybar::util::command::exec("hyprctl workspaces -j"); auto cmd = waybar::util::command::exec("hyprctl workspaces -j");
assert(cmd.exit_code == 0); assert(cmd.exit_code == 0);
Json::Value json = parser_.parse(cmd.out); Json::Value json = parser_.parse(cmd.out);
assert(json.isArray()); assert(json.isArray());
auto workspace = std::find_if(json.begin(), json.end(), [&](Json::Value workspace) { auto workspace = std::find_if(json.begin(), json.end(), [&](Json::Value workspace) {
return workspace["id"].as<uint>() == workspaceID; return workspace["id"].as<int>() == workspaceID;
}); });
if (workspace == std::end(json)) { if (workspace == std::end(json)) {

View File

@ -8,7 +8,7 @@ bool waybar::modules::IdleInhibitor::status = false;
waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar, waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar,
const Json::Value& config) const Json::Value& config)
: AButton(config, "idle_inhibitor", id, "{status}", 0, false, true), : ALabel(config, "idle_inhibitor", id, "{status}", 0, false, true),
bar_(bar), bar_(bar),
idle_inhibitor_(nullptr), idle_inhibitor_(nullptr),
pid_(-1) { pid_(-1) {
@ -49,13 +49,13 @@ waybar::modules::IdleInhibitor::~IdleInhibitor() {
auto waybar::modules::IdleInhibitor::update() -> void { auto waybar::modules::IdleInhibitor::update() -> void {
// Check status // Check status
if (status) { if (status) {
button_.get_style_context()->remove_class("deactivated"); label_.get_style_context()->remove_class("deactivated");
if (idle_inhibitor_ == nullptr) { if (idle_inhibitor_ == nullptr) {
idle_inhibitor_ = zwp_idle_inhibit_manager_v1_create_inhibitor( idle_inhibitor_ = zwp_idle_inhibit_manager_v1_create_inhibitor(
waybar::Client::inst()->idle_inhibit_manager, bar_.surface); waybar::Client::inst()->idle_inhibit_manager, bar_.surface);
} }
} else { } else {
button_.get_style_context()->remove_class("activated"); label_.get_style_context()->remove_class("activated");
if (idle_inhibitor_ != nullptr) { if (idle_inhibitor_ != nullptr) {
zwp_idle_inhibitor_v1_destroy(idle_inhibitor_); zwp_idle_inhibitor_v1_destroy(idle_inhibitor_);
idle_inhibitor_ = nullptr; idle_inhibitor_ = nullptr;
@ -63,11 +63,11 @@ auto waybar::modules::IdleInhibitor::update() -> void {
} }
std::string status_text = status ? "activated" : "deactivated"; std::string status_text = status ? "activated" : "deactivated";
label_->set_markup(fmt::format(format_, fmt::arg("status", status_text), label_.set_markup(fmt::format(format_, fmt::arg("status", status_text),
fmt::arg("icon", getIcon(0, status_text)))); fmt::arg("icon", getIcon(0, status_text))));
button_.get_style_context()->add_class(status_text); label_.get_style_context()->add_class(status_text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
button_.set_tooltip_markup( label_.set_tooltip_markup(
status ? fmt::format(config_["tooltip-format-activated"].isString() status ? fmt::format(config_["tooltip-format-activated"].isString()
? config_["tooltip-format-activated"].asString() ? config_["tooltip-format-activated"].asString()
: "{status}", : "{status}",
@ -80,7 +80,7 @@ auto waybar::modules::IdleInhibitor::update() -> void {
fmt::arg("icon", getIcon(0, status_text)))); fmt::arg("icon", getIcon(0, status_text))));
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
void waybar::modules::IdleInhibitor::toggleStatus() { void waybar::modules::IdleInhibitor::toggleStatus() {
@ -124,6 +124,6 @@ bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
} }
} }
AButton::handleToggle(e); ALabel::handleToggle(e);
return true; return true;
} }

View File

@ -98,7 +98,7 @@ auto getInhibitors(const Json::Value& config) -> std::string {
namespace waybar::modules { namespace waybar::modules {
Inhibitor::Inhibitor(const std::string& id, const Bar& bar, const Json::Value& config) Inhibitor::Inhibitor(const std::string& id, const Bar& bar, const Json::Value& config)
: AButton(config, "inhibitor", id, "{status}", true), : ALabel(config, "inhibitor", id, "{status}", true),
dbus_(::dbus()), dbus_(::dbus()),
inhibitors_(::getInhibitors(config)) { inhibitors_(::getInhibitors(config)) {
event_box_.add_events(Gdk::BUTTON_PRESS_MASK); event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
@ -117,16 +117,16 @@ auto Inhibitor::activated() -> bool { return handle_ != -1; }
auto Inhibitor::update() -> void { auto Inhibitor::update() -> void {
std::string status_text = activated() ? "activated" : "deactivated"; std::string status_text = activated() ? "activated" : "deactivated";
button_.get_style_context()->remove_class(activated() ? "deactivated" : "activated"); label_.get_style_context()->remove_class(activated() ? "deactivated" : "activated");
label_->set_markup(fmt::format(format_, fmt::arg("status", status_text), label_.set_markup(fmt::format(format_, fmt::arg("status", status_text),
fmt::arg("icon", getIcon(0, status_text)))); fmt::arg("icon", getIcon(0, status_text))));
button_.get_style_context()->add_class(status_text); label_.get_style_context()->add_class(status_text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
button_.set_tooltip_text(status_text); label_.set_tooltip_text(status_text);
} }
return AButton::update(); return ALabel::update();
} }
auto Inhibitor::handleToggle(GdkEventButton* const& e) -> bool { auto Inhibitor::handleToggle(GdkEventButton* const& e) -> bool {
@ -142,7 +142,7 @@ auto Inhibitor::handleToggle(GdkEventButton* const& e) -> bool {
} }
} }
return AButton::handleToggle(e); return ALabel::handleToggle(e);
} }
} // namespace waybar::modules } // namespace waybar::modules

View File

@ -1,7 +1,7 @@
#include "modules/memory.hpp" #include "modules/memory.hpp"
waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config) waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config)
: AButton(config, "memory", id, "{}%", 30) { : ALabel(config, "memory", id, "{}%", 30) {
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
thread_.sleep_for(interval_); thread_.sleep_for(interval_);
@ -55,7 +55,7 @@ auto waybar::modules::Memory::update() -> void {
} else { } else {
event_box_.show(); event_box_.show();
auto icons = std::vector<std::string>{state}; auto icons = std::vector<std::string>{state};
label_->set_markup(fmt::format( label_.set_markup(fmt::format(
format, used_ram_percentage, fmt::arg("icon", getIcon(used_ram_percentage, icons)), format, used_ram_percentage, fmt::arg("icon", getIcon(used_ram_percentage, icons)),
fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes), fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
fmt::arg("percentage", used_ram_percentage), fmt::arg("percentage", used_ram_percentage),
@ -67,7 +67,7 @@ auto waybar::modules::Memory::update() -> void {
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
auto tooltip_format = config_["tooltip-format"].asString(); auto tooltip_format = config_["tooltip-format"].asString();
button_.set_tooltip_text(fmt::format( label_.set_tooltip_text(fmt::format(
tooltip_format, used_ram_percentage, fmt::arg("total", total_ram_gigabytes), tooltip_format, used_ram_percentage, fmt::arg("total", total_ram_gigabytes),
fmt::arg("swapTotal", total_swap_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
fmt::arg("percentage", used_ram_percentage), fmt::arg("percentage", used_ram_percentage),
@ -75,12 +75,12 @@ auto waybar::modules::Memory::update() -> void {
fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes), fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
fmt::arg("swapAvail", available_swap_gigabytes))); fmt::arg("swapAvail", available_swap_gigabytes)));
} else { } else {
button_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1)); label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
} }
} }
} else { } else {
event_box_.hide(); event_box_.hide();
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }

View File

@ -15,7 +15,7 @@ namespace waybar::modules {
#endif #endif
waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config) waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
: AButton(config, "mpd", id, "{album} - {artist} - {title}", 5, false, true), : ALabel(config, "mpd", id, "{album} - {artist} - {title}", 5, false, true),
module_name_(id.empty() ? "mpd" : "mpd#" + id), module_name_(id.empty() ? "mpd" : "mpd#" + id),
server_(nullptr), server_(nullptr),
port_(config_["port"].isUInt() ? config["port"].asUInt() : 0), port_(config_["port"].isUInt() ? config["port"].asUInt() : 0),
@ -47,7 +47,7 @@ auto waybar::modules::MPD::update() -> void {
context_.update(); context_.update();
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
void waybar::modules::MPD::queryMPD() { void waybar::modules::MPD::queryMPD() {
@ -88,15 +88,15 @@ std::string waybar::modules::MPD::getFilename() const {
void waybar::modules::MPD::setLabel() { void waybar::modules::MPD::setLabel() {
if (connection_ == nullptr) { if (connection_ == nullptr) {
button_.get_style_context()->add_class("disconnected"); label_.get_style_context()->add_class("disconnected");
button_.get_style_context()->remove_class("stopped"); label_.get_style_context()->remove_class("stopped");
button_.get_style_context()->remove_class("playing"); label_.get_style_context()->remove_class("playing");
button_.get_style_context()->remove_class("paused"); label_.get_style_context()->remove_class("paused");
auto format = config_["format-disconnected"].isString() auto format = config_["format-disconnected"].isString()
? config_["format-disconnected"].asString() ? config_["format-disconnected"].asString()
: "disconnected"; : "disconnected";
label_->set_markup(format); label_.set_markup(format);
if (tooltipEnabled()) { if (tooltipEnabled()) {
std::string tooltip_format; std::string tooltip_format;
@ -104,11 +104,11 @@ void waybar::modules::MPD::setLabel() {
? config_["tooltip-format-disconnected"].asString() ? config_["tooltip-format-disconnected"].asString()
: "MPD (disconnected)"; : "MPD (disconnected)";
// Nothing to format // Nothing to format
button_.set_tooltip_text(tooltip_format); label_.set_tooltip_text(tooltip_format);
} }
return; return;
} else { } else {
button_.get_style_context()->remove_class("disconnected"); label_.get_style_context()->remove_class("disconnected");
} }
auto format = format_; auto format = format_;
@ -121,19 +121,19 @@ void waybar::modules::MPD::setLabel() {
if (stopped()) { if (stopped()) {
format = format =
config_["format-stopped"].isString() ? config_["format-stopped"].asString() : "stopped"; config_["format-stopped"].isString() ? config_["format-stopped"].asString() : "stopped";
button_.get_style_context()->add_class("stopped"); label_.get_style_context()->add_class("stopped");
button_.get_style_context()->remove_class("playing"); label_.get_style_context()->remove_class("playing");
button_.get_style_context()->remove_class("paused"); label_.get_style_context()->remove_class("paused");
} else { } else {
button_.get_style_context()->remove_class("stopped"); label_.get_style_context()->remove_class("stopped");
if (playing()) { if (playing()) {
button_.get_style_context()->add_class("playing"); label_.get_style_context()->add_class("playing");
button_.get_style_context()->remove_class("paused"); label_.get_style_context()->remove_class("paused");
} else if (paused()) { } else if (paused()) {
format = config_["format-paused"].isString() ? config_["format-paused"].asString() format = config_["format-paused"].isString() ? config_["format-paused"].asString()
: config_["format"].asString(); : config_["format"].asString();
button_.get_style_context()->add_class("paused"); label_.get_style_context()->add_class("paused");
button_.get_style_context()->remove_class("playing"); label_.get_style_context()->remove_class("playing");
} }
stateIcon = getStateIcon(); stateIcon = getStateIcon();
@ -169,17 +169,15 @@ void waybar::modules::MPD::setLabel() {
if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt()); if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt());
try { try {
label_->set_markup(fmt::format( label_.set_markup(fmt::format(
format, fmt::arg("artist", Glib::Markup::escape_text(artist).raw()), format, fmt::arg("artist", artist.raw()), fmt::arg("albumArtist", album_artist.raw()),
fmt::arg("albumArtist", Glib::Markup::escape_text(album_artist).raw()), fmt::arg("album", album.raw()), fmt::arg("title", title.raw()), fmt::arg("date", date),
fmt::arg("album", Glib::Markup::escape_text(album).raw()), fmt::arg("volume", volume), fmt::arg("elapsedTime", elapsedTime),
fmt::arg("title", Glib::Markup::escape_text(title).raw()), fmt::arg("totalTime", totalTime), fmt::arg("songPosition", song_pos),
fmt::arg("date", Glib::Markup::escape_text(date).raw()), fmt::arg("volume", volume), fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon),
fmt::arg("elapsedTime", elapsedTime), fmt::arg("totalTime", totalTime), fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon),
fmt::arg("songPosition", song_pos), fmt::arg("queueLength", queue_length), fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon),
fmt::arg("stateIcon", stateIcon), fmt::arg("consumeIcon", consumeIcon), fmt::arg("filename", filename)));
fmt::arg("randomIcon", randomIcon), fmt::arg("repeatIcon", repeatIcon),
fmt::arg("singleIcon", singleIcon), fmt::arg("filename", filename)));
} catch (fmt::format_error const& e) { } catch (fmt::format_error const& e) {
spdlog::warn("mpd: format error: {}", e.what()); spdlog::warn("mpd: format error: {}", e.what());
} }
@ -198,7 +196,7 @@ void waybar::modules::MPD::setLabel() {
fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon), fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon),
fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon), fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon),
fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon)); fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon));
button_.set_tooltip_text(tooltip_text); label_.set_tooltip_text(tooltip_text);
} catch (fmt::format_error const& e) { } catch (fmt::format_error const& e) {
spdlog::warn("mpd: format error (tooltip): {}", e.what()); spdlog::warn("mpd: format error (tooltip): {}", e.what());
} }

View File

@ -78,7 +78,7 @@ waybar::modules::Network::readBandwidthUsage() {
} }
waybar::modules::Network::Network(const std::string &id, const Json::Value &config) waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
: AButton(config, "network", id, DEFAULT_FORMAT, 60), : ALabel(config, "network", id, DEFAULT_FORMAT, 60),
ifid_(-1), ifid_(-1),
family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET), family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET),
efd_(-1), efd_(-1),
@ -95,11 +95,11 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
#endif #endif
frequency_(0.0) { frequency_(0.0) {
// Start with some "text" in the module's label_-> update() will then // Start with some "text" in the module's label_. update() will then
// update it. Since the text should be different, update() will be able // update it. Since the text should be different, update() will be able
// to show or hide the event_box_. This is to work around the case where // to show or hide the event_box_. This is to work around the case where
// the module start with no text, but the the event_box_ is shown. // the module start with no text, but the the event_box_ is shown.
label_->set_markup("<s></s>"); label_.set_markup("<s></s>");
auto bandwidth = readBandwidthUsage(); auto bandwidth = readBandwidthUsage();
if (bandwidth.has_value()) { if (bandwidth.has_value()) {
@ -309,8 +309,8 @@ auto waybar::modules::Network::update() -> void {
if (!alt_) { if (!alt_) {
auto state = getNetworkState(); auto state = getNetworkState();
if (!state_.empty() && button_.get_style_context()->has_class(state_)) { if (!state_.empty() && label_.get_style_context()->has_class(state_)) {
button_.get_style_context()->remove_class(state_); label_.get_style_context()->remove_class(state_);
} }
if (config_["format-" + state].isString()) { if (config_["format-" + state].isString()) {
default_format_ = config_["format-" + state].asString(); default_format_ = config_["format-" + state].asString();
@ -322,8 +322,8 @@ auto waybar::modules::Network::update() -> void {
if (config_["tooltip-format-" + state].isString()) { if (config_["tooltip-format-" + state].isString()) {
tooltip_format = config_["tooltip-format-" + state].asString(); tooltip_format = config_["tooltip-format-" + state].asString();
} }
if (!button_.get_style_context()->has_class(state)) { if (!label_.get_style_context()->has_class(state)) {
button_.get_style_context()->add_class(state); label_.get_style_context()->add_class(state);
} }
format_ = default_format_; format_ = default_format_;
state_ = state; state_ = state;
@ -349,8 +349,8 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / interval_.count(), "B/s")), fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / interval_.count(), "B/s")),
fmt::arg("bandwidthTotalBytes", fmt::arg("bandwidthTotalBytes",
pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s"))); pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s")));
if (text.compare(label_->get_label()) != 0) { if (text.compare(label_.get_label()) != 0) {
label_->set_markup(text); label_.set_markup(text);
if (text.empty()) { if (text.empty()) {
event_box_.hide(); event_box_.hide();
} else { } else {
@ -382,16 +382,16 @@ auto waybar::modules::Network::update() -> void {
fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / interval_.count(), "B/s")), fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / interval_.count(), "B/s")),
fmt::arg("bandwidthTotalBytes", fmt::arg("bandwidthTotalBytes",
pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s"))); pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s")));
if (button_.get_tooltip_text() != tooltip_text) { if (label_.get_tooltip_text() != tooltip_text) {
button_.set_tooltip_markup(tooltip_text); label_.set_tooltip_markup(tooltip_text);
} }
} else if (button_.get_tooltip_text() != text) { } else if (label_.get_tooltip_text() != text) {
button_.set_tooltip_markup(text); label_.set_tooltip_markup(text);
} }
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
bool waybar::modules::Network::checkInterface(std::string name) { bool waybar::modules::Network::checkInterface(std::string name) {

View File

@ -1,7 +1,7 @@
#include "modules/pulseaudio.hpp" #include "modules/pulseaudio.hpp"
waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value &config) waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value &config)
: AButton(config, "pulseaudio", id, "{volume}%"), : ALabel(config, "pulseaudio", id, "{volume}%"),
mainloop_(nullptr), mainloop_(nullptr),
mainloop_api_(nullptr), mainloop_api_(nullptr),
context_(nullptr), context_(nullptr),
@ -260,11 +260,12 @@ auto waybar::modules::Pulseaudio::update() -> void {
if (!alt_) { if (!alt_) {
std::string format_name = "format"; std::string format_name = "format";
if (monitor_.find("a2dp_sink") != std::string::npos || // PulseAudio if (monitor_.find("a2dp_sink") != std::string::npos || // PulseAudio
monitor_.find("a2dp-sink") != std::string::npos) { // PipeWire monitor_.find("a2dp-sink") != std::string::npos || // PipeWire
monitor_.find("bluez") != std::string::npos) {
format_name = format_name + "-bluetooth"; format_name = format_name + "-bluetooth";
button_.get_style_context()->add_class("bluetooth"); label_.get_style_context()->add_class("bluetooth");
} else { } else {
button_.get_style_context()->remove_class("bluetooth"); label_.get_style_context()->remove_class("bluetooth");
} }
if (muted_) { if (muted_) {
// Check muted bluetooth format exist, otherwise fallback to default muted format // Check muted bluetooth format exist, otherwise fallback to default muted format
@ -272,29 +273,29 @@ auto waybar::modules::Pulseaudio::update() -> void {
format_name = "format"; format_name = "format";
} }
format_name = format_name + "-muted"; format_name = format_name + "-muted";
button_.get_style_context()->add_class("muted"); label_.get_style_context()->add_class("muted");
button_.get_style_context()->add_class("sink-muted"); label_.get_style_context()->add_class("sink-muted");
} else { } else {
button_.get_style_context()->remove_class("muted"); label_.get_style_context()->remove_class("muted");
button_.get_style_context()->remove_class("sink-muted"); label_.get_style_context()->remove_class("sink-muted");
} }
format = config_[format_name].isString() ? config_[format_name].asString() : format; format = config_[format_name].isString() ? config_[format_name].asString() : format;
} }
// TODO: find a better way to split source/sink // TODO: find a better way to split source/sink
std::string format_source = "{volume}%"; std::string format_source = "{volume}%";
if (source_muted_) { if (source_muted_) {
button_.get_style_context()->add_class("source-muted"); label_.get_style_context()->add_class("source-muted");
if (config_["format-source-muted"].isString()) { if (config_["format-source-muted"].isString()) {
format_source = config_["format-source-muted"].asString(); format_source = config_["format-source-muted"].asString();
} }
} else { } else {
button_.get_style_context()->remove_class("source-muted"); label_.get_style_context()->remove_class("source-muted");
if (config_["format-source-muted"].isString()) { if (config_["format-source-muted"].isString()) {
format_source = config_["format-source"].asString(); format_source = config_["format-source"].asString();
} }
} }
format_source = fmt::format(format_source, fmt::arg("volume", source_volume_)); format_source = fmt::format(format_source, fmt::arg("volume", source_volume_));
label_->set_markup(fmt::format( label_.set_markup(fmt::format(
format, fmt::arg("desc", desc_), fmt::arg("volume", volume_), format, fmt::arg("desc", desc_), fmt::arg("volume", volume_),
fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_), fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_),
fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon())))); fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon()))));
@ -305,16 +306,16 @@ auto waybar::modules::Pulseaudio::update() -> void {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
if (!tooltip_format.empty()) { if (!tooltip_format.empty()) {
button_.set_tooltip_text(fmt::format( label_.set_tooltip_text(fmt::format(
tooltip_format, fmt::arg("desc", desc_), fmt::arg("volume", volume_), tooltip_format, fmt::arg("desc", desc_), fmt::arg("volume", volume_),
fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_), fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_),
fmt::arg("source_desc", source_desc_), fmt::arg("source_desc", source_desc_),
fmt::arg("icon", getIcon(volume_, getPulseIcon())))); fmt::arg("icon", getIcon(volume_, getPulseIcon()))));
} else { } else {
button_.set_tooltip_text(desc_); label_.set_tooltip_text(desc_);
} }
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }

View File

@ -3,7 +3,7 @@
#include <time.h> #include <time.h>
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
: AButton(config, "clock", id, "{:%H:%M}", 60) { : ALabel(config, "clock", id, "{:%H:%M}", 60) {
thread_ = [this] { thread_ = [this] {
dp.emit(); dp.emit();
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
@ -19,17 +19,17 @@ auto waybar::modules::Clock::update() -> void {
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
auto text = fmt::format(format_, localtime); auto text = fmt::format(format_, localtime);
label_->set_markup(text); label_.set_markup(text);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
auto tooltip_format = config_["tooltip-format"].asString(); auto tooltip_format = config_["tooltip-format"].asString();
auto tooltip_text = fmt::format(tooltip_format, localtime); auto tooltip_text = fmt::format(tooltip_format, localtime);
button_.set_tooltip_text(tooltip_text); label_.set_tooltip_text(tooltip_text);
} else { } else {
button_.set_tooltip_text(text); label_.set_tooltip_text(text);
} }
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }

View File

@ -41,7 +41,7 @@ auto Sndio::connect_to_sndio() -> void {
} }
Sndio::Sndio(const std::string &id, const Json::Value &config) Sndio::Sndio(const std::string &id, const Json::Value &config)
: AButton(config, "sndio", id, "{volume}%", 1, false, true), : ALabel(config, "sndio", id, "{volume}%", 1, false, true),
hdl_(nullptr), hdl_(nullptr),
pfds_(0), pfds_(0),
addr_(0), addr_(0),
@ -105,14 +105,14 @@ auto Sndio::update() -> void {
unsigned int vol = 100. * static_cast<double>(volume_) / static_cast<double>(maxval_); unsigned int vol = 100. * static_cast<double>(volume_) / static_cast<double>(maxval_);
if (volume_ == 0) { if (volume_ == 0) {
button_.get_style_context()->add_class("muted"); label_.get_style_context()->add_class("muted");
} else { } else {
button_.get_style_context()->remove_class("muted"); label_.get_style_context()->remove_class("muted");
} }
label_->set_markup(fmt::format(format, fmt::arg("volume", vol), fmt::arg("raw_value", volume_))); label_.set_markup(fmt::format(format, fmt::arg("volume", vol), fmt::arg("raw_value", volume_)));
AButton::update(); ALabel::update();
} }
auto Sndio::set_desc(struct sioctl_desc *d, unsigned int val) -> void { auto Sndio::set_desc(struct sioctl_desc *d, unsigned int val) -> void {

View File

@ -18,7 +18,7 @@ const std::string Language::XKB_LAYOUT_NAMES_KEY = "xkb_layout_names";
const std::string Language::XKB_ACTIVE_LAYOUT_NAME_KEY = "xkb_active_layout_name"; const std::string Language::XKB_ACTIVE_LAYOUT_NAME_KEY = "xkb_active_layout_name";
Language::Language(const std::string& id, const Json::Value& config) Language::Language(const std::string& id, const Json::Value& config)
: AButton(config, "language", id, "{}", 0, true) { : ALabel(config, "language", id, "{}", 0, true) {
is_variant_displayed = format_.find("{variant}") != std::string::npos; is_variant_displayed = format_.find("{variant}") != std::string::npos;
if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) { if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) {
displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortName); displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortName);
@ -99,7 +99,7 @@ auto Language::update() -> void {
format_, fmt::arg("short", layout_.short_name), format_, fmt::arg("short", layout_.short_name),
fmt::arg("shortDescription", layout_.short_description), fmt::arg("long", layout_.full_name), fmt::arg("shortDescription", layout_.short_description), fmt::arg("long", layout_.full_name),
fmt::arg("variant", layout_.variant), fmt::arg("flag", layout_.country_flag()))); fmt::arg("variant", layout_.variant), fmt::arg("flag", layout_.country_flag())));
label_->set_markup(display_layout); label_.set_markup(display_layout);
if (tooltipEnabled()) { if (tooltipEnabled()) {
if (tooltip_format_ != "") { if (tooltip_format_ != "") {
auto tooltip_display_layout = trim( auto tooltip_display_layout = trim(
@ -107,22 +107,22 @@ auto Language::update() -> void {
fmt::arg("shortDescription", layout_.short_description), fmt::arg("shortDescription", layout_.short_description),
fmt::arg("long", layout_.full_name), fmt::arg("variant", layout_.variant), fmt::arg("long", layout_.full_name), fmt::arg("variant", layout_.variant),
fmt::arg("flag", layout_.country_flag()))); fmt::arg("flag", layout_.country_flag())));
button_.set_tooltip_markup(tooltip_display_layout); label_.set_tooltip_markup(tooltip_display_layout);
} else { } else {
button_.set_tooltip_markup(display_layout); label_.set_tooltip_markup(display_layout);
} }
} }
event_box_.show(); event_box_.show();
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
auto Language::set_current_layout(std::string current_layout) -> void { auto Language::set_current_layout(std::string current_layout) -> void {
button_.get_style_context()->remove_class(layout_.short_name); label_.get_style_context()->remove_class(layout_.short_name);
layout_ = layouts_map_[current_layout]; layout_ = layouts_map_[current_layout];
button_.get_style_context()->add_class(layout_.short_name); label_.get_style_context()->add_class(layout_.short_name);
} }
auto Language::init_layouts_map(const std::vector<std::string>& used_layouts) -> void { auto Language::init_layouts_map(const std::vector<std::string>& used_layouts) -> void {

View File

@ -5,7 +5,7 @@
namespace waybar::modules::sway { namespace waybar::modules::sway {
Mode::Mode(const std::string& id, const Json::Value& config) Mode::Mode(const std::string& id, const Json::Value& config)
: AButton(config, "mode", id, "{}", 0, true) { : ALabel(config, "mode", id, "{}", 0, true) {
ipc_.subscribe(R"(["mode"])"); ipc_.subscribe(R"(["mode"])");
ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent)); ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent));
// Launch worker // Launch worker
@ -42,14 +42,14 @@ auto Mode::update() -> void {
if (mode_.empty()) { if (mode_.empty()) {
event_box_.hide(); event_box_.hide();
} else { } else {
label_->set_markup(fmt::format(format_, mode_)); label_.set_markup(fmt::format(format_, mode_));
if (tooltipEnabled()) { if (tooltipEnabled()) {
button_.set_tooltip_text(mode_); label_.set_tooltip_text(mode_);
} }
event_box_.show(); event_box_.show();
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
} // namespace waybar::modules::sway } // namespace waybar::modules::sway

View File

@ -7,7 +7,7 @@
#endif #endif
waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config) waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config)
: AButton(config, "temperature", id, "{temperatureC}°C", 10) { : ALabel(config, "temperature", id, "{temperatureC}°C", 10) {
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
// try to read sysctl? // try to read sysctl?
#else #else
@ -42,9 +42,9 @@ auto waybar::modules::Temperature::update() -> void {
auto format = format_; auto format = format_;
if (critical) { if (critical) {
format = config_["format-critical"].isString() ? config_["format-critical"].asString() : format; format = config_["format-critical"].isString() ? config_["format-critical"].asString() : format;
button_.get_style_context()->add_class("critical"); label_.get_style_context()->add_class("critical");
} else { } else {
button_.get_style_context()->remove_class("critical"); label_.get_style_context()->remove_class("critical");
} }
if (format.empty()) { if (format.empty()) {
@ -55,21 +55,21 @@ auto waybar::modules::Temperature::update() -> void {
} }
auto max_temp = config_["critical-threshold"].isInt() ? config_["critical-threshold"].asInt() : 0; auto max_temp = config_["critical-threshold"].isInt() ? config_["critical-threshold"].asInt() : 0;
label_->set_markup(fmt::format(format, fmt::arg("temperatureC", temperature_c), label_.set_markup(fmt::format(format, fmt::arg("temperatureC", temperature_c),
fmt::arg("temperatureF", temperature_f), fmt::arg("temperatureF", temperature_f),
fmt::arg("temperatureK", temperature_k), fmt::arg("temperatureK", temperature_k),
fmt::arg("icon", getIcon(temperature_c, "", max_temp)))); fmt::arg("icon", getIcon(temperature_c, "", max_temp))));
if (tooltipEnabled()) { if (tooltipEnabled()) {
std::string tooltip_format = "{temperatureC}°C"; std::string tooltip_format = "{temperatureC}°C";
if (config_["tooltip-format"].isString()) { if (config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString(); tooltip_format = config_["tooltip-format"].asString();
} }
button_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("temperatureC", temperature_c), label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("temperatureC", temperature_c),
fmt::arg("temperatureF", temperature_f), fmt::arg("temperatureF", temperature_f),
fmt::arg("temperatureK", temperature_k))); fmt::arg("temperatureK", temperature_k)));
} }
// Call parent update // Call parent update
AButton::update(); ALabel::update();
} }
float waybar::modules::Temperature::getTemperature() { float waybar::modules::Temperature::getTemperature() {

View File

@ -6,7 +6,12 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <iostream>
#include "gdkmm/cursor.h"
#include "gdkmm/event.h"
#include "gdkmm/types.h"
#include "sigc++/functors/mem_fun.h"
#include "sigc++/functors/ptr_fun.h"
#if HAVE_CPU_LINUX #if HAVE_CPU_LINUX
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
@ -16,15 +21,33 @@
#include <time.h> #include <time.h>
#endif #endif
const static int LEFT_MOUSE_BUTTON_CODE = 1;
namespace waybar::modules { namespace waybar::modules {
User::User(const std::string& id, const Json::Value& config) User::User(const std::string& id, const Json::Value& config)
: AIconLabel(config, "user", id, "{user} {work_H}:{work_M}", 60, false, false, true) { : AIconLabel(config, "user", id, "{user} {work_H}:{work_M}", 60, false, true, true) {
if (AIconLabel::iconEnabled()) { if (AIconLabel::iconEnabled()) {
this->init_avatar(AIconLabel::config_); this->init_avatar(AIconLabel::config_);
} }
this->init_update_worker(); this->init_update_worker();
} }
bool User::handleToggle(GdkEventButton* const& e) {
if (AIconLabel::config_["open-on-click"].isBool() &&
AIconLabel::config_["open-on-click"].asBool() && e->button == LEFT_MOUSE_BUTTON_CODE) {
std::string openPath = this->get_user_home_dir();
if (AIconLabel::config_["open-path"].isString()) {
std::string customPath = AIconLabel::config_["open-path"].asString();
if (!customPath.empty()) {
openPath = std::move(customPath);
}
}
Gio::AppInfo::launch_default_for_uri("file:///" + openPath);
}
return true;
}
long User::uptime_as_seconds() { long User::uptime_as_seconds() {
long uptime = 0; long uptime = 0;
@ -45,9 +68,9 @@ long User::uptime_as_seconds() {
return uptime; return uptime;
} }
std::string User::get_user_login() { return Glib::get_user_name(); } std::string User::get_user_login() const { return Glib::get_user_name(); }
std::string User::get_user_home_dir() { return Glib::get_home_dir(); } std::string User::get_user_home_dir() const { return Glib::get_home_dir(); }
void User::init_update_worker() { void User::init_update_worker() {
this->thread_ = [this] { this->thread_ = [this] {
@ -74,7 +97,7 @@ void User::init_avatar(const Json::Value& config) {
this->init_default_user_avatar(width, width); this->init_default_user_avatar(width, width);
} }
std::string User::get_default_user_avatar_path() { std::string User::get_default_user_avatar_path() const {
return this->get_user_home_dir() + "/" + ".face"; return this->get_user_home_dir() + "/" + ".face";
} }
@ -83,8 +106,8 @@ void User::init_default_user_avatar(int width, int height) {
} }
void User::init_user_avatar(const std::string& path, int width, int height) { void User::init_user_avatar(const std::string& path, int width, int height) {
this->pixbuf_ = Gdk::Pixbuf::create_from_file(path, width, height); Glib::RefPtr<Gdk::Pixbuf> pixbuf_ = Gdk::Pixbuf::create_from_file(path, width, height);
AIconLabel::image_.set(this->pixbuf_); AIconLabel::image_.set(pixbuf_);
} }
auto User::update() -> void { auto User::update() -> void {

180
src/modules/wireplumber.cpp Normal file
View File

@ -0,0 +1,180 @@
#include "modules/wireplumber.hpp"
waybar::modules::Wireplumber::Wireplumber(const std::string& id, const Json::Value& config)
: ALabel(config, "wireplumber", id, "{volume}%"),
wp_core_(nullptr),
apis_(nullptr),
om_(nullptr),
pending_plugins_(0),
muted_(false),
volume_(0.0),
node_id_(0) {
wp_init(WP_INIT_ALL);
wp_core_ = wp_core_new(NULL, NULL);
apis_ = g_ptr_array_new_with_free_func(g_object_unref);
om_ = wp_object_manager_new();
prepare();
loadRequiredApiModules();
if (!wp_core_connect(wp_core_)) {
throw std::runtime_error("Could not connect to PipeWire\n");
}
g_signal_connect_swapped(om_, "installed", (GCallback)onObjectManagerInstalled, this);
activatePlugins();
dp.emit();
}
waybar::modules::Wireplumber::~Wireplumber() {
g_clear_pointer(&apis_, g_ptr_array_unref);
g_clear_object(&om_);
g_clear_object(&wp_core_);
}
uint32_t waybar::modules::Wireplumber::getDefaultNodeId(waybar::modules::Wireplumber* self) {
uint32_t id;
g_autoptr(WpPlugin) def_nodes_api = wp_plugin_find(self->wp_core_, "default-nodes-api");
if (!def_nodes_api) {
throw std::runtime_error("Default nodes API is not loaded\n");
}
g_signal_emit_by_name(def_nodes_api, "get-default-node", "Audio/Sink", &id);
if (id <= 0 || id >= G_MAXUINT32) {
auto err = fmt::format("'{}' is not a valid ID (returned by default-nodes-api)\n", id);
throw std::runtime_error(err);
}
return id;
}
void waybar::modules::Wireplumber::updateNodeName(waybar::modules::Wireplumber* self) {
auto proxy = static_cast<WpPipewireObject*>(wp_object_manager_lookup(
self->om_, WP_TYPE_GLOBAL_PROXY, WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY, "object.id", "=u",
self->node_id_, NULL));
if (!proxy) {
throw std::runtime_error(fmt::format("Object '{}' not found\n", self->node_id_));
}
g_autoptr(WpProperties) properties = wp_pipewire_object_get_properties(proxy);
properties = wp_properties_ensure_unique_owner(properties);
self->node_name_ = wp_properties_get(properties, "node.nick");
}
void waybar::modules::Wireplumber::updateVolume(waybar::modules::Wireplumber* self) {
double vol;
GVariant* variant = NULL;
g_autoptr(WpPlugin) mixer_api = wp_plugin_find(self->wp_core_, "mixer-api");
g_signal_emit_by_name(mixer_api, "get-volume", self->node_id_, &variant);
if (!variant) {
auto err = fmt::format("Node {} does not support volume\n", self->node_id_);
throw std::runtime_error(err);
}
g_variant_lookup(variant, "volume", "d", &vol);
g_variant_lookup(variant, "mute", "b", &self->muted_);
g_clear_pointer(&variant, g_variant_unref);
self->volume_ = std::round(vol * 100.0F);
self->dp.emit();
}
void waybar::modules::Wireplumber::onObjectManagerInstalled(waybar::modules::Wireplumber* self) {
self->node_id_ =
self->config_["node-id"].isInt() ? self->config_["node-id"].asInt() : getDefaultNodeId(self);
g_autoptr(WpPlugin) mixer_api = wp_plugin_find(self->wp_core_, "mixer-api");
updateVolume(self);
updateNodeName(self);
g_signal_connect_swapped(mixer_api, "changed", (GCallback)updateVolume, self);
}
void waybar::modules::Wireplumber::onPluginActivated(WpObject* p, GAsyncResult* res,
waybar::modules::Wireplumber* self) {
g_autoptr(GError) error = NULL;
if (!wp_object_activate_finish(p, res, &error)) {
throw std::runtime_error(error->message);
}
if (--self->pending_plugins_ == 0) {
wp_core_install_object_manager(self->wp_core_, self->om_);
}
}
void waybar::modules::Wireplumber::activatePlugins() {
for (uint16_t i = 0; i < apis_->len; i++) {
WpPlugin* plugin = static_cast<WpPlugin*>(g_ptr_array_index(apis_, i));
pending_plugins_++;
wp_object_activate(WP_OBJECT(plugin), WP_PLUGIN_FEATURE_ENABLED, NULL,
(GAsyncReadyCallback)onPluginActivated, this);
}
}
void waybar::modules::Wireplumber::prepare() {
wp_object_manager_add_interest(om_, WP_TYPE_NODE, NULL);
wp_object_manager_request_object_features(om_, WP_TYPE_GLOBAL_PROXY,
WP_PIPEWIRE_OBJECT_FEATURES_MINIMAL);
}
void waybar::modules::Wireplumber::loadRequiredApiModules() {
g_autoptr(GError) error = NULL;
if (!wp_core_load_component(wp_core_, "libwireplumber-module-default-nodes-api", "module", NULL,
&error)) {
throw std::runtime_error(error->message);
}
if (!wp_core_load_component(wp_core_, "libwireplumber-module-mixer-api", "module", NULL,
&error)) {
throw std::runtime_error(error->message);
}
g_ptr_array_add(apis_, wp_plugin_find(wp_core_, "default-nodes-api"));
g_ptr_array_add(apis_, ({
WpPlugin* p = wp_plugin_find(wp_core_, "mixer-api");
g_object_set(G_OBJECT(p), "scale", 1 /* cubic */, NULL);
p;
}));
}
auto waybar::modules::Wireplumber::update() -> void {
auto format = format_;
std::string tooltip_format;
if (muted_) {
format = config_["format-muted"].isString() ? config_["format-muted"].asString() : format;
label_.get_style_context()->add_class("muted");
} else {
label_.get_style_context()->remove_class("muted");
}
std::string markup =
fmt::format(format, fmt::arg("node_name", node_name_), fmt::arg("volume", volume_));
label_.set_markup(markup);
getState(volume_);
if (tooltipEnabled()) {
if (tooltip_format.empty() && config_["tooltip-format"].isString()) {
tooltip_format = config_["tooltip-format"].asString();
}
if (!tooltip_format.empty()) {
label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("node_name", node_name_),
fmt::arg("volume", volume_)));
} else {
label_.set_tooltip_text(node_name_);
}
}
// Call parent update
ALabel::update();
}

View File

@ -6,6 +6,7 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <stdexcept>
#include <vector> #include <vector>
#include "gtkmm/widget.h" #include "gtkmm/widget.h"
@ -66,10 +67,13 @@ auto WorkspaceManager::workspace_comparator() const
auto is_name_less = lhs->get_name() < rhs->get_name(); auto is_name_less = lhs->get_name() < rhs->get_name();
auto is_name_eq = lhs->get_name() == rhs->get_name(); auto is_name_eq = lhs->get_name() == rhs->get_name();
auto is_coords_less = lhs->get_coords() < rhs->get_coords(); auto is_coords_less = lhs->get_coords() < rhs->get_coords();
auto is_number_less = std::stoi(lhs->get_name()) < std::stoi(rhs->get_name());
if (sort_by_number_) { if (sort_by_number_) {
return is_number_less; try {
auto is_number_less = std::stoi(lhs->get_name()) < std::stoi(rhs->get_name());
return is_number_less;
} catch (std::invalid_argument) {
}
} }
if (sort_by_name_) { if (sort_by_name_) {

9
subprojects/jsoncpp.wrap Normal file
View File

@ -0,0 +1,9 @@
[wrap-file]
directory = jsoncpp-1.9.5
source_url = https://github.com/open-source-parsers/jsoncpp/archive/1.9.5.tar.gz
source_filename = jsoncpp-1.9.5.tar.gz
source_hash = f409856e5920c18d0c2fb85276e24ee607d2a09b5e7d5f0a371368903c275da2
[provide]
jsoncpp = jsoncpp_dep