mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-11-04 09:42:42 +01:00 
			
		
		
		
	Merge branch 'master' into freebsd_temperature_use_thermal-zone_config
This commit is contained in:
		
							
								
								
									
										57
									
								
								ext4fuse.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								ext4fuse.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
class MacFuseRequirement < Requirement
 | 
			
		||||
  fatal true
 | 
			
		||||
 | 
			
		||||
  satisfy(build_env: false) { self.class.binary_mac_fuse_installed? }
 | 
			
		||||
 | 
			
		||||
  def self.binary_mac_fuse_installed?
 | 
			
		||||
    File.exist?("/usr/local/include/fuse/fuse.h") &&
 | 
			
		||||
      !File.symlink?("/usr/local/include/fuse")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  env do
 | 
			
		||||
    ENV.append_path "PKG_CONFIG_PATH", HOMEBREW_LIBRARY/"Homebrew/os/mac/pkgconfig/fuse"
 | 
			
		||||
    ENV.append_path "PKG_CONFIG_PATH", "/usr/local/lib/pkgconfig"
 | 
			
		||||
 | 
			
		||||
    unless HOMEBREW_PREFIX.to_s == "/usr/local"
 | 
			
		||||
      ENV.append_path "HOMEBREW_LIBRARY_PATHS", "/usr/local/lib"
 | 
			
		||||
      ENV.append_path "HOMEBREW_INCLUDE_PATHS", "/usr/local/include/fuse"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def message
 | 
			
		||||
    "macFUSE is required. Please run `brew install --cask macfuse` first."
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
class Ext4fuse < Formula
 | 
			
		||||
  desc "Read-only implementation of ext4 for FUSE"
 | 
			
		||||
  homepage "https://github.com/gerard/ext4fuse"
 | 
			
		||||
  url "https://github.com/gerard/ext4fuse/archive/v0.1.3.tar.gz"
 | 
			
		||||
  sha256 "550f1e152c4de7d4ea517ee1c708f57bfebb0856281c508511419db45aa3ca9f"
 | 
			
		||||
  license "GPL-2.0"
 | 
			
		||||
  head "https://github.com/gerard/ext4fuse.git"
 | 
			
		||||
 | 
			
		||||
  bottle do
 | 
			
		||||
    sha256 cellar: :any, catalina:    "446dde5e84b058966ead0cde5e38e9411f465732527f6decfa1c0dcdbd4abbef"
 | 
			
		||||
    sha256 cellar: :any, mojave:      "88c4918bf5218f99295e539fe4499152edb3b60b6659e44ddd68b22359f512ae"
 | 
			
		||||
    sha256 cellar: :any, high_sierra: "fc69c8993afd0ffc16a73c9c036ca8f83c77ac2a19b3237f76f9ccee8b30bbc9"
 | 
			
		||||
    sha256 cellar: :any, sierra:      "fe8bbe7cd5362f00ff06ef750926bf349d60563c20b0ecf212778631c8912ba2"
 | 
			
		||||
    sha256 cellar: :any, el_capitan:  "291047c821b7b205d85be853fb005510c6ab01bd4c2a2193c192299b6f049d35"
 | 
			
		||||
    sha256 cellar: :any, yosemite:    "b11f564b7e7c08af0b0a3e9854973d39809bf2d8a56014f4882772b2f7307ac1"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  depends_on "pkg-config" => :build
 | 
			
		||||
 | 
			
		||||
  on_macos do
 | 
			
		||||
    depends_on MacFuseRequirement => :build
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  on_linux do
 | 
			
		||||
    depends_on "libfuse"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def install
 | 
			
		||||
    system "make"
 | 
			
		||||
    bin.install "ext4fuse"
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										34
									
								
								include/AButton.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								include/AButton.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <glibmm/markup.h>
 | 
			
		||||
#include <gtkmm/button.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
 | 
			
		||||
@@ -23,8 +23,8 @@
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef HAVE_HYPRLAND
 | 
			
		||||
#include "modules/hyprland/backend.hpp"
 | 
			
		||||
#include "modules/hyprland/window.hpp"
 | 
			
		||||
#include "modules/hyprland/language.hpp"
 | 
			
		||||
#include "modules/hyprland/window.hpp"
 | 
			
		||||
#endif
 | 
			
		||||
#if defined(__linux__) && !defined(NO_FILESYSTEM)
 | 
			
		||||
#include "modules/battery.hpp"
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/json.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -14,7 +14,7 @@ struct udev_device;
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Backlight : public ALabel {
 | 
			
		||||
class Backlight : public AButton {
 | 
			
		||||
  class BacklightDev {
 | 
			
		||||
   public:
 | 
			
		||||
    BacklightDev() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
@@ -24,7 +24,7 @@ namespace fs = std::experimental::filesystem;
 | 
			
		||||
namespace fs = std::filesystem;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class Battery : public ALabel {
 | 
			
		||||
class Battery : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Battery(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Battery();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#ifdef WANT_RFKILL
 | 
			
		||||
#include "util/rfkill.hpp"
 | 
			
		||||
#endif
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Bluetooth : public ALabel {
 | 
			
		||||
class Bluetooth : public AButton {
 | 
			
		||||
  struct ControllerInfo {
 | 
			
		||||
    std::string path;
 | 
			
		||||
    std::string address;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
#include <date/tz.h>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar {
 | 
			
		||||
@@ -14,7 +14,7 @@ namespace modules {
 | 
			
		||||
const std::string kCalendarPlaceholder = "calendar";
 | 
			
		||||
const std::string KTimezonedTimeListPlaceholder = "timezoned_time_list";
 | 
			
		||||
 | 
			
		||||
class Clock : public ALabel {
 | 
			
		||||
class Clock : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Clock(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Clock() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,12 @@
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Cpu : public ALabel {
 | 
			
		||||
class Cpu : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Cpu(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Cpu() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,14 @@
 | 
			
		||||
#include <csignal>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/command.hpp"
 | 
			
		||||
#include "util/json.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Custom : public ALabel {
 | 
			
		||||
class Custom : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Custom(const std::string&, const std::string&, const Json::Value&);
 | 
			
		||||
  ~Custom();
 | 
			
		||||
 
 | 
			
		||||
@@ -5,13 +5,13 @@
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/format.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Disk : public ALabel {
 | 
			
		||||
class Disk : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Disk(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Disk() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,28 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules::hyprland {
 | 
			
		||||
class IPC {
 | 
			
		||||
public:
 | 
			
		||||
 public:
 | 
			
		||||
  IPC() { startIPC(); }
 | 
			
		||||
 | 
			
		||||
  void registerForIPC(const std::string&, std::function<void(const std::string&)>);
 | 
			
		||||
 | 
			
		||||
  std::string getSocket1Reply(const std::string& rq);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 private:
 | 
			
		||||
  void startIPC();
 | 
			
		||||
  void parseIPC(const std::string&);
 | 
			
		||||
 | 
			
		||||
 void startIPC();
 | 
			
		||||
 void parseIPC(const std::string&);
 | 
			
		||||
 | 
			
		||||
 std::mutex callbackMutex;
 | 
			
		||||
 std::deque<std::pair<std::string, std::function<void(const std::string&)>>> callbacks;
 | 
			
		||||
  std::mutex callbackMutex;
 | 
			
		||||
  std::deque<std::pair<std::string, std::function<void(const std::string&)>>> callbacks;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
inline std::unique_ptr<IPC> gIPC;
 | 
			
		||||
inline bool modulesReady = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
};  // namespace waybar::modules::hyprland
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,20 @@
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "bar.hpp"
 | 
			
		||||
#include "modules/hyprland/backend.hpp"
 | 
			
		||||
#include "util/json.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules::hyprland {
 | 
			
		||||
 | 
			
		||||
class Language : public waybar::ALabel {
 | 
			
		||||
public:
 | 
			
		||||
class Language : public waybar::AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Language(const std::string&, const waybar::Bar&, const Json::Value&);
 | 
			
		||||
  ~Language() = default;
 | 
			
		||||
 | 
			
		||||
  auto update() -> void;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 private:
 | 
			
		||||
  void onEvent(const std::string&);
 | 
			
		||||
 | 
			
		||||
  void initLanguage();
 | 
			
		||||
@@ -26,4 +26,4 @@ private:
 | 
			
		||||
  std::string layoutName_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}  // namespace waybar::modules::hyprland
 | 
			
		||||
 
 | 
			
		||||
@@ -10,13 +10,13 @@
 | 
			
		||||
namespace waybar::modules::hyprland {
 | 
			
		||||
 | 
			
		||||
class Window : public waybar::ALabel {
 | 
			
		||||
public:
 | 
			
		||||
 public:
 | 
			
		||||
  Window(const std::string&, const waybar::Bar&, const Json::Value&);
 | 
			
		||||
  ~Window() = default;
 | 
			
		||||
 | 
			
		||||
  auto update() -> void;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 private:
 | 
			
		||||
  void onEvent(const std::string&);
 | 
			
		||||
 | 
			
		||||
  std::mutex mutex_;
 | 
			
		||||
@@ -25,4 +25,4 @@ private:
 | 
			
		||||
  std::string lastView;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}  // namespace waybar::modules::hyprland
 | 
			
		||||
@@ -2,13 +2,13 @@
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "bar.hpp"
 | 
			
		||||
#include "client.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class IdleInhibitor : public ALabel {
 | 
			
		||||
class IdleInhibitor : public AButton {
 | 
			
		||||
  sigc::connection timeout_;
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
@@ -20,6 +20,7 @@ class IdleInhibitor : public ALabel {
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  bool handleToggle(GdkEventButton* const& e);
 | 
			
		||||
  void toggleStatus();
 | 
			
		||||
 | 
			
		||||
  const Bar& bar_;
 | 
			
		||||
  struct zwp_idle_inhibitor_v1* idle_inhibitor_;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "bar.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Inhibitor : public ALabel {
 | 
			
		||||
class Inhibitor : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Inhibitor(const std::string&, const waybar::Bar&, const Json::Value&);
 | 
			
		||||
  ~Inhibitor() override;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,11 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <jack/jack.h>
 | 
			
		||||
#include <jack/thread.h>
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
@@ -11,26 +13,26 @@ namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class JACK : public ALabel {
 | 
			
		||||
 public:
 | 
			
		||||
  JACK(const std::string&, const Json::Value&);
 | 
			
		||||
  JACK(const std::string &, const Json::Value &);
 | 
			
		||||
  ~JACK() = default;
 | 
			
		||||
  auto update() -> void;
 | 
			
		||||
 | 
			
		||||
  int                 bufSize(jack_nframes_t size);
 | 
			
		||||
  int                 sampleRate(jack_nframes_t rate);
 | 
			
		||||
  int                 xrun();
 | 
			
		||||
  void                shutdown();
 | 
			
		||||
  int bufSize(jack_nframes_t size);
 | 
			
		||||
  int sampleRate(jack_nframes_t rate);
 | 
			
		||||
  int xrun();
 | 
			
		||||
  void shutdown();
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
  std::string         JACKState();
 | 
			
		||||
  std::string JACKState();
 | 
			
		||||
 | 
			
		||||
  jack_client_t*      client_;
 | 
			
		||||
  jack_nframes_t      bufsize_;
 | 
			
		||||
  jack_nframes_t      samplerate_;
 | 
			
		||||
  unsigned int        xruns_;
 | 
			
		||||
  float               load_;
 | 
			
		||||
  bool                running_;
 | 
			
		||||
  std::mutex          mutex_;
 | 
			
		||||
  std::string         state_;
 | 
			
		||||
  jack_client_t *client_;
 | 
			
		||||
  jack_nframes_t bufsize_;
 | 
			
		||||
  jack_nframes_t samplerate_;
 | 
			
		||||
  unsigned int xruns_;
 | 
			
		||||
  float load_;
 | 
			
		||||
  bool running_;
 | 
			
		||||
  std::mutex mutex_;
 | 
			
		||||
  std::string state_;
 | 
			
		||||
  util::SleeperThread thread_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,12 @@
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Memory : public ALabel {
 | 
			
		||||
class Memory : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Memory(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Memory() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -7,12 +7,12 @@
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "modules/mpd/state.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class MPD : public ALabel {
 | 
			
		||||
class MPD : public AButton {
 | 
			
		||||
  friend class detail::Context;
 | 
			
		||||
 | 
			
		||||
  // State machine
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
#include <condition_variable>
 | 
			
		||||
#include <thread>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
class MPD;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
#include <optional>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
#ifdef WANT_RFKILL
 | 
			
		||||
#include "util/rfkill.hpp"
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Network : public ALabel {
 | 
			
		||||
class Network : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Network(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Network();
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,11 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Pulseaudio : public ALabel {
 | 
			
		||||
class Pulseaudio : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Pulseaudio(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Pulseaudio();
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,12 @@
 | 
			
		||||
 | 
			
		||||
#include <fmt/chrono.h>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Clock : public ALabel {
 | 
			
		||||
class Clock : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Clock(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Clock() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Sndio : public ALabel {
 | 
			
		||||
class Sndio : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Sndio(const std::string &, const Json::Value &);
 | 
			
		||||
  ~Sndio();
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "bar.hpp"
 | 
			
		||||
#include "client.hpp"
 | 
			
		||||
#include "modules/sway/ipc/client.hpp"
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules::sway {
 | 
			
		||||
 | 
			
		||||
class Language : public ALabel, public sigc::trackable {
 | 
			
		||||
class Language : public AButton, public sigc::trackable {
 | 
			
		||||
 public:
 | 
			
		||||
  Language(const std::string& id, const Json::Value& config);
 | 
			
		||||
  ~Language() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
#include <fmt/format.h>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "bar.hpp"
 | 
			
		||||
#include "client.hpp"
 | 
			
		||||
#include "modules/sway/ipc/client.hpp"
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules::sway {
 | 
			
		||||
 | 
			
		||||
class Mode : public ALabel, public sigc::trackable {
 | 
			
		||||
class Mode : public AButton, public sigc::trackable {
 | 
			
		||||
 public:
 | 
			
		||||
  Mode(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Mode() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@
 | 
			
		||||
 | 
			
		||||
#include <fstream>
 | 
			
		||||
 | 
			
		||||
#include "ALabel.hpp"
 | 
			
		||||
#include "AButton.hpp"
 | 
			
		||||
#include "util/sleeper_thread.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
class Temperature : public ALabel {
 | 
			
		||||
class Temperature : public AButton {
 | 
			
		||||
 public:
 | 
			
		||||
  Temperature(const std::string&, const Json::Value&);
 | 
			
		||||
  ~Temperature() = default;
 | 
			
		||||
 
 | 
			
		||||
@@ -56,9 +56,10 @@ struct formatter<pow_format> {
 | 
			
		||||
      fraction /= base;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto max_width = 4            // coeff in {:.3g} format
 | 
			
		||||
                     + 1          // prefix from units array
 | 
			
		||||
                     + s.binary_  // for the 'i' in GiB.
 | 
			
		||||
    auto number_width = 5              // coeff in {:.1f} format
 | 
			
		||||
                        + s.binary_;   // potential 4th digit before the decimal point
 | 
			
		||||
    auto max_width = number_width + 1  // prefix from units array
 | 
			
		||||
                     + s.binary_       // for the 'i' in GiB.
 | 
			
		||||
                     + s.unit_.length();
 | 
			
		||||
 | 
			
		||||
    const char* format;
 | 
			
		||||
@@ -69,15 +70,16 @@ struct formatter<pow_format> {
 | 
			
		||||
      case '<':
 | 
			
		||||
        return format_to(ctx.out(), "{:<{}}", fmt::format("{}", s), max_width);
 | 
			
		||||
      case '=':
 | 
			
		||||
        format = "{coefficient:<4.3g}{padding}{prefix}{unit}";
 | 
			
		||||
        format = "{coefficient:<{number_width}.1f}{padding}{prefix}{unit}";
 | 
			
		||||
        break;
 | 
			
		||||
      case 0:
 | 
			
		||||
      default:
 | 
			
		||||
        format = "{coefficient:.3g}{prefix}{unit}";
 | 
			
		||||
        format = "{coefficient:.1f}{prefix}{unit}";
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    return format_to(
 | 
			
		||||
        ctx.out(), format, fmt::arg("coefficient", fraction),
 | 
			
		||||
        fmt::arg("number_width", number_width),
 | 
			
		||||
        fmt::arg("prefix", std::string() + units[pow] + ((s.binary_ && pow) ? "i" : "")),
 | 
			
		||||
        fmt::arg("unit", s.unit_),
 | 
			
		||||
        fmt::arg("padding", pow         ? ""
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								include/util/sanitize_str.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								include/util/sanitize_str.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
namespace waybar::util {
 | 
			
		||||
std::string sanitize_string(std::string str);
 | 
			
		||||
}  // namespace waybar::util
 | 
			
		||||
@@ -63,6 +63,11 @@ screensaving, also known as "presentation mode".
 | 
			
		||||
	typeof: double ++
 | 
			
		||||
	Threshold to be used when scrolling.
 | 
			
		||||
 | 
			
		||||
*start-activated*: ++
 | 
			
		||||
  typeof: bool ++
 | 
			
		||||
  default: *false* ++
 | 
			
		||||
  Whether the inhibit should be activated when starting waybar.
 | 
			
		||||
 | 
			
		||||
*timeout*: ++
 | 
			
		||||
	typeof: double ++
 | 
			
		||||
	The number of minutes the inhibit should last.
 | 
			
		||||
 
 | 
			
		||||
@@ -101,6 +101,10 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
 | 
			
		||||
	default: 100 ++
 | 
			
		||||
	The maximum volume that can be set, in percentage.
 | 
			
		||||
 | 
			
		||||
*ignored-sinks*: ++
 | 
			
		||||
	typeof: array ++
 | 
			
		||||
	Sinks in this list will not be shown as the active sink by Waybar. Entries should be the sink's description field.
 | 
			
		||||
 | 
			
		||||
# FORMAT REPLACEMENTS
 | 
			
		||||
 | 
			
		||||
*{desc}*: Pulseaudio port's description, for bluetooth it'll be the device name.
 | 
			
		||||
 
 | 
			
		||||
@@ -143,6 +143,7 @@ endif
 | 
			
		||||
src_files = files(
 | 
			
		||||
    'src/factory.cpp',
 | 
			
		||||
    'src/AModule.cpp',
 | 
			
		||||
    'src/AButton.cpp',
 | 
			
		||||
    'src/ALabel.cpp',
 | 
			
		||||
    'src/AIconLabel.cpp',
 | 
			
		||||
    'src/modules/custom.cpp',
 | 
			
		||||
@@ -154,7 +155,8 @@ src_files = files(
 | 
			
		||||
    'src/client.cpp',
 | 
			
		||||
    'src/config.cpp',
 | 
			
		||||
    'src/group.cpp',
 | 
			
		||||
    'src/util/ustring_clen.cpp'
 | 
			
		||||
    'src/util/ustring_clen.cpp',
 | 
			
		||||
    'src/util/sanitize_str.cpp'
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
if is_linux
 | 
			
		||||
 
 | 
			
		||||
@@ -34,6 +34,12 @@ window#waybar.chromium {
 | 
			
		||||
    border: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
 | 
			
		||||
button:hover {
 | 
			
		||||
    background: inherit;
 | 
			
		||||
    box-shadow: inset 0 -3px #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#workspaces button {
 | 
			
		||||
    padding: 0 5px;
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
@@ -45,10 +51,8 @@ window#waybar.chromium {
 | 
			
		||||
    border-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
 | 
			
		||||
#workspaces button:hover {
 | 
			
		||||
    background: rgba(0, 0, 0, 0.2);
 | 
			
		||||
    box-shadow: inset 0 -3px #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#workspaces button.focused {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										154
									
								
								src/AButton.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/AButton.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,154 @@
 | 
			
		||||
#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);
 | 
			
		||||
  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
 | 
			
		||||
@@ -87,7 +87,7 @@ int waybar::modules::Backlight::BacklightDev::get_max() const { return max_; }
 | 
			
		||||
void waybar::modules::Backlight::BacklightDev::set_max(int max) { max_ = max; }
 | 
			
		||||
 | 
			
		||||
waybar::modules::Backlight::Backlight(const std::string &id, const Json::Value &config)
 | 
			
		||||
    : ALabel(config, "backlight", id, "{percent}%", 2),
 | 
			
		||||
    : AButton(config, "backlight", id, "{percent}%", 2),
 | 
			
		||||
      preferred_device_(config["device"].isString() ? config["device"].asString() : "") {
 | 
			
		||||
  // Get initial state
 | 
			
		||||
  {
 | 
			
		||||
@@ -174,19 +174,19 @@ auto waybar::modules::Backlight::update() -> void {
 | 
			
		||||
 | 
			
		||||
    const uint8_t percent =
 | 
			
		||||
        best->get_max() == 0 ? 100 : round(best->get_actual() * 100.0f / best->get_max());
 | 
			
		||||
    label_.set_markup(fmt::format(format_, fmt::arg("percent", std::to_string(percent)),
 | 
			
		||||
                                  fmt::arg("icon", getIcon(percent))));
 | 
			
		||||
    label_->set_markup(fmt::format(format_, fmt::arg("percent", std::to_string(percent)),
 | 
			
		||||
                                   fmt::arg("icon", getIcon(percent))));
 | 
			
		||||
    getState(percent);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (!previous_best_.has_value()) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    label_.set_markup("");
 | 
			
		||||
    label_->set_markup("");
 | 
			
		||||
  }
 | 
			
		||||
  previous_best_ = best == nullptr ? std::nullopt : std::optional{*best};
 | 
			
		||||
  previous_format_ = format_;
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class ForwardIt>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
#include <spdlog/spdlog.h>
 | 
			
		||||
 | 
			
		||||
waybar::modules::Battery::Battery(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "battery", id, "{capacity}%", 60) {
 | 
			
		||||
    : AButton(config, "battery", id, "{capacity}%", 60) {
 | 
			
		||||
  battery_watch_fd_ = inotify_init1(IN_CLOEXEC);
 | 
			
		||||
  if (battery_watch_fd_ == -1) {
 | 
			
		||||
    throw std::runtime_error("Unable to listen batteries.");
 | 
			
		||||
@@ -108,7 +108,7 @@ void waybar::modules::Battery::refreshBatteries() {
 | 
			
		||||
      }
 | 
			
		||||
      auto adap_defined = config_["adapter"].isString();
 | 
			
		||||
      if (((adap_defined && dir_name == config_["adapter"].asString()) || !adap_defined) &&
 | 
			
		||||
          fs::exists(node.path() / "online")) {
 | 
			
		||||
          (fs::exists(node.path() / "online") || fs::exists(node.path() / "status"))) {
 | 
			
		||||
        adapter_ = node.path();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -156,124 +156,305 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
 | 
			
		||||
  std::lock_guard<std::mutex> guard(battery_list_mutex_);
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    uint32_t total_power = 0;   // μW
 | 
			
		||||
    uint32_t total_power = 0;  // μW
 | 
			
		||||
    bool total_power_exists = false;
 | 
			
		||||
    uint32_t total_energy = 0;  // μWh
 | 
			
		||||
    bool total_energy_exists = false;
 | 
			
		||||
    uint32_t total_energy_full = 0;
 | 
			
		||||
    bool total_energy_full_exists = false;
 | 
			
		||||
    uint32_t total_energy_full_design = 0;
 | 
			
		||||
    uint32_t total_capacity{0};
 | 
			
		||||
    bool total_energy_full_design_exists = false;
 | 
			
		||||
    uint32_t total_capacity = 0;
 | 
			
		||||
    bool total_capacity_exists = false;
 | 
			
		||||
 | 
			
		||||
    std::string status = "Unknown";
 | 
			
		||||
    for (auto const& item : batteries_) {
 | 
			
		||||
      auto bat = item.first;
 | 
			
		||||
      uint32_t power_now;
 | 
			
		||||
      uint32_t energy_full;
 | 
			
		||||
      uint32_t energy_now;
 | 
			
		||||
      uint32_t energy_full_design;
 | 
			
		||||
      uint32_t capacity{0};
 | 
			
		||||
      std::string _status;
 | 
			
		||||
      std::getline(std::ifstream(bat / "status"), _status);
 | 
			
		||||
 | 
			
		||||
      // Some battery will report current and charge in μA/μAh.
 | 
			
		||||
      // Scale these by the voltage to get μW/μWh.
 | 
			
		||||
      if (fs::exists(bat / "current_now") || fs::exists(bat / "current_avg")) {
 | 
			
		||||
        uint32_t voltage_now;
 | 
			
		||||
        uint32_t current_now;
 | 
			
		||||
        uint32_t charge_now;
 | 
			
		||||
        uint32_t charge_full;
 | 
			
		||||
        uint32_t charge_full_design;
 | 
			
		||||
        // Some batteries have only *_avg, not *_now
 | 
			
		||||
        if (fs::exists(bat / "voltage_now"))
 | 
			
		||||
          std::ifstream(bat / "voltage_now") >> voltage_now;
 | 
			
		||||
        else
 | 
			
		||||
          std::ifstream(bat / "voltage_avg") >> voltage_now;
 | 
			
		||||
        if (fs::exists(bat / "current_now"))
 | 
			
		||||
          std::ifstream(bat / "current_now") >> current_now;
 | 
			
		||||
        else
 | 
			
		||||
          std::ifstream(bat / "current_avg") >> current_now;
 | 
			
		||||
        std::ifstream(bat / "charge_full") >> charge_full;
 | 
			
		||||
        std::ifstream(bat / "charge_full_design") >> charge_full_design;
 | 
			
		||||
        if (fs::exists(bat / "charge_now"))
 | 
			
		||||
          std::ifstream(bat / "charge_now") >> charge_now;
 | 
			
		||||
        else {
 | 
			
		||||
          // charge_now is missing on some systems, estimate using capacity.
 | 
			
		||||
          uint32_t capacity;
 | 
			
		||||
          std::ifstream(bat / "capacity") >> capacity;
 | 
			
		||||
          charge_now = (capacity * charge_full) / 100;
 | 
			
		||||
        }
 | 
			
		||||
        power_now = ((uint64_t)current_now * (uint64_t)voltage_now) / 1000000;
 | 
			
		||||
        energy_now = ((uint64_t)charge_now * (uint64_t)voltage_now) / 1000000;
 | 
			
		||||
        energy_full = ((uint64_t)charge_full * (uint64_t)voltage_now) / 1000000;
 | 
			
		||||
        energy_full_design = ((uint64_t)charge_full_design * (uint64_t)voltage_now) / 1000000;
 | 
			
		||||
      }  // Gamepads such as PS Dualshock provide the only capacity
 | 
			
		||||
      else if (fs::exists(bat / "energy_now") && fs::exists(bat / "energy_full")) {
 | 
			
		||||
        std::ifstream(bat / "power_now") >> power_now;
 | 
			
		||||
        std::ifstream(bat / "energy_now") >> energy_now;
 | 
			
		||||
        std::ifstream(bat / "energy_full") >> energy_full;
 | 
			
		||||
        std::ifstream(bat / "energy_full_design") >> energy_full_design;
 | 
			
		||||
      } else {
 | 
			
		||||
 | 
			
		||||
      uint32_t capacity = 0;
 | 
			
		||||
      bool capacity_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "capacity")) {
 | 
			
		||||
        capacity_exists = true;
 | 
			
		||||
        std::ifstream(bat / "capacity") >> capacity;
 | 
			
		||||
        power_now = 0;
 | 
			
		||||
        energy_now = 0;
 | 
			
		||||
        energy_full = 0;
 | 
			
		||||
        energy_full_design = 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t current_now = 0;
 | 
			
		||||
      bool current_now_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "current_now")) {
 | 
			
		||||
        current_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "current_now") >> current_now;
 | 
			
		||||
      } else if (fs::exists(bat / "current_avg")) {
 | 
			
		||||
        current_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "current_avg") >> current_now;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t voltage_now = 0;
 | 
			
		||||
      bool voltage_now_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "voltage_now")) {
 | 
			
		||||
        voltage_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "voltage_now") >> voltage_now;
 | 
			
		||||
      } else if (fs::exists(bat / "voltage_avg")) {
 | 
			
		||||
        voltage_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "voltage_avg") >> voltage_now;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t charge_full = 0;
 | 
			
		||||
      bool charge_full_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "charge_full")) {
 | 
			
		||||
        charge_full_exists = true;
 | 
			
		||||
        std::ifstream(bat / "charge_full") >> charge_full;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t charge_full_design = 0;
 | 
			
		||||
      bool charge_full_design_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "charge_full_design")) {
 | 
			
		||||
        charge_full_design_exists = true;
 | 
			
		||||
        std::ifstream(bat / "charge_full_design") >> charge_full_design;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t charge_now = 0;
 | 
			
		||||
      bool charge_now_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "charge_now")) {
 | 
			
		||||
        charge_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "charge_now") >> charge_now;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t power_now = 0;
 | 
			
		||||
      bool power_now_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "power_now")) {
 | 
			
		||||
        power_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "power_now") >> power_now;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t energy_now = 0;
 | 
			
		||||
      bool energy_now_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "energy_now")) {
 | 
			
		||||
        energy_now_exists = true;
 | 
			
		||||
        std::ifstream(bat / "energy_now") >> energy_now;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t energy_full = 0;
 | 
			
		||||
      bool energy_full_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "energy_full")) {
 | 
			
		||||
        energy_full_exists = true;
 | 
			
		||||
        std::ifstream(bat / "energy_full") >> energy_full;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      uint32_t energy_full_design = 0;
 | 
			
		||||
      bool energy_full_design_exists = false;
 | 
			
		||||
      if (fs::exists(bat / "energy_full_design")) {
 | 
			
		||||
        energy_full_design_exists = true;
 | 
			
		||||
        std::ifstream(bat / "energy_full_design") >> energy_full_design;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!voltage_now_exists) {
 | 
			
		||||
        if (power_now_exists && current_now_exists && current_now != 0) {
 | 
			
		||||
          voltage_now_exists = true;
 | 
			
		||||
          voltage_now = 1000000 * (uint64_t)power_now / (uint64_t)current_now;
 | 
			
		||||
        } else if (energy_full_design_exists && charge_full_design_exists &&
 | 
			
		||||
                   charge_full_design != 0) {
 | 
			
		||||
          voltage_now_exists = true;
 | 
			
		||||
          voltage_now = 1000000 * (uint64_t)energy_full_design / (uint64_t)charge_full_design;
 | 
			
		||||
        } else if (energy_now_exists) {
 | 
			
		||||
          if (charge_now_exists && charge_now != 0) {
 | 
			
		||||
            voltage_now_exists = true;
 | 
			
		||||
            voltage_now = 1000000 * (uint64_t)energy_now / (uint64_t)charge_now;
 | 
			
		||||
          } else if (capacity_exists && charge_full_exists) {
 | 
			
		||||
            charge_now_exists = true;
 | 
			
		||||
            charge_now = (uint64_t)charge_full * (uint64_t)capacity / 100;
 | 
			
		||||
            if (charge_full != 0 && capacity != 0) {
 | 
			
		||||
              voltage_now_exists = true;
 | 
			
		||||
              voltage_now =
 | 
			
		||||
                  1000000 * (uint64_t)energy_now * 100 / (uint64_t)charge_full / (uint64_t)capacity;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        } else if (energy_full_exists) {
 | 
			
		||||
          if (charge_full_exists && charge_full != 0) {
 | 
			
		||||
            voltage_now_exists = true;
 | 
			
		||||
            voltage_now = 1000000 * (uint64_t)energy_full / (uint64_t)charge_full;
 | 
			
		||||
          } else if (charge_now_exists && capacity_exists) {
 | 
			
		||||
            if (capacity != 0) {
 | 
			
		||||
              charge_full_exists = true;
 | 
			
		||||
              charge_full = 100 * (uint64_t)charge_now / (uint64_t)capacity;
 | 
			
		||||
            }
 | 
			
		||||
            if (charge_now != 0) {
 | 
			
		||||
              voltage_now_exists = true;
 | 
			
		||||
              voltage_now =
 | 
			
		||||
                  10000 * (uint64_t)energy_full * (uint64_t)capacity / (uint64_t)charge_now;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!capacity_exists) {
 | 
			
		||||
        if (charge_now_exists && charge_full_exists && charge_full != 0) {
 | 
			
		||||
          capacity_exists = true;
 | 
			
		||||
          capacity = 100 * (uint64_t)charge_now / (uint64_t)charge_full;
 | 
			
		||||
        } else if (energy_now_exists && energy_full_exists && energy_full != 0) {
 | 
			
		||||
          capacity_exists = true;
 | 
			
		||||
          capacity = 100 * (uint64_t)energy_now / (uint64_t)energy_full;
 | 
			
		||||
        } else if (charge_now_exists && energy_full_exists && voltage_now_exists) {
 | 
			
		||||
          if (!charge_full_exists && voltage_now != 0) {
 | 
			
		||||
            charge_full_exists = true;
 | 
			
		||||
            charge_full = 1000000 * (uint64_t)energy_full / (uint64_t)voltage_now;
 | 
			
		||||
          }
 | 
			
		||||
          if (energy_full != 0) {
 | 
			
		||||
            capacity_exists = true;
 | 
			
		||||
            capacity = (uint64_t)charge_now * (uint64_t)voltage_now / 10000 / (uint64_t)energy_full;
 | 
			
		||||
          }
 | 
			
		||||
        } else if (charge_full_exists && energy_now_exists && voltage_now_exists) {
 | 
			
		||||
          if (!charge_now_exists && voltage_now != 0) {
 | 
			
		||||
            charge_now_exists = true;
 | 
			
		||||
            charge_now = 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now;
 | 
			
		||||
          }
 | 
			
		||||
          if (voltage_now != 0 && charge_full != 0) {
 | 
			
		||||
            capacity_exists = true;
 | 
			
		||||
            capacity = 100 * 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now /
 | 
			
		||||
                       (uint64_t)charge_full;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!energy_now_exists && voltage_now_exists) {
 | 
			
		||||
        if (charge_now_exists) {
 | 
			
		||||
          energy_now_exists = true;
 | 
			
		||||
          energy_now = (uint64_t)charge_now * (uint64_t)voltage_now / 1000000;
 | 
			
		||||
        } else if (capacity_exists && charge_full_exists) {
 | 
			
		||||
          charge_now_exists = true;
 | 
			
		||||
          charge_now = (uint64_t)capacity * (uint64_t)charge_full / 100;
 | 
			
		||||
          energy_now_exists = true;
 | 
			
		||||
          energy_now =
 | 
			
		||||
              (uint64_t)voltage_now * (uint64_t)capacity * (uint64_t)charge_full / 1000000 / 100;
 | 
			
		||||
        } else if (capacity_exists && energy_full) {
 | 
			
		||||
          if (voltage_now != 0) {
 | 
			
		||||
            charge_full_exists = true;
 | 
			
		||||
            charge_full = 1000000 * (uint64_t)energy_full / (uint64_t)voltage_now;
 | 
			
		||||
            charge_now_exists = true;
 | 
			
		||||
            charge_now = (uint64_t)capacity * 10000 * (uint64_t)energy_full / (uint64_t)voltage_now;
 | 
			
		||||
          }
 | 
			
		||||
          energy_now_exists = true;
 | 
			
		||||
          energy_now = (uint64_t)capacity * (uint64_t)energy_full / 100;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!energy_full_exists && voltage_now_exists) {
 | 
			
		||||
        if (charge_full_exists) {
 | 
			
		||||
          energy_full_exists = true;
 | 
			
		||||
          energy_full = (uint64_t)charge_full * (uint64_t)voltage_now / 1000000;
 | 
			
		||||
        } else if (charge_now_exists && capacity_exists && capacity != 0) {
 | 
			
		||||
          charge_full_exists = true;
 | 
			
		||||
          charge_full = 100 * (uint64_t)charge_now / (uint64_t)capacity;
 | 
			
		||||
          energy_full_exists = true;
 | 
			
		||||
          energy_full = (uint64_t)charge_now * (uint64_t)voltage_now / (uint64_t)capacity / 10000;
 | 
			
		||||
        } else if (capacity_exists && energy_now) {
 | 
			
		||||
          if (voltage_now != 0) {
 | 
			
		||||
            charge_now_exists = true;
 | 
			
		||||
            charge_now = 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now;
 | 
			
		||||
          }
 | 
			
		||||
          if (capacity != 0) {
 | 
			
		||||
            energy_full_exists = true;
 | 
			
		||||
            energy_full = 100 * (uint64_t)energy_now / (uint64_t)capacity;
 | 
			
		||||
            if (voltage_now != 0) {
 | 
			
		||||
              charge_full_exists = true;
 | 
			
		||||
              charge_full =
 | 
			
		||||
                  100 * 1000000 * (uint64_t)energy_now / (uint64_t)voltage_now / (uint64_t)capacity;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!power_now_exists && voltage_now_exists && current_now_exists) {
 | 
			
		||||
        power_now_exists = true;
 | 
			
		||||
        power_now = (uint64_t)voltage_now * (uint64_t)current_now / 1000000;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!energy_full_design_exists && voltage_now_exists && charge_full_design_exists) {
 | 
			
		||||
        energy_full_design_exists = true;
 | 
			
		||||
        energy_full_design = (uint64_t)voltage_now * (uint64_t)charge_full_design / 1000000;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Show the "smallest" status among all batteries
 | 
			
		||||
      if (status_gt(status, _status)) {
 | 
			
		||||
        status = _status;
 | 
			
		||||
      if (status_gt(status, _status)) status = _status;
 | 
			
		||||
 | 
			
		||||
      if (power_now_exists) {
 | 
			
		||||
        total_power_exists = true;
 | 
			
		||||
        total_power += power_now;
 | 
			
		||||
      }
 | 
			
		||||
      if (energy_now_exists) {
 | 
			
		||||
        total_energy_exists = true;
 | 
			
		||||
        total_energy += energy_now;
 | 
			
		||||
      }
 | 
			
		||||
      if (energy_full_exists) {
 | 
			
		||||
        total_energy_full_exists = true;
 | 
			
		||||
        total_energy_full += energy_full;
 | 
			
		||||
      }
 | 
			
		||||
      if (energy_full_design_exists) {
 | 
			
		||||
        total_energy_full_design_exists = true;
 | 
			
		||||
        total_energy_full_design += energy_full_design;
 | 
			
		||||
      }
 | 
			
		||||
      if (capacity_exists) {
 | 
			
		||||
        total_capacity_exists = true;
 | 
			
		||||
        total_capacity += capacity;
 | 
			
		||||
      }
 | 
			
		||||
      total_power += power_now;
 | 
			
		||||
      total_energy += energy_now;
 | 
			
		||||
      total_energy_full += energy_full;
 | 
			
		||||
      total_energy_full_design += energy_full_design;
 | 
			
		||||
      total_capacity += capacity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!adapter_.empty() && status == "Discharging") {
 | 
			
		||||
      bool online;
 | 
			
		||||
      std::string current_status;
 | 
			
		||||
      std::ifstream(adapter_ / "online") >> online;
 | 
			
		||||
      if (online) {
 | 
			
		||||
        status = "Plugged";
 | 
			
		||||
      std::getline(std::ifstream(adapter_ / "status"), current_status);
 | 
			
		||||
      if (online && current_status != "Discharging") status = "Plugged";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float time_remaining{0.0f};
 | 
			
		||||
    if (status == "Discharging" && total_power_exists && total_energy_exists) {
 | 
			
		||||
      if (total_power != 0) time_remaining = (float)total_energy / total_power;
 | 
			
		||||
    } else if (status == "Charging" && total_energy_exists && total_energy_full_exists &&
 | 
			
		||||
               total_power_exists) {
 | 
			
		||||
      if (total_power != 0)
 | 
			
		||||
        time_remaining = -(float)(total_energy_full - total_energy) / total_power;
 | 
			
		||||
      // If we've turned positive it means the battery is past 100% and so just report that as no
 | 
			
		||||
      // time remaining
 | 
			
		||||
      if (time_remaining > 0.0f) time_remaining = 0.0f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    float calculated_capacity{0.0f};
 | 
			
		||||
    if (total_capacity_exists) {
 | 
			
		||||
      if (total_capacity > 0.0f)
 | 
			
		||||
        calculated_capacity = (float)total_capacity;
 | 
			
		||||
      else if (total_energy_full_exists && total_energy_exists) {
 | 
			
		||||
        if (total_energy_full > 0.0f)
 | 
			
		||||
          calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    float time_remaining = 0;
 | 
			
		||||
    if (status == "Discharging" && total_power != 0) {
 | 
			
		||||
      time_remaining = (float)total_energy / total_power;
 | 
			
		||||
    } else if (status == "Charging" && total_power != 0) {
 | 
			
		||||
      time_remaining = -(float)(total_energy_full - total_energy) / total_power;
 | 
			
		||||
      if (time_remaining > 0.0f) {
 | 
			
		||||
        // If we've turned positive it means the battery is past 100% and so
 | 
			
		||||
        // just report that as no time remaining
 | 
			
		||||
        time_remaining = 0.0f;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    float capacity{0.0f};
 | 
			
		||||
    if (total_energy_full > 0.0f) {
 | 
			
		||||
      capacity = ((float)total_energy * 100.0f / (float)total_energy_full);
 | 
			
		||||
    } else {
 | 
			
		||||
      capacity = (float)total_capacity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Handle design-capacity
 | 
			
		||||
    if (config_["design-capacity"].isBool() ? config_["design-capacity"].asBool() : false) {
 | 
			
		||||
      capacity = ((float)total_energy * 100.0f / (float)total_energy_full_design);
 | 
			
		||||
    if ((config_["design-capacity"].isBool() ? config_["design-capacity"].asBool() : false) &&
 | 
			
		||||
        total_energy_exists && total_energy_full_design_exists) {
 | 
			
		||||
      if (total_energy_full_design > 0.0f)
 | 
			
		||||
        calculated_capacity = ((float)total_energy * 100.0f / (float)total_energy_full_design);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Handle full-at
 | 
			
		||||
    if (config_["full-at"].isUInt()) {
 | 
			
		||||
      auto full_at = config_["full-at"].asUInt();
 | 
			
		||||
      if (full_at < 100) {
 | 
			
		||||
        capacity = 100.f * capacity / full_at;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (capacity > 100.f) {
 | 
			
		||||
      // This can happen when the battery is calibrating and goes above 100%
 | 
			
		||||
      // Handle it gracefully by clamping at 100%
 | 
			
		||||
      capacity = 100.f;
 | 
			
		||||
    }
 | 
			
		||||
    uint8_t cap = round(capacity);
 | 
			
		||||
    if (cap == 100 && status == "Charging") {
 | 
			
		||||
      // If we've reached 100% just mark as full as some batteries can stay
 | 
			
		||||
      // stuck reporting they're still charging but not yet done
 | 
			
		||||
      status = "Full";
 | 
			
		||||
      if (full_at < 100) calculated_capacity = 100.f * calculated_capacity / full_at;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Handle it gracefully by clamping at 100%
 | 
			
		||||
    // This can happen when the battery is calibrating and goes above 100%
 | 
			
		||||
    if (calculated_capacity > 100.f) calculated_capacity = 100.f;
 | 
			
		||||
 | 
			
		||||
    uint8_t cap = round(calculated_capacity);
 | 
			
		||||
    // If we've reached 100% just mark as full as some batteries can stay stuck reporting they're
 | 
			
		||||
    // still charging but not yet done
 | 
			
		||||
    if (cap == 100 && status == "Charging") status = "Full";
 | 
			
		||||
 | 
			
		||||
    return {cap, time_remaining, status, total_power / 1e6};
 | 
			
		||||
  } catch (const std::exception& e) {
 | 
			
		||||
    spdlog::error("Battery: {}", e.what());
 | 
			
		||||
@@ -284,11 +465,13 @@ const std::tuple<uint8_t, float, std::string, float> waybar::modules::Battery::g
 | 
			
		||||
const std::string waybar::modules::Battery::getAdapterStatus(uint8_t capacity) const {
 | 
			
		||||
  if (!adapter_.empty()) {
 | 
			
		||||
    bool online;
 | 
			
		||||
    std::string status;
 | 
			
		||||
    std::ifstream(adapter_ / "online") >> online;
 | 
			
		||||
    std::getline(std::ifstream(adapter_ / "status"), status);
 | 
			
		||||
    if (capacity == 100) {
 | 
			
		||||
      return "Full";
 | 
			
		||||
    }
 | 
			
		||||
    if (online) {
 | 
			
		||||
    if (online && status != "Discharging") {
 | 
			
		||||
      return "Plugged";
 | 
			
		||||
    }
 | 
			
		||||
    return "Discharging";
 | 
			
		||||
@@ -309,7 +492,8 @@ const std::string waybar::modules::Battery::formatTimeRemaining(float hoursRemai
 | 
			
		||||
    format = config_["format-time"].asString();
 | 
			
		||||
  }
 | 
			
		||||
  std::string zero_pad_minutes = fmt::format("{:02d}", minutes);
 | 
			
		||||
  return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", minutes), fmt::arg("m", zero_pad_minutes));
 | 
			
		||||
  return fmt::format(format, fmt::arg("H", full_hours), fmt::arg("M", minutes),
 | 
			
		||||
                     fmt::arg("m", zero_pad_minutes));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto waybar::modules::Battery::update() -> void {
 | 
			
		||||
@@ -346,14 +530,14 @@ auto waybar::modules::Battery::update() -> void {
 | 
			
		||||
    } else if (config_["tooltip-format"].isString()) {
 | 
			
		||||
      tooltip_format = config_["tooltip-format"].asString();
 | 
			
		||||
    }
 | 
			
		||||
    label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("timeTo", tooltip_text_default),
 | 
			
		||||
                                        fmt::arg("capacity", capacity),
 | 
			
		||||
                                        fmt::arg("time", time_remaining_formatted)));
 | 
			
		||||
    button_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("timeTo", tooltip_text_default),
 | 
			
		||||
                                         fmt::arg("capacity", capacity),
 | 
			
		||||
                                         fmt::arg("time", time_remaining_formatted)));
 | 
			
		||||
  }
 | 
			
		||||
  if (!old_status_.empty()) {
 | 
			
		||||
    label_.get_style_context()->remove_class(old_status_);
 | 
			
		||||
    button_.get_style_context()->remove_class(old_status_);
 | 
			
		||||
  }
 | 
			
		||||
  label_.get_style_context()->add_class(status);
 | 
			
		||||
  button_.get_style_context()->add_class(status);
 | 
			
		||||
  old_status_ = status;
 | 
			
		||||
  if (!state.empty() && config_["format-" + status + "-" + state].isString()) {
 | 
			
		||||
    format = config_["format-" + status + "-" + state].asString();
 | 
			
		||||
@@ -367,10 +551,10 @@ auto waybar::modules::Battery::update() -> void {
 | 
			
		||||
  } else {
 | 
			
		||||
    event_box_.show();
 | 
			
		||||
    auto icons = std::vector<std::string>{status + "-" + state, status, state};
 | 
			
		||||
    label_.set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("power", power),
 | 
			
		||||
                                  fmt::arg("icon", getIcon(capacity, icons)),
 | 
			
		||||
                                  fmt::arg("time", time_remaining_formatted)));
 | 
			
		||||
    label_->set_markup(fmt::format(format, fmt::arg("capacity", capacity), fmt::arg("power", power),
 | 
			
		||||
                                   fmt::arg("icon", getIcon(capacity, icons)),
 | 
			
		||||
                                   fmt::arg("time", time_remaining_formatted)));
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ auto getUcharProperty(GDBusProxy* proxy, const char* property_name) -> unsigned
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
waybar::modules::Bluetooth::Bluetooth(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "bluetooth", id, " {status}", 10),
 | 
			
		||||
    : AButton(config, "bluetooth", id, " {status}", 10),
 | 
			
		||||
#ifdef WANT_RFKILL
 | 
			
		||||
      rfkill_{RFKILL_TYPE_BLUETOOTH},
 | 
			
		||||
#endif
 | 
			
		||||
@@ -189,10 +189,10 @@ auto waybar::modules::Bluetooth::update() -> void {
 | 
			
		||||
  format_.empty() ? event_box_.hide() : event_box_.show();
 | 
			
		||||
 | 
			
		||||
  auto update_style_context = [this](const std::string& style_class, bool in_next_state) {
 | 
			
		||||
    if (in_next_state && !label_.get_style_context()->has_class(style_class)) {
 | 
			
		||||
      label_.get_style_context()->add_class(style_class);
 | 
			
		||||
    } else if (!in_next_state && label_.get_style_context()->has_class(style_class)) {
 | 
			
		||||
      label_.get_style_context()->remove_class(style_class);
 | 
			
		||||
    if (in_next_state && !button_.get_style_context()->has_class(style_class)) {
 | 
			
		||||
      button_.get_style_context()->add_class(style_class);
 | 
			
		||||
    } else if (!in_next_state && button_.get_style_context()->has_class(style_class)) {
 | 
			
		||||
      button_.get_style_context()->remove_class(style_class);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  update_style_context("discoverable", cur_controller_.discoverable);
 | 
			
		||||
@@ -204,7 +204,7 @@ auto waybar::modules::Bluetooth::update() -> void {
 | 
			
		||||
  update_style_context(state, true);
 | 
			
		||||
  state_ = state;
 | 
			
		||||
 | 
			
		||||
  label_.set_markup(fmt::format(
 | 
			
		||||
  label_->set_markup(fmt::format(
 | 
			
		||||
      format_, fmt::arg("status", state_), fmt::arg("num_connections", connected_devices_.size()),
 | 
			
		||||
      fmt::arg("controller_address", cur_controller_.address),
 | 
			
		||||
      fmt::arg("controller_address_type", cur_controller_.address_type),
 | 
			
		||||
@@ -245,7 +245,7 @@ auto waybar::modules::Bluetooth::update() -> void {
 | 
			
		||||
        device_enumerate_.erase(0, 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    label_.set_tooltip_text(fmt::format(
 | 
			
		||||
    button_.set_tooltip_text(fmt::format(
 | 
			
		||||
        tooltip_format, fmt::arg("status", state_),
 | 
			
		||||
        fmt::arg("num_connections", connected_devices_.size()),
 | 
			
		||||
        fmt::arg("controller_address", cur_controller_.address),
 | 
			
		||||
@@ -259,7 +259,7 @@ auto waybar::modules::Bluetooth::update() -> void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NOTE: only for when the org.bluez.Battery1 interface is added/removed after/before a device is
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
using waybar::waybar_time;
 | 
			
		||||
 | 
			
		||||
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "clock", id, "{:%H:%M}", 60, false, false, true),
 | 
			
		||||
    : AButton(config, "clock", id, "{:%H:%M}", 60, false, false, true),
 | 
			
		||||
      current_time_zone_idx_(0),
 | 
			
		||||
      is_calendar_in_tooltip_(false),
 | 
			
		||||
      is_timezoned_list_in_tooltip_(false) {
 | 
			
		||||
@@ -107,7 +107,7 @@ auto waybar::modules::Clock::update() -> void {
 | 
			
		||||
  } else {
 | 
			
		||||
    text = fmt::format(format_, wtime);
 | 
			
		||||
  }
 | 
			
		||||
  label_.set_markup(text);
 | 
			
		||||
  label_->set_markup(text);
 | 
			
		||||
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    if (config_["tooltip-format"].isString()) {
 | 
			
		||||
@@ -119,12 +119,12 @@ auto waybar::modules::Clock::update() -> void {
 | 
			
		||||
      text =
 | 
			
		||||
          fmt::format(tooltip_format, wtime, fmt::arg(kCalendarPlaceholder.c_str(), calendar_lines),
 | 
			
		||||
                      fmt::arg(KTimezonedTimeListPlaceholder.c_str(), timezoned_time_lines));
 | 
			
		||||
      label_.set_tooltip_markup(text);
 | 
			
		||||
      button_.set_tooltip_markup(text);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool waybar::modules::Clock::handleScroll(GdkEventScroll* e) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
waybar::modules::Cpu::Cpu(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "cpu", id, "{usage}%", 10) {
 | 
			
		||||
    : AButton(config, "cpu", id, "{usage}%", 10) {
 | 
			
		||||
  thread_ = [this] {
 | 
			
		||||
    dp.emit();
 | 
			
		||||
    thread_.sleep_for(interval_);
 | 
			
		||||
@@ -23,7 +23,7 @@ auto waybar::modules::Cpu::update() -> void {
 | 
			
		||||
  auto [cpu_usage, tooltip] = getCpuUsage();
 | 
			
		||||
  auto [max_frequency, min_frequency, avg_frequency] = getCpuFrequency();
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    label_.set_tooltip_text(tooltip);
 | 
			
		||||
    button_.set_tooltip_text(tooltip);
 | 
			
		||||
  }
 | 
			
		||||
  auto format = format_;
 | 
			
		||||
  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);
 | 
			
		||||
      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
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double waybar::modules::Cpu::getCpuLoad() {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
waybar::modules::Custom::Custom(const std::string& name, const std::string& id,
 | 
			
		||||
                                const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "custom-" + name, id, "{}"),
 | 
			
		||||
    : AButton(config, "custom-" + name, id, "{}"),
 | 
			
		||||
      name_(name),
 | 
			
		||||
      id_(id),
 | 
			
		||||
      percentage_(0),
 | 
			
		||||
@@ -103,13 +103,13 @@ void waybar::modules::Custom::handleEvent() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool waybar::modules::Custom::handleScroll(GdkEventScroll* e) {
 | 
			
		||||
  auto ret = ALabel::handleScroll(e);
 | 
			
		||||
  auto ret = AButton::handleScroll(e);
 | 
			
		||||
  handleEvent();
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool waybar::modules::Custom::handleToggle(GdkEventButton* const& e) {
 | 
			
		||||
  auto ret = ALabel::handleToggle(e);
 | 
			
		||||
  auto ret = AButton::handleToggle(e);
 | 
			
		||||
  handleEvent();
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
@@ -125,37 +125,39 @@ auto waybar::modules::Custom::update() -> void {
 | 
			
		||||
    } else {
 | 
			
		||||
      parseOutputRaw();
 | 
			
		||||
    }
 | 
			
		||||
    auto str = fmt::format(format_, text_, fmt::arg("alt", alt_),
 | 
			
		||||
    auto str = fmt::format(format_, Glib::Markup::escape_text(text_).raw(), fmt::arg("alt", alt_),
 | 
			
		||||
                           fmt::arg("icon", getIcon(percentage_, alt_)),
 | 
			
		||||
                           fmt::arg("percentage", percentage_));
 | 
			
		||||
    if (str.empty()) {
 | 
			
		||||
      event_box_.hide();
 | 
			
		||||
    } else {
 | 
			
		||||
      label_.set_markup(str);
 | 
			
		||||
      label_->set_markup(str);
 | 
			
		||||
      if (tooltipEnabled()) {
 | 
			
		||||
        if (text_ == tooltip_) {
 | 
			
		||||
          if (label_.get_tooltip_markup() != str) {
 | 
			
		||||
            label_.set_tooltip_markup(str);
 | 
			
		||||
          if (button_.get_tooltip_markup() != str) {
 | 
			
		||||
            button_.set_tooltip_markup(str);
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          if (label_.get_tooltip_markup() != tooltip_) {
 | 
			
		||||
            label_.set_tooltip_markup(tooltip_);
 | 
			
		||||
          if (button_.get_tooltip_markup() != tooltip_) {
 | 
			
		||||
            button_.set_tooltip_markup(tooltip_);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      auto classes = label_.get_style_context()->list_classes();
 | 
			
		||||
      auto classes = button_.get_style_context()->list_classes();
 | 
			
		||||
      for (auto const& c : classes) {
 | 
			
		||||
        if (c == id_) continue;
 | 
			
		||||
        label_.get_style_context()->remove_class(c);
 | 
			
		||||
        button_.get_style_context()->remove_class(c);
 | 
			
		||||
      }
 | 
			
		||||
      for (auto const& c : class_) {
 | 
			
		||||
        label_.get_style_context()->add_class(c);
 | 
			
		||||
        button_.get_style_context()->add_class(c);
 | 
			
		||||
      }
 | 
			
		||||
      button_.get_style_context()->add_class("flat");
 | 
			
		||||
      button_.get_style_context()->add_class("text-button");
 | 
			
		||||
      event_box_.show();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void waybar::modules::Custom::parseOutputRaw() {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
using namespace waybar::util;
 | 
			
		||||
 | 
			
		||||
waybar::modules::Disk::Disk(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "disk", id, "{}%", 30), path_("/") {
 | 
			
		||||
    : AButton(config, "disk", id, "{}%", 30), path_("/") {
 | 
			
		||||
  thread_ = [this] {
 | 
			
		||||
    dp.emit();
 | 
			
		||||
    thread_.sleep_for(interval_);
 | 
			
		||||
@@ -58,7 +58,7 @@ auto waybar::modules::Disk::update() -> void {
 | 
			
		||||
    event_box_.hide();
 | 
			
		||||
  } else {
 | 
			
		||||
    event_box_.show();
 | 
			
		||||
    label_.set_markup(
 | 
			
		||||
    label_->set_markup(
 | 
			
		||||
        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("used", used), fmt::arg("percentage_used", percentage_used),
 | 
			
		||||
@@ -70,12 +70,12 @@ auto waybar::modules::Disk::update() -> void {
 | 
			
		||||
    if (config_["tooltip-format"].isString()) {
 | 
			
		||||
      tooltip_format = config_["tooltip-format"].asString();
 | 
			
		||||
    }
 | 
			
		||||
    label_.set_tooltip_text(
 | 
			
		||||
    button_.set_tooltip_text(
 | 
			
		||||
        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("used", used), fmt::arg("percentage_used", percentage_used),
 | 
			
		||||
                    fmt::arg("total", total), fmt::arg("path", path_)));
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,14 @@
 | 
			
		||||
#include <xkbcommon/xkbcommon.h>
 | 
			
		||||
#include <xkbcommon/xkbregistry.h>
 | 
			
		||||
 | 
			
		||||
#include <util/sanitize_str.hpp>
 | 
			
		||||
 | 
			
		||||
#include "modules/hyprland/backend.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules::hyprland {
 | 
			
		||||
 | 
			
		||||
Language::Language(const std::string& id, const Bar& bar, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "language", id, "{}", 0, true), bar_(bar) {
 | 
			
		||||
    : AButton(config, "language", id, "{}", 0, true), bar_(bar) {
 | 
			
		||||
  modulesReady = true;
 | 
			
		||||
 | 
			
		||||
  if (!gIPC.get()) {
 | 
			
		||||
@@ -19,8 +21,8 @@ Language::Language(const std::string& id, const Bar& bar, const Json::Value& con
 | 
			
		||||
  // get the active layout when open
 | 
			
		||||
  initLanguage();
 | 
			
		||||
 | 
			
		||||
  label_.hide();
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  button_.hide();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
 | 
			
		||||
  // register for hyprland ipc
 | 
			
		||||
  gIPC->registerForIPC("activelayout", [&](const std::string& ev) { this->onEvent(ev); });
 | 
			
		||||
@@ -30,13 +32,13 @@ auto Language::update() -> void {
 | 
			
		||||
  std::lock_guard<std::mutex> lg(mutex_);
 | 
			
		||||
 | 
			
		||||
  if (!format_.empty()) {
 | 
			
		||||
    label_.show();
 | 
			
		||||
    label_.set_markup(layoutName_);
 | 
			
		||||
    button_.show();
 | 
			
		||||
    label_->set_markup(layoutName_);
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.hide();
 | 
			
		||||
    button_.hide();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Language::onEvent(const std::string& ev) {
 | 
			
		||||
@@ -48,16 +50,6 @@ void Language::onEvent(const std::string& ev) {
 | 
			
		||||
  if (config_.isMember("keyboard-name") && keebName != config_["keyboard-name"].asString())
 | 
			
		||||
    return;  // ignore
 | 
			
		||||
 | 
			
		||||
  auto replaceAll = [](std::string str, const std::string& from,
 | 
			
		||||
                       const std::string& to) -> std::string {
 | 
			
		||||
    size_t start_pos = 0;
 | 
			
		||||
    while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
 | 
			
		||||
      str.replace(start_pos, from.length(), to);
 | 
			
		||||
      start_pos += to.length();
 | 
			
		||||
    }
 | 
			
		||||
    return str;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const auto BRIEFNAME = getShortFrom(layoutName);
 | 
			
		||||
 | 
			
		||||
  if (config_.isMember("format-" + BRIEFNAME)) {
 | 
			
		||||
@@ -67,7 +59,7 @@ void Language::onEvent(const std::string& ev) {
 | 
			
		||||
    layoutName = fmt::format(format_, layoutName);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  layoutName = replaceAll(layoutName, "&", "&");
 | 
			
		||||
  layoutName = waybar::util::sanitize_string(layoutName);
 | 
			
		||||
 | 
			
		||||
  if (layoutName == layoutName_) return;
 | 
			
		||||
 | 
			
		||||
@@ -128,4 +120,4 @@ std::string Language::getShortFrom(const std::string& fullName) {
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace waybar::modules::hyprland
 | 
			
		||||
}  // namespace waybar::modules::hyprland
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,8 @@
 | 
			
		||||
 | 
			
		||||
#include <spdlog/spdlog.h>
 | 
			
		||||
 | 
			
		||||
#include <util/sanitize_str.hpp>
 | 
			
		||||
 | 
			
		||||
#include "modules/hyprland/backend.hpp"
 | 
			
		||||
 | 
			
		||||
namespace waybar::modules::hyprland {
 | 
			
		||||
@@ -39,17 +41,7 @@ void Window::onEvent(const std::string& ev) {
 | 
			
		||||
  std::lock_guard<std::mutex> lg(mutex_);
 | 
			
		||||
  auto windowName = ev.substr(ev.find_first_of(',') + 1).substr(0, 256);
 | 
			
		||||
 | 
			
		||||
  auto replaceAll = [](std::string str, const std::string& from,
 | 
			
		||||
                       const std::string& to) -> std::string {
 | 
			
		||||
    size_t start_pos = 0;
 | 
			
		||||
    while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
 | 
			
		||||
      str.replace(start_pos, from.length(), to);
 | 
			
		||||
      start_pos += to.length();
 | 
			
		||||
    }
 | 
			
		||||
    return str;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  windowName = replaceAll(windowName, "&", "&");
 | 
			
		||||
  windowName = waybar::util::sanitize_string(windowName);
 | 
			
		||||
 | 
			
		||||
  if (windowName == lastView) return;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ bool waybar::modules::IdleInhibitor::status = false;
 | 
			
		||||
 | 
			
		||||
waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar& bar,
 | 
			
		||||
                                              const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "idle_inhibitor", id, "{status}"),
 | 
			
		||||
    : AButton(config, "idle_inhibitor", id, "{status}", 0, false, true),
 | 
			
		||||
      bar_(bar),
 | 
			
		||||
      idle_inhibitor_(nullptr),
 | 
			
		||||
      pid_(-1) {
 | 
			
		||||
@@ -16,6 +16,11 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar&
 | 
			
		||||
    throw std::runtime_error("idle-inhibit not available");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (waybar::modules::IdleInhibitor::modules.empty() && config_["start-activated"].isBool() &&
 | 
			
		||||
      config_["start-activated"].asBool() != status) {
 | 
			
		||||
    toggleStatus();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
 | 
			
		||||
  event_box_.signal_button_press_event().connect(
 | 
			
		||||
      sigc::mem_fun(*this, &IdleInhibitor::handleToggle));
 | 
			
		||||
@@ -44,13 +49,13 @@ waybar::modules::IdleInhibitor::~IdleInhibitor() {
 | 
			
		||||
auto waybar::modules::IdleInhibitor::update() -> void {
 | 
			
		||||
  // Check status
 | 
			
		||||
  if (status) {
 | 
			
		||||
    label_.get_style_context()->remove_class("deactivated");
 | 
			
		||||
    button_.get_style_context()->remove_class("deactivated");
 | 
			
		||||
    if (idle_inhibitor_ == nullptr) {
 | 
			
		||||
      idle_inhibitor_ = zwp_idle_inhibit_manager_v1_create_inhibitor(
 | 
			
		||||
          waybar::Client::inst()->idle_inhibit_manager, bar_.surface);
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.get_style_context()->remove_class("activated");
 | 
			
		||||
    button_.get_style_context()->remove_class("activated");
 | 
			
		||||
    if (idle_inhibitor_ != nullptr) {
 | 
			
		||||
      zwp_idle_inhibitor_v1_destroy(idle_inhibitor_);
 | 
			
		||||
      idle_inhibitor_ = nullptr;
 | 
			
		||||
@@ -58,11 +63,11 @@ auto waybar::modules::IdleInhibitor::update() -> void {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  std::string status_text = status ? "activated" : "deactivated";
 | 
			
		||||
  label_.set_markup(fmt::format(format_, fmt::arg("status", status_text),
 | 
			
		||||
                                fmt::arg("icon", getIcon(0, status_text))));
 | 
			
		||||
  label_.get_style_context()->add_class(status_text);
 | 
			
		||||
  label_->set_markup(fmt::format(format_, fmt::arg("status", status_text),
 | 
			
		||||
                                 fmt::arg("icon", getIcon(0, status_text))));
 | 
			
		||||
  button_.get_style_context()->add_class(status_text);
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    label_.set_tooltip_markup(
 | 
			
		||||
    button_.set_tooltip_markup(
 | 
			
		||||
        status ? fmt::format(config_["tooltip-format-activated"].isString()
 | 
			
		||||
                                 ? config_["tooltip-format-activated"].asString()
 | 
			
		||||
                                 : "{status}",
 | 
			
		||||
@@ -75,37 +80,41 @@ auto waybar::modules::IdleInhibitor::update() -> void {
 | 
			
		||||
                             fmt::arg("icon", getIcon(0, status_text))));
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void waybar::modules::IdleInhibitor::toggleStatus() {
 | 
			
		||||
  status = !status;
 | 
			
		||||
 | 
			
		||||
  if (timeout_.connected()) {
 | 
			
		||||
    /* cancel any already active timeout handler */
 | 
			
		||||
    timeout_.disconnect();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (status && config_["timeout"].isNumeric()) {
 | 
			
		||||
    auto timeoutMins = config_["timeout"].asDouble();
 | 
			
		||||
    int timeoutSecs = timeoutMins * 60;
 | 
			
		||||
 | 
			
		||||
    timeout_ = Glib::signal_timeout().connect_seconds(
 | 
			
		||||
        []() {
 | 
			
		||||
          /* intentionally not tied to a module instance lifetime
 | 
			
		||||
           * as the output with `this` can be disconnected
 | 
			
		||||
           */
 | 
			
		||||
          spdlog::info("deactivating idle_inhibitor by timeout");
 | 
			
		||||
          status = false;
 | 
			
		||||
          for (auto const& module : waybar::modules::IdleInhibitor::modules) {
 | 
			
		||||
            module->update();
 | 
			
		||||
          }
 | 
			
		||||
          /* disconnect */
 | 
			
		||||
          return false;
 | 
			
		||||
        },
 | 
			
		||||
        timeoutSecs);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
 | 
			
		||||
  if (e->button == 1) {
 | 
			
		||||
    status = !status;
 | 
			
		||||
 | 
			
		||||
    if (timeout_.connected()) {
 | 
			
		||||
      /* cancel any already active timeout handler */
 | 
			
		||||
      timeout_.disconnect();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (status && config_["timeout"].isNumeric()) {
 | 
			
		||||
      auto timeoutMins = config_["timeout"].asDouble();
 | 
			
		||||
      int timeoutSecs = timeoutMins * 60;
 | 
			
		||||
 | 
			
		||||
      timeout_ = Glib::signal_timeout().connect_seconds(
 | 
			
		||||
          []() {
 | 
			
		||||
            /* intentionally not tied to a module instance lifetime
 | 
			
		||||
             * as the output with `this` can be disconnected
 | 
			
		||||
             */
 | 
			
		||||
            spdlog::info("deactivating idle_inhibitor by timeout");
 | 
			
		||||
            status = false;
 | 
			
		||||
            for (auto const& module : waybar::modules::IdleInhibitor::modules) {
 | 
			
		||||
              module->update();
 | 
			
		||||
            }
 | 
			
		||||
            /* disconnect */
 | 
			
		||||
            return false;
 | 
			
		||||
          },
 | 
			
		||||
          timeoutSecs);
 | 
			
		||||
    }
 | 
			
		||||
    toggleStatus();
 | 
			
		||||
 | 
			
		||||
    // Make all other idle inhibitor modules update
 | 
			
		||||
    for (auto const& module : waybar::modules::IdleInhibitor::modules) {
 | 
			
		||||
@@ -115,6 +124,6 @@ bool waybar::modules::IdleInhibitor::handleToggle(GdkEventButton* const& e) {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  ALabel::handleToggle(e);
 | 
			
		||||
  AButton::handleToggle(e);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -98,7 +98,7 @@ auto getInhibitors(const Json::Value& config) -> std::string {
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
 | 
			
		||||
Inhibitor::Inhibitor(const std::string& id, const Bar& bar, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "inhibitor", id, "{status}", true),
 | 
			
		||||
    : AButton(config, "inhibitor", id, "{status}", true),
 | 
			
		||||
      dbus_(::dbus()),
 | 
			
		||||
      inhibitors_(::getInhibitors(config)) {
 | 
			
		||||
  event_box_.add_events(Gdk::BUTTON_PRESS_MASK);
 | 
			
		||||
@@ -117,16 +117,16 @@ auto Inhibitor::activated() -> bool { return handle_ != -1; }
 | 
			
		||||
auto Inhibitor::update() -> void {
 | 
			
		||||
  std::string status_text = activated() ? "activated" : "deactivated";
 | 
			
		||||
 | 
			
		||||
  label_.get_style_context()->remove_class(activated() ? "deactivated" : "activated");
 | 
			
		||||
  label_.set_markup(fmt::format(format_, fmt::arg("status", status_text),
 | 
			
		||||
                                fmt::arg("icon", getIcon(0, status_text))));
 | 
			
		||||
  label_.get_style_context()->add_class(status_text);
 | 
			
		||||
  button_.get_style_context()->remove_class(activated() ? "deactivated" : "activated");
 | 
			
		||||
  label_->set_markup(fmt::format(format_, fmt::arg("status", status_text),
 | 
			
		||||
                                 fmt::arg("icon", getIcon(0, status_text))));
 | 
			
		||||
  button_.get_style_context()->add_class(status_text);
 | 
			
		||||
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    label_.set_tooltip_text(status_text);
 | 
			
		||||
    button_.set_tooltip_text(status_text);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ALabel::update();
 | 
			
		||||
  return AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto Inhibitor::handleToggle(GdkEventButton* const& e) -> bool {
 | 
			
		||||
@@ -142,7 +142,7 @@ auto Inhibitor::handleToggle(GdkEventButton* const& e) -> bool {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return ALabel::handleToggle(e);
 | 
			
		||||
  return AButton::handleToggle(e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace waybar::modules
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#include "modules/memory.hpp"
 | 
			
		||||
 | 
			
		||||
waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "memory", id, "{}%", 30) {
 | 
			
		||||
    : AButton(config, "memory", id, "{}%", 30) {
 | 
			
		||||
  thread_ = [this] {
 | 
			
		||||
    dp.emit();
 | 
			
		||||
    thread_.sleep_for(interval_);
 | 
			
		||||
@@ -54,7 +54,7 @@ auto waybar::modules::Memory::update() -> void {
 | 
			
		||||
    } else {
 | 
			
		||||
      event_box_.show();
 | 
			
		||||
      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)),
 | 
			
		||||
          fmt::arg("total", total_ram_gigabytes), fmt::arg("swapTotal", total_swap_gigabytes),
 | 
			
		||||
          fmt::arg("percentage", used_ram_percentage),
 | 
			
		||||
@@ -66,7 +66,7 @@ auto waybar::modules::Memory::update() -> void {
 | 
			
		||||
    if (tooltipEnabled()) {
 | 
			
		||||
      if (config_["tooltip-format"].isString()) {
 | 
			
		||||
        auto tooltip_format = config_["tooltip-format"].asString();
 | 
			
		||||
        label_.set_tooltip_text(fmt::format(
 | 
			
		||||
        button_.set_tooltip_text(fmt::format(
 | 
			
		||||
            tooltip_format, used_ram_percentage, fmt::arg("total", total_ram_gigabytes),
 | 
			
		||||
            fmt::arg("swapTotal", total_swap_gigabytes),
 | 
			
		||||
            fmt::arg("percentage", used_ram_percentage),
 | 
			
		||||
@@ -74,12 +74,12 @@ auto waybar::modules::Memory::update() -> void {
 | 
			
		||||
            fmt::arg("swapUsed", used_swap_gigabytes), fmt::arg("avail", available_ram_gigabytes),
 | 
			
		||||
            fmt::arg("swapAvail", available_swap_gigabytes)));
 | 
			
		||||
      } else {
 | 
			
		||||
        label_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
 | 
			
		||||
        button_.set_tooltip_text(fmt::format("{:.{}f}GiB used", used_ram_gigabytes, 1));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    event_box_.hide();
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,9 @@
 | 
			
		||||
#include <glibmm/ustring.h>
 | 
			
		||||
#include <spdlog/spdlog.h>
 | 
			
		||||
 | 
			
		||||
#include <util/sanitize_str.hpp>
 | 
			
		||||
using namespace waybar::util;
 | 
			
		||||
 | 
			
		||||
#include "modules/mpd/state.hpp"
 | 
			
		||||
#if defined(MPD_NOINLINE)
 | 
			
		||||
namespace waybar::modules {
 | 
			
		||||
@@ -12,7 +15,7 @@ namespace waybar::modules {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
waybar::modules::MPD::MPD(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "mpd", id, "{album} - {artist} - {title}", 5),
 | 
			
		||||
    : AButton(config, "mpd", id, "{album} - {artist} - {title}", 5, false, true),
 | 
			
		||||
      module_name_(id.empty() ? "mpd" : "mpd#" + id),
 | 
			
		||||
      server_(nullptr),
 | 
			
		||||
      port_(config_["port"].isUInt() ? config["port"].asUInt() : 0),
 | 
			
		||||
@@ -44,7 +47,7 @@ auto waybar::modules::MPD::update() -> void {
 | 
			
		||||
  context_.update();
 | 
			
		||||
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void waybar::modules::MPD::queryMPD() {
 | 
			
		||||
@@ -85,15 +88,15 @@ std::string waybar::modules::MPD::getFilename() const {
 | 
			
		||||
 | 
			
		||||
void waybar::modules::MPD::setLabel() {
 | 
			
		||||
  if (connection_ == nullptr) {
 | 
			
		||||
    label_.get_style_context()->add_class("disconnected");
 | 
			
		||||
    label_.get_style_context()->remove_class("stopped");
 | 
			
		||||
    label_.get_style_context()->remove_class("playing");
 | 
			
		||||
    label_.get_style_context()->remove_class("paused");
 | 
			
		||||
    button_.get_style_context()->add_class("disconnected");
 | 
			
		||||
    button_.get_style_context()->remove_class("stopped");
 | 
			
		||||
    button_.get_style_context()->remove_class("playing");
 | 
			
		||||
    button_.get_style_context()->remove_class("paused");
 | 
			
		||||
 | 
			
		||||
    auto format = config_["format-disconnected"].isString()
 | 
			
		||||
                      ? config_["format-disconnected"].asString()
 | 
			
		||||
                      : "disconnected";
 | 
			
		||||
    label_.set_markup(format);
 | 
			
		||||
    label_->set_markup(format);
 | 
			
		||||
 | 
			
		||||
    if (tooltipEnabled()) {
 | 
			
		||||
      std::string tooltip_format;
 | 
			
		||||
@@ -101,11 +104,11 @@ void waybar::modules::MPD::setLabel() {
 | 
			
		||||
                           ? config_["tooltip-format-disconnected"].asString()
 | 
			
		||||
                           : "MPD (disconnected)";
 | 
			
		||||
      // Nothing to format
 | 
			
		||||
      label_.set_tooltip_text(tooltip_format);
 | 
			
		||||
      button_.set_tooltip_text(tooltip_format);
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.get_style_context()->remove_class("disconnected");
 | 
			
		||||
    button_.get_style_context()->remove_class("disconnected");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  auto format = format_;
 | 
			
		||||
@@ -118,29 +121,29 @@ void waybar::modules::MPD::setLabel() {
 | 
			
		||||
  if (stopped()) {
 | 
			
		||||
    format =
 | 
			
		||||
        config_["format-stopped"].isString() ? config_["format-stopped"].asString() : "stopped";
 | 
			
		||||
    label_.get_style_context()->add_class("stopped");
 | 
			
		||||
    label_.get_style_context()->remove_class("playing");
 | 
			
		||||
    label_.get_style_context()->remove_class("paused");
 | 
			
		||||
    button_.get_style_context()->add_class("stopped");
 | 
			
		||||
    button_.get_style_context()->remove_class("playing");
 | 
			
		||||
    button_.get_style_context()->remove_class("paused");
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.get_style_context()->remove_class("stopped");
 | 
			
		||||
    button_.get_style_context()->remove_class("stopped");
 | 
			
		||||
    if (playing()) {
 | 
			
		||||
      label_.get_style_context()->add_class("playing");
 | 
			
		||||
      label_.get_style_context()->remove_class("paused");
 | 
			
		||||
      button_.get_style_context()->add_class("playing");
 | 
			
		||||
      button_.get_style_context()->remove_class("paused");
 | 
			
		||||
    } else if (paused()) {
 | 
			
		||||
      format = config_["format-paused"].isString() ? config_["format-paused"].asString()
 | 
			
		||||
                                                   : config_["format"].asString();
 | 
			
		||||
      label_.get_style_context()->add_class("paused");
 | 
			
		||||
      label_.get_style_context()->remove_class("playing");
 | 
			
		||||
      button_.get_style_context()->add_class("paused");
 | 
			
		||||
      button_.get_style_context()->remove_class("playing");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    stateIcon = getStateIcon();
 | 
			
		||||
 | 
			
		||||
    artist = getTag(MPD_TAG_ARTIST);
 | 
			
		||||
    album_artist = getTag(MPD_TAG_ALBUM_ARTIST);
 | 
			
		||||
    album = getTag(MPD_TAG_ALBUM);
 | 
			
		||||
    title = getTag(MPD_TAG_TITLE);
 | 
			
		||||
    date = getTag(MPD_TAG_DATE);
 | 
			
		||||
    filename = getFilename();
 | 
			
		||||
    artist = sanitize_string(getTag(MPD_TAG_ARTIST));
 | 
			
		||||
    album_artist = sanitize_string(getTag(MPD_TAG_ALBUM_ARTIST));
 | 
			
		||||
    album = sanitize_string(getTag(MPD_TAG_ALBUM));
 | 
			
		||||
    title = sanitize_string(getTag(MPD_TAG_TITLE));
 | 
			
		||||
    date = sanitize_string(getTag(MPD_TAG_DATE));
 | 
			
		||||
    filename = sanitize_string(getFilename());
 | 
			
		||||
    song_pos = mpd_status_get_song_pos(status_.get()) + 1;
 | 
			
		||||
    volume = mpd_status_get_volume(status_.get());
 | 
			
		||||
    if (volume < 0) {
 | 
			
		||||
@@ -166,7 +169,7 @@ void waybar::modules::MPD::setLabel() {
 | 
			
		||||
  if (config_["title-len"].isInt()) title = title.substr(0, config_["title-len"].asInt());
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    label_.set_markup(fmt::format(
 | 
			
		||||
    label_->set_markup(fmt::format(
 | 
			
		||||
        format, fmt::arg("artist", Glib::Markup::escape_text(artist).raw()),
 | 
			
		||||
        fmt::arg("albumArtist", Glib::Markup::escape_text(album_artist).raw()),
 | 
			
		||||
        fmt::arg("album", Glib::Markup::escape_text(album).raw()),
 | 
			
		||||
@@ -195,7 +198,7 @@ void waybar::modules::MPD::setLabel() {
 | 
			
		||||
                      fmt::arg("queueLength", queue_length), fmt::arg("stateIcon", stateIcon),
 | 
			
		||||
                      fmt::arg("consumeIcon", consumeIcon), fmt::arg("randomIcon", randomIcon),
 | 
			
		||||
                      fmt::arg("repeatIcon", repeatIcon), fmt::arg("singleIcon", singleIcon));
 | 
			
		||||
      label_.set_tooltip_text(tooltip_text);
 | 
			
		||||
      button_.set_tooltip_text(tooltip_text);
 | 
			
		||||
    } catch (fmt::format_error const& e) {
 | 
			
		||||
      spdlog::warn("mpd: format error (tooltip): {}", e.what());
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ waybar::modules::Network::readBandwidthUsage() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
waybar::modules::Network::Network(const std::string &id, const Json::Value &config)
 | 
			
		||||
    : ALabel(config, "network", id, DEFAULT_FORMAT, 60),
 | 
			
		||||
    : AButton(config, "network", id, DEFAULT_FORMAT, 60),
 | 
			
		||||
      ifid_(-1),
 | 
			
		||||
      family_(config["family"] == "ipv6" ? AF_INET6 : AF_INET),
 | 
			
		||||
      efd_(-1),
 | 
			
		||||
@@ -95,11 +95,11 @@ waybar::modules::Network::Network(const std::string &id, const Json::Value &conf
 | 
			
		||||
#endif
 | 
			
		||||
      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
 | 
			
		||||
  // 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.
 | 
			
		||||
  label_.set_markup("<s></s>");
 | 
			
		||||
  label_->set_markup("<s></s>");
 | 
			
		||||
 | 
			
		||||
  auto bandwidth = readBandwidthUsage();
 | 
			
		||||
  if (bandwidth.has_value()) {
 | 
			
		||||
@@ -309,8 +309,8 @@ auto waybar::modules::Network::update() -> void {
 | 
			
		||||
 | 
			
		||||
  if (!alt_) {
 | 
			
		||||
    auto state = getNetworkState();
 | 
			
		||||
    if (!state_.empty() && label_.get_style_context()->has_class(state_)) {
 | 
			
		||||
      label_.get_style_context()->remove_class(state_);
 | 
			
		||||
    if (!state_.empty() && button_.get_style_context()->has_class(state_)) {
 | 
			
		||||
      button_.get_style_context()->remove_class(state_);
 | 
			
		||||
    }
 | 
			
		||||
    if (config_["format-" + state].isString()) {
 | 
			
		||||
      default_format_ = config_["format-" + state].asString();
 | 
			
		||||
@@ -322,8 +322,8 @@ auto waybar::modules::Network::update() -> void {
 | 
			
		||||
    if (config_["tooltip-format-" + state].isString()) {
 | 
			
		||||
      tooltip_format = config_["tooltip-format-" + state].asString();
 | 
			
		||||
    }
 | 
			
		||||
    if (!label_.get_style_context()->has_class(state)) {
 | 
			
		||||
      label_.get_style_context()->add_class(state);
 | 
			
		||||
    if (!button_.get_style_context()->has_class(state)) {
 | 
			
		||||
      button_.get_style_context()->add_class(state);
 | 
			
		||||
    }
 | 
			
		||||
    format_ = default_format_;
 | 
			
		||||
    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("bandwidthTotalBytes",
 | 
			
		||||
               pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s")));
 | 
			
		||||
  if (text.compare(label_.get_label()) != 0) {
 | 
			
		||||
    label_.set_markup(text);
 | 
			
		||||
  if (text.compare(label_->get_label()) != 0) {
 | 
			
		||||
    label_->set_markup(text);
 | 
			
		||||
    if (text.empty()) {
 | 
			
		||||
      event_box_.hide();
 | 
			
		||||
    } else {
 | 
			
		||||
@@ -382,16 +382,16 @@ auto waybar::modules::Network::update() -> void {
 | 
			
		||||
          fmt::arg("bandwidthUpBytes", pow_format(bandwidth_up / interval_.count(), "B/s")),
 | 
			
		||||
          fmt::arg("bandwidthTotalBytes",
 | 
			
		||||
                   pow_format((bandwidth_up + bandwidth_down) / interval_.count(), "B/s")));
 | 
			
		||||
      if (label_.get_tooltip_text() != tooltip_text) {
 | 
			
		||||
        label_.set_tooltip_markup(tooltip_text);
 | 
			
		||||
      if (button_.get_tooltip_text() != tooltip_text) {
 | 
			
		||||
        button_.set_tooltip_markup(tooltip_text);
 | 
			
		||||
      }
 | 
			
		||||
    } else if (label_.get_tooltip_text() != text) {
 | 
			
		||||
      label_.set_tooltip_markup(text);
 | 
			
		||||
    } else if (button_.get_tooltip_text() != text) {
 | 
			
		||||
      button_.set_tooltip_markup(text);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool waybar::modules::Network::checkInterface(std::string name) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
#include "modules/pulseaudio.hpp"
 | 
			
		||||
 | 
			
		||||
waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value &config)
 | 
			
		||||
    : ALabel(config, "pulseaudio", id, "{volume}%"),
 | 
			
		||||
    : AButton(config, "pulseaudio", id, "{volume}%"),
 | 
			
		||||
      mainloop_(nullptr),
 | 
			
		||||
      mainloop_api_(nullptr),
 | 
			
		||||
      context_(nullptr),
 | 
			
		||||
@@ -91,19 +91,31 @@ bool waybar::modules::Pulseaudio::handleScroll(GdkEventScroll *e) {
 | 
			
		||||
  pa_volume_t change = volume_tick;
 | 
			
		||||
  pa_cvolume pa_volume = pa_volume_;
 | 
			
		||||
  int max_volume = 100;
 | 
			
		||||
  double step = 1;
 | 
			
		||||
  // isDouble returns true for integers as well, just in case
 | 
			
		||||
  if (config_["scroll-step"].isDouble()) {
 | 
			
		||||
    change = round(config_["scroll-step"].asDouble() * volume_tick);
 | 
			
		||||
    step = config_["scroll-step"].asDouble();
 | 
			
		||||
  }
 | 
			
		||||
  if (config_["max-volume"].isInt()) {
 | 
			
		||||
    max_volume = std::min(0, config_["max-volume"].asInt());
 | 
			
		||||
    max_volume = std::min(config_["max-volume"].asInt(), static_cast<int>(PA_VOLUME_UI_MAX));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (dir == SCROLL_DIR::UP) {
 | 
			
		||||
    if (volume_ + 1 <= max_volume) {
 | 
			
		||||
    if (volume_ < max_volume) {
 | 
			
		||||
      if (volume_ + step > max_volume) {
 | 
			
		||||
        change = round((max_volume - volume_) * volume_tick);
 | 
			
		||||
      } else {
 | 
			
		||||
        change = round(step * volume_tick);
 | 
			
		||||
      }
 | 
			
		||||
      pa_cvolume_inc(&pa_volume, change);
 | 
			
		||||
    }
 | 
			
		||||
  } else if (dir == SCROLL_DIR::DOWN) {
 | 
			
		||||
    if (volume_ - 1 >= 0) {
 | 
			
		||||
    if (volume_ > 0) {
 | 
			
		||||
      if (volume_ - step < 0) {
 | 
			
		||||
        change = round(volume_ * volume_tick);
 | 
			
		||||
      } else {
 | 
			
		||||
        change = round(step * volume_tick);
 | 
			
		||||
      }
 | 
			
		||||
      pa_cvolume_dec(&pa_volume, change);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -170,6 +182,15 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_
 | 
			
		||||
  if (i == nullptr) return;
 | 
			
		||||
 | 
			
		||||
  auto pa = static_cast<waybar::modules::Pulseaudio *>(data);
 | 
			
		||||
 | 
			
		||||
  if (pa->config_["ignored-sinks"].isArray()) {
 | 
			
		||||
    for (const auto &ignored_sink : pa->config_["ignored-sinks"]) {
 | 
			
		||||
      if (ignored_sink.asString() == i->description) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (pa->current_sink_name_ == i->name) {
 | 
			
		||||
    if (i->state != PA_SINK_RUNNING) {
 | 
			
		||||
      pa->current_sink_running_ = false;
 | 
			
		||||
@@ -240,9 +261,9 @@ auto waybar::modules::Pulseaudio::update() -> void {
 | 
			
		||||
    if (monitor_.find("a2dp_sink") != std::string::npos ||  // PulseAudio
 | 
			
		||||
        monitor_.find("a2dp-sink") != std::string::npos) {  // PipeWire
 | 
			
		||||
      format_name = format_name + "-bluetooth";
 | 
			
		||||
      label_.get_style_context()->add_class("bluetooth");
 | 
			
		||||
      button_.get_style_context()->add_class("bluetooth");
 | 
			
		||||
    } else {
 | 
			
		||||
      label_.get_style_context()->remove_class("bluetooth");
 | 
			
		||||
      button_.get_style_context()->remove_class("bluetooth");
 | 
			
		||||
    }
 | 
			
		||||
    if (muted_) {
 | 
			
		||||
      // Check muted bluetooth format exist, otherwise fallback to default muted format
 | 
			
		||||
@@ -250,29 +271,29 @@ auto waybar::modules::Pulseaudio::update() -> void {
 | 
			
		||||
        format_name = "format";
 | 
			
		||||
      }
 | 
			
		||||
      format_name = format_name + "-muted";
 | 
			
		||||
      label_.get_style_context()->add_class("muted");
 | 
			
		||||
      label_.get_style_context()->add_class("sink-muted");
 | 
			
		||||
      button_.get_style_context()->add_class("muted");
 | 
			
		||||
      button_.get_style_context()->add_class("sink-muted");
 | 
			
		||||
    } else {
 | 
			
		||||
      label_.get_style_context()->remove_class("muted");
 | 
			
		||||
      label_.get_style_context()->remove_class("sink-muted");
 | 
			
		||||
      button_.get_style_context()->remove_class("muted");
 | 
			
		||||
      button_.get_style_context()->remove_class("sink-muted");
 | 
			
		||||
    }
 | 
			
		||||
    format = config_[format_name].isString() ? config_[format_name].asString() : format;
 | 
			
		||||
  }
 | 
			
		||||
  // TODO: find a better way to split source/sink
 | 
			
		||||
  std::string format_source = "{volume}%";
 | 
			
		||||
  if (source_muted_) {
 | 
			
		||||
    label_.get_style_context()->add_class("source-muted");
 | 
			
		||||
    button_.get_style_context()->add_class("source-muted");
 | 
			
		||||
    if (config_["format-source-muted"].isString()) {
 | 
			
		||||
      format_source = config_["format-source-muted"].asString();
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.get_style_context()->remove_class("source-muted");
 | 
			
		||||
    button_.get_style_context()->remove_class("source-muted");
 | 
			
		||||
    if (config_["format-source-muted"].isString()) {
 | 
			
		||||
      format_source = config_["format-source"].asString();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  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_),
 | 
			
		||||
      fmt::arg("format_source", format_source), fmt::arg("source_volume", source_volume_),
 | 
			
		||||
      fmt::arg("source_desc", source_desc_), fmt::arg("icon", getIcon(volume_, getPulseIcon()))));
 | 
			
		||||
@@ -283,16 +304,16 @@ auto waybar::modules::Pulseaudio::update() -> void {
 | 
			
		||||
      tooltip_format = config_["tooltip-format"].asString();
 | 
			
		||||
    }
 | 
			
		||||
    if (!tooltip_format.empty()) {
 | 
			
		||||
      label_.set_tooltip_text(fmt::format(
 | 
			
		||||
      button_.set_tooltip_text(fmt::format(
 | 
			
		||||
          tooltip_format, fmt::arg("desc", desc_), fmt::arg("volume", 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()))));
 | 
			
		||||
    } else {
 | 
			
		||||
      label_.set_tooltip_text(desc_);
 | 
			
		||||
      button_.set_tooltip_text(desc_);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "clock", id, "{:%H:%M}", 60) {
 | 
			
		||||
    : AButton(config, "clock", id, "{:%H:%M}", 60) {
 | 
			
		||||
  thread_ = [this] {
 | 
			
		||||
    dp.emit();
 | 
			
		||||
    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 localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now));
 | 
			
		||||
  auto text = fmt::format(format_, localtime);
 | 
			
		||||
  label_.set_markup(text);
 | 
			
		||||
  label_->set_markup(text);
 | 
			
		||||
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    if (config_["tooltip-format"].isString()) {
 | 
			
		||||
      auto tooltip_format = config_["tooltip-format"].asString();
 | 
			
		||||
      auto tooltip_text = fmt::format(tooltip_format, localtime);
 | 
			
		||||
      label_.set_tooltip_text(tooltip_text);
 | 
			
		||||
      button_.set_tooltip_text(tooltip_text);
 | 
			
		||||
    } else {
 | 
			
		||||
      label_.set_tooltip_text(text);
 | 
			
		||||
      button_.set_tooltip_text(text);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ auto Sndio::connect_to_sndio() -> void {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Sndio::Sndio(const std::string &id, const Json::Value &config)
 | 
			
		||||
    : ALabel(config, "sndio", id, "{volume}%", 1),
 | 
			
		||||
    : AButton(config, "sndio", id, "{volume}%", 1, false, true),
 | 
			
		||||
      hdl_(nullptr),
 | 
			
		||||
      pfds_(0),
 | 
			
		||||
      addr_(0),
 | 
			
		||||
@@ -105,14 +105,14 @@ auto Sndio::update() -> void {
 | 
			
		||||
  unsigned int vol = 100. * static_cast<double>(volume_) / static_cast<double>(maxval_);
 | 
			
		||||
 | 
			
		||||
  if (volume_ == 0) {
 | 
			
		||||
    label_.get_style_context()->add_class("muted");
 | 
			
		||||
    button_.get_style_context()->add_class("muted");
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.get_style_context()->remove_class("muted");
 | 
			
		||||
    button_.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_)));
 | 
			
		||||
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto Sndio::set_desc(struct sioctl_desc *d, unsigned int val) -> void {
 | 
			
		||||
 
 | 
			
		||||
@@ -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";
 | 
			
		||||
 | 
			
		||||
Language::Language(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "language", id, "{}", 0, true) {
 | 
			
		||||
    : AButton(config, "language", id, "{}", 0, true) {
 | 
			
		||||
  is_variant_displayed = format_.find("{variant}") != std::string::npos;
 | 
			
		||||
  if (format_.find("{}") != std::string::npos || format_.find("{short}") != std::string::npos) {
 | 
			
		||||
    displayed_short_flag |= static_cast<std::byte>(DispayedShortFlag::ShortName);
 | 
			
		||||
@@ -99,7 +99,7 @@ auto Language::update() -> void {
 | 
			
		||||
      format_, fmt::arg("short", layout_.short_name),
 | 
			
		||||
      fmt::arg("shortDescription", layout_.short_description), fmt::arg("long", layout_.full_name),
 | 
			
		||||
      fmt::arg("variant", layout_.variant), fmt::arg("flag", layout_.country_flag())));
 | 
			
		||||
  label_.set_markup(display_layout);
 | 
			
		||||
  label_->set_markup(display_layout);
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    if (tooltip_format_ != "") {
 | 
			
		||||
      auto tooltip_display_layout = trim(
 | 
			
		||||
@@ -107,22 +107,22 @@ auto Language::update() -> void {
 | 
			
		||||
                      fmt::arg("shortDescription", layout_.short_description),
 | 
			
		||||
                      fmt::arg("long", layout_.full_name), fmt::arg("variant", layout_.variant),
 | 
			
		||||
                      fmt::arg("flag", layout_.country_flag())));
 | 
			
		||||
      label_.set_tooltip_markup(tooltip_display_layout);
 | 
			
		||||
      button_.set_tooltip_markup(tooltip_display_layout);
 | 
			
		||||
    } else {
 | 
			
		||||
      label_.set_tooltip_markup(display_layout);
 | 
			
		||||
      button_.set_tooltip_markup(display_layout);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  event_box_.show();
 | 
			
		||||
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto Language::set_current_layout(std::string current_layout) -> void {
 | 
			
		||||
  label_.get_style_context()->remove_class(layout_.short_name);
 | 
			
		||||
  button_.get_style_context()->remove_class(layout_.short_name);
 | 
			
		||||
  layout_ = layouts_map_[current_layout];
 | 
			
		||||
  label_.get_style_context()->add_class(layout_.short_name);
 | 
			
		||||
  button_.get_style_context()->add_class(layout_.short_name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
auto Language::init_layouts_map(const std::vector<std::string>& used_layouts) -> void {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
namespace waybar::modules::sway {
 | 
			
		||||
 | 
			
		||||
Mode::Mode(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "mode", id, "{}", 0, true) {
 | 
			
		||||
    : AButton(config, "mode", id, "{}", 0, true) {
 | 
			
		||||
  ipc_.subscribe(R"(["mode"])");
 | 
			
		||||
  ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent));
 | 
			
		||||
  // Launch worker
 | 
			
		||||
@@ -42,14 +42,14 @@ auto Mode::update() -> void {
 | 
			
		||||
  if (mode_.empty()) {
 | 
			
		||||
    event_box_.hide();
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.set_markup(fmt::format(format_, mode_));
 | 
			
		||||
    label_->set_markup(fmt::format(format_, mode_));
 | 
			
		||||
    if (tooltipEnabled()) {
 | 
			
		||||
      label_.set_tooltip_text(mode_);
 | 
			
		||||
      button_.set_tooltip_text(mode_);
 | 
			
		||||
    }
 | 
			
		||||
    event_box_.show();
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}  // namespace waybar::modules::sway
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config)
 | 
			
		||||
    : ALabel(config, "temperature", id, "{temperatureC}°C", 10) {
 | 
			
		||||
    : AButton(config, "temperature", id, "{temperatureC}°C", 10) {
 | 
			
		||||
#if defined(__FreeBSD__)
 | 
			
		||||
// try to read sysctl?
 | 
			
		||||
#else
 | 
			
		||||
@@ -42,9 +42,9 @@ auto waybar::modules::Temperature::update() -> void {
 | 
			
		||||
  auto format = format_;
 | 
			
		||||
  if (critical) {
 | 
			
		||||
    format = config_["format-critical"].isString() ? config_["format-critical"].asString() : format;
 | 
			
		||||
    label_.get_style_context()->add_class("critical");
 | 
			
		||||
    button_.get_style_context()->add_class("critical");
 | 
			
		||||
  } else {
 | 
			
		||||
    label_.get_style_context()->remove_class("critical");
 | 
			
		||||
    button_.get_style_context()->remove_class("critical");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  label_.set_markup(fmt::format(format, fmt::arg("temperatureC", temperature_c),
 | 
			
		||||
                                fmt::arg("temperatureF", temperature_f),
 | 
			
		||||
                                fmt::arg("temperatureK", temperature_k),
 | 
			
		||||
                                fmt::arg("icon", getIcon(temperature_c, "", max_temp))));
 | 
			
		||||
  label_->set_markup(fmt::format(format, fmt::arg("temperatureC", temperature_c),
 | 
			
		||||
                                 fmt::arg("temperatureF", temperature_f),
 | 
			
		||||
                                 fmt::arg("temperatureK", temperature_k),
 | 
			
		||||
                                 fmt::arg("icon", getIcon(temperature_c, "", max_temp))));
 | 
			
		||||
  if (tooltipEnabled()) {
 | 
			
		||||
    std::string tooltip_format = "{temperatureC}°C";
 | 
			
		||||
    if (config_["tooltip-format"].isString()) {
 | 
			
		||||
      tooltip_format = config_["tooltip-format"].asString();
 | 
			
		||||
    }
 | 
			
		||||
    label_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("temperatureC", temperature_c),
 | 
			
		||||
                                        fmt::arg("temperatureF", temperature_f),
 | 
			
		||||
                                        fmt::arg("temperatureK", temperature_k)));
 | 
			
		||||
    button_.set_tooltip_text(fmt::format(tooltip_format, fmt::arg("temperatureC", temperature_c),
 | 
			
		||||
                                         fmt::arg("temperatureF", temperature_f),
 | 
			
		||||
                                         fmt::arg("temperatureK", temperature_k)));
 | 
			
		||||
  }
 | 
			
		||||
  // Call parent update
 | 
			
		||||
  ALabel::update();
 | 
			
		||||
  AButton::update();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float waybar::modules::Temperature::getTemperature() {
 | 
			
		||||
@@ -80,8 +80,9 @@ float waybar::modules::Temperature::getTemperature() {
 | 
			
		||||
  auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0;
 | 
			
		||||
  auto sysctl_thermal = fmt::format("hw.acpi.thermal.tz{}.temperature", zone);
 | 
			
		||||
 | 
			
		||||
  if (sysctlbyname(sysctl_thermal.c_str(), &temp, &size, NULL, 0) != 0) {
 | 
			
		||||
    throw std::runtime_error(fmt::format("sysctl {} failed", sysctl_thermal));
 | 
			
		||||
  if (sysctlbyname("hw.acpi.thermal.tz0.temperature", &temp, &size, NULL, 0) != 0) {
 | 
			
		||||
    throw std::runtime_error(
 | 
			
		||||
        "sysctl hw.acpi.thermal.tz0.temperature or dev.cpu.0.temperature failed");
 | 
			
		||||
  }
 | 
			
		||||
  auto temperature_c = ((float)temp - 2732) / 10;
 | 
			
		||||
  return temperature_c;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								src/util/sanitize_str.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/util/sanitize_str.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <util/sanitize_str.hpp>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
namespace waybar::util {
 | 
			
		||||
// replaces ``<>&"'`` with their encoded counterparts
 | 
			
		||||
std::string sanitize_string(std::string str) {
 | 
			
		||||
  // note: it's important that '&' is replaced first; therefor we *can't* use std::map
 | 
			
		||||
  const std::pair<char, std::string> replacement_table[] = {
 | 
			
		||||
      {'&', "&"}, {'<', "<"}, {'>', ">"}, {'"', """}, {'\'', "'"}};
 | 
			
		||||
  size_t startpoint;
 | 
			
		||||
  for (size_t i = 0; i < (sizeof(replacement_table) / sizeof(replacement_table[0])); ++i) {
 | 
			
		||||
    startpoint = 0;
 | 
			
		||||
    std::pair pair = replacement_table[i];
 | 
			
		||||
    while ((startpoint = str.find(pair.first, startpoint)) != std::string::npos) {
 | 
			
		||||
      str.replace(startpoint, 1, pair.second);
 | 
			
		||||
      startpoint += pair.second.length();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return str;
 | 
			
		||||
}
 | 
			
		||||
}  // namespace waybar::util
 | 
			
		||||
		Reference in New Issue
	
	Block a user