mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	Merge branch 'master' into on-update
This commit is contained in:
		| @@ -2,4 +2,4 @@ | ||||
|  | ||||
| FROM alpine:latest | ||||
|  | ||||
| RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev libnl3-dev pulseaudio-dev libmpdclient-dev scdoc | ||||
| RUN apk add --no-cache git meson alpine-sdk libinput-dev wayland-dev wayland-protocols mesa-dev libxkbcommon-dev eudev-dev pixman-dev gtkmm3-dev jsoncpp-dev pugixml libnl3-dev pulseaudio-dev libmpdclient-dev scdoc | ||||
|   | ||||
| @@ -3,4 +3,4 @@ | ||||
| FROM archlinux/base:latest | ||||
|  | ||||
| RUN pacman -Syu --noconfirm && \ | ||||
|     pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp scdoc --noconfirm | ||||
|     pacman -S git meson base-devel libinput wayland wayland-protocols pixman libxkbcommon mesa gtkmm3 jsoncpp pugixml scdoc --noconfirm | ||||
|   | ||||
| @@ -3,5 +3,5 @@ | ||||
| FROM debian:sid | ||||
|  | ||||
| RUN apt-get update && \ | ||||
|     apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev scdoc && \ | ||||
|     apt-get install -y build-essential meson ninja-build git pkg-config libinput10 libpugixml-dev libinput-dev wayland-protocols libwayland-client0 libwayland-cursor0 libwayland-dev libegl1-mesa-dev libgles2-mesa-dev libgbm-dev libxkbcommon-dev libudev-dev libpixman-1-dev libgtkmm-3.0-dev libjsoncpp-dev scdoc && \ | ||||
|     apt-get clean | ||||
|   | ||||
| @@ -2,6 +2,6 @@ | ||||
|  | ||||
| FROM fedora:30 | ||||
|  | ||||
| RUN dnf install sway meson git libinput-devel wayland-devel wayland-protocols-devel egl-wayland-devel mesa-libEGL-devel mesa-libGLES-devel mesa-libgbm-devel libxkbcommon-devel libudev-devel pixman-devel gtkmm30-devel jsoncpp-devel scdoc -y && \ | ||||
| RUN dnf install sway meson git libinput-devel wayland-devel wayland-protocols-devel pugixml-devel egl-wayland-devel mesa-libEGL-devel mesa-libGLES-devel mesa-libgbm-devel libxkbcommon-devel libudev-devel pixman-devel gtkmm30-devel jsoncpp-devel scdoc -y && \ | ||||
|     dnf group install "C Development Tools and Libraries" -y && \ | ||||
|     dnf clean all -y | ||||
|   | ||||
| @@ -4,4 +4,4 @@ FROM opensuse/tumbleweed:latest | ||||
|  | ||||
| RUN zypper -n up && \ | ||||
|     zypper -n install -t pattern devel_C_C++ && \ | ||||
|     zypper -n install git meson clang libinput10 libinput-devel libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel scdoc | ||||
|     zypper -n install git meson clang libinput10 libinput-devel libpugixml1 libwayland-client0 libwayland-cursor0 wayland-protocols-devel wayland-devel Mesa-libEGL-devel Mesa-libGLESv2-devel libgbm-devel libxkbcommon-devel libudev-devel libpixman-1-0-devel gtkmm3-devel jsoncpp-devel scdoc | ||||
|   | ||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| .PHONY: build build-debug run clean default install | ||||
|  | ||||
| default: run | ||||
| default: build | ||||
|  | ||||
| build: | ||||
| 	meson build | ||||
|   | ||||
							
								
								
									
										27
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								README.md
									
									
									
									
									
								
							| @@ -49,6 +49,9 @@ libsigc++ | ||||
| fmt | ||||
| wayland | ||||
| wlroots | ||||
| libgtk-3-dev [gtk-layer-shell] | ||||
| gobject-introspection [gtk-layer-shell] | ||||
| libgirepository1.0-dev [gtk-layer-shell] | ||||
| libpulse [Pulseaudio module] | ||||
| libnl [Network module] | ||||
| sway [Sway modules] | ||||
| @@ -56,6 +59,30 @@ libdbusmenu-gtk3 [Tray module] | ||||
| libmpdclient [MPD module] | ||||
| ``` | ||||
|  | ||||
| On Ubuntu 19.10 you can install all the relevant dependencies using this command: | ||||
|  | ||||
| ``` | ||||
| sudo apt install \ | ||||
|   clang-tidy \ | ||||
|   gobject-introspection \ | ||||
|   libdbusmenu-gtk3-dev \ | ||||
|   libfmt-dev \ | ||||
|   libgirepository1.0-dev \ | ||||
|   libgtk-3-dev \ | ||||
|   libgtkmm-3.0-dev \ | ||||
|   libinput-dev \ | ||||
|   libjsoncpp-dev \ | ||||
|   libmpdclient-dev \ | ||||
|   libnl-3-dev \ | ||||
|   libnl-genl-3-dev \ | ||||
|   libpulse-dev \ | ||||
|   libsigc++-2.0-dev \ | ||||
|   libspdlog-dev \ | ||||
|   libwayland-dev \ | ||||
|   scdoc | ||||
| ``` | ||||
|  | ||||
|  | ||||
| Contributions welcome! - have fun :)<br> | ||||
| The style guidelines is [Google's](https://google.github.io/styleguide/cppguide.html) | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <gdkmm/monitor.h> | ||||
| #include <glibmm/refptr.h> | ||||
| #include <gtkmm/box.h> | ||||
| #include <gtkmm/cssprovider.h> | ||||
| @@ -15,10 +16,11 @@ namespace waybar { | ||||
|  | ||||
| class Factory; | ||||
| struct waybar_output { | ||||
|   struct wl_output *     output = nullptr; | ||||
|   std::string            name; | ||||
|   uint32_t               wl_name; | ||||
|   struct zxdg_output_v1 *xdg_output = nullptr; | ||||
|   Glib::RefPtr<Gdk::Monitor> monitor; | ||||
|   std::string                name; | ||||
|  | ||||
|   std::unique_ptr<struct zxdg_output_v1, decltype(&zxdg_output_v1_destroy)> xdg_output = { | ||||
|       nullptr, &zxdg_output_v1_destroy}; | ||||
| }; | ||||
|  | ||||
| class Bar { | ||||
| @@ -30,13 +32,12 @@ class Bar { | ||||
|   auto toggle() -> void; | ||||
|   void handleSignal(int); | ||||
|  | ||||
|   struct waybar_output *        output; | ||||
|   Json::Value                   config; | ||||
|   Gtk::Window                   window; | ||||
|   struct wl_surface *           surface; | ||||
|   struct zwlr_layer_surface_v1 *layer_surface; | ||||
|   bool                          visible = true; | ||||
|   bool                          vertical = false; | ||||
|   struct waybar_output *output; | ||||
|   Json::Value           config; | ||||
|   Gtk::Window           window; | ||||
|   struct wl_surface *   surface; | ||||
|   bool                  visible = true; | ||||
|   bool                  vertical = false; | ||||
|  | ||||
|  private: | ||||
|   static constexpr const char *MIN_HEIGHT_MSG = | ||||
| @@ -51,7 +52,9 @@ class Bar { | ||||
|                                           uint32_t, uint32_t); | ||||
|   static void layerSurfaceHandleClosed(void *, struct zwlr_layer_surface_v1 *); | ||||
|  | ||||
|   void destroyOutput(); | ||||
| #ifdef HAVE_GTK_LAYER_SHELL | ||||
|   void initGtkLayerShell(); | ||||
| #endif | ||||
|   void onConfigure(GdkEventConfigure *ev); | ||||
|   void onRealize(); | ||||
|   void onMap(GdkEventAny *ev); | ||||
| @@ -68,6 +71,9 @@ class Bar { | ||||
|     int bottom = 0; | ||||
|     int left = 0; | ||||
|   } margins_; | ||||
|   struct zwlr_layer_surface_v1 *layer_surface_; | ||||
|   // use gtk-layer-shell instead of handling layer surfaces directly | ||||
|   bool                                          use_gls_ = false; | ||||
|   uint32_t                                      width_ = 0; | ||||
|   uint32_t                                      height_ = 1; | ||||
|   uint8_t                                       anchor_; | ||||
|   | ||||
| @@ -30,26 +30,24 @@ class Client { | ||||
|                                                               const std::string &style) const; | ||||
|   void                                             bindInterfaces(); | ||||
|   const std::string getValidPath(const std::vector<std::string> &paths) const; | ||||
|   void              handleOutput(std::unique_ptr<struct waybar_output> &output); | ||||
|   bool isValidOutput(const Json::Value &config, std::unique_ptr<struct waybar_output> &output); | ||||
|   void              handleOutput(struct waybar_output &output); | ||||
|   bool isValidOutput(const Json::Value &config, struct waybar_output &output); | ||||
|   auto setupConfig(const std::string &config_file) -> void; | ||||
|   auto setupCss(const std::string &css_file) -> void; | ||||
|   std::unique_ptr<struct waybar_output> &getOutput(uint32_t wl_name); | ||||
|   std::vector<Json::Value> getOutputConfigs(std::unique_ptr<struct waybar_output> &output); | ||||
|   struct waybar_output &getOutput(void *); | ||||
|   std::vector<Json::Value> getOutputConfigs(struct waybar_output &output); | ||||
|  | ||||
|   static void handleGlobal(void *data, struct wl_registry *registry, uint32_t name, | ||||
|                            const char *interface, uint32_t version); | ||||
|   static void handleGlobalRemove(void *data, struct wl_registry *registry, uint32_t name); | ||||
|   static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t, int32_t); | ||||
|   static void handleLogicalSize(void *, struct zxdg_output_v1 *, int32_t, int32_t); | ||||
|   static void handleDone(void *, struct zxdg_output_v1 *); | ||||
|   static void handleName(void *, struct zxdg_output_v1 *, const char *); | ||||
|   static void handleDescription(void *, struct zxdg_output_v1 *, const char *); | ||||
|   static void handleOutputName(void *, struct zxdg_output_v1 *, const char *); | ||||
|   void        handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor); | ||||
|   void        handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor); | ||||
|  | ||||
|   Json::Value                                        config_; | ||||
|   Glib::RefPtr<Gtk::StyleContext>                    style_context_; | ||||
|   Glib::RefPtr<Gtk::CssProvider>                     css_provider_; | ||||
|   std::vector<std::unique_ptr<struct waybar_output>> outputs_; | ||||
|   Json::Value                     config_; | ||||
|   Glib::RefPtr<Gtk::StyleContext> style_context_; | ||||
|   Glib::RefPtr<Gtk::CssProvider>  css_provider_; | ||||
|   std::list<struct waybar_output> outputs_; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar | ||||
|   | ||||
| @@ -6,11 +6,17 @@ | ||||
| #else | ||||
| #include <fmt/chrono.h> | ||||
| #endif | ||||
| #include <date/tz.h> | ||||
| #include "ALabel.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar::modules { | ||||
|  | ||||
| struct waybar_time { | ||||
|   std::locale locale; | ||||
|   date::zoned_seconds ztime; | ||||
| }; | ||||
|  | ||||
| class Clock : public ALabel { | ||||
|  public: | ||||
|   Clock(const std::string&, const Json::Value&); | ||||
| @@ -19,6 +25,15 @@ class Clock : public ALabel { | ||||
|  | ||||
|  private: | ||||
|   util::SleeperThread thread_; | ||||
|   std::locale locale_; | ||||
|   const date::time_zone* time_zone_; | ||||
|   bool fixed_time_zone_; | ||||
|   date::year_month_day cached_calendar_ymd_; | ||||
|   std::string cached_calendar_text_; | ||||
|  | ||||
|   auto calendar_text(const waybar_time& wtime) -> std::string; | ||||
|   auto weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void; | ||||
|   auto first_day_of_week() -> date::weekday; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar::modules | ||||
|   | ||||
| @@ -17,8 +17,7 @@ class Memory : public ALabel { | ||||
|   static inline const std::string data_dir_ = "/proc/meminfo"; | ||||
|   void                            parseMeminfo(); | ||||
|  | ||||
|   unsigned long memtotal_; | ||||
|   unsigned long memfree_; | ||||
|   std::unordered_map<std::string, unsigned long> meminfo_; | ||||
|  | ||||
|   util::SleeperThread thread_; | ||||
| }; | ||||
|   | ||||
| @@ -36,6 +36,7 @@ class MPD : public ALabel { | ||||
|  | ||||
|   bool stopped(); | ||||
|   bool playing(); | ||||
|   bool paused(); | ||||
|  | ||||
|   const std::string module_name_; | ||||
|  | ||||
|   | ||||
| @@ -34,14 +34,17 @@ class Pulseaudio : public ALabel { | ||||
|   pa_cvolume  pa_volume_; | ||||
|   bool        muted_; | ||||
|   std::string port_name_; | ||||
|   std::string form_factor_; | ||||
|   std::string desc_; | ||||
|   std::string monitor_; | ||||
|   std::string default_sink_name_; | ||||
|   // SOURCE | ||||
|   uint32_t    source_idx_{0}; | ||||
|   uint16_t    source_volume_; | ||||
|   bool        source_muted_; | ||||
|   std::string source_port_name_; | ||||
|   std::string source_desc_; | ||||
|   std::string default_source_name_; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar::modules | ||||
|   | ||||
| @@ -21,7 +21,7 @@ class Tray : public AModule { | ||||
|  | ||||
|   static inline std::size_t nb_hosts_ = 0; | ||||
|   Gtk::Box                  box_; | ||||
|   SNI::Watcher              watcher_; | ||||
|   SNI::Watcher::singleton   watcher_; | ||||
|   SNI::Host                 host_; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -7,10 +7,24 @@ | ||||
| namespace waybar::modules::SNI { | ||||
|  | ||||
| class Watcher { | ||||
|  private: | ||||
|   Watcher(); | ||||
|  | ||||
|  public: | ||||
|   Watcher(std::size_t id); | ||||
|   ~Watcher(); | ||||
|  | ||||
|   using singleton = std::shared_ptr<Watcher>; | ||||
|   static singleton getInstance() { | ||||
|     static std::weak_ptr<Watcher> weak; | ||||
|  | ||||
|     std::shared_ptr<Watcher> strong = weak.lock(); | ||||
|     if (!strong) { | ||||
|       strong = std::shared_ptr<Watcher>(new Watcher()); | ||||
|       weak = strong; | ||||
|     } | ||||
|     return strong; | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType; | ||||
|  | ||||
| @@ -34,7 +48,6 @@ class Watcher { | ||||
|   void updateRegisteredItems(SnWatcher *obj); | ||||
|  | ||||
|   uint32_t   bus_name_id_; | ||||
|   uint32_t   watcher_id_; | ||||
|   GSList *   hosts_ = nullptr; | ||||
|   GSList *   items_ = nullptr; | ||||
|   SnWatcher *watcher_ = nullptr; | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include "ipc.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
|  | ||||
| @@ -28,6 +29,7 @@ class Ipc { | ||||
|   void sendCmd(uint32_t type, const std::string &payload = ""); | ||||
|   void subscribe(const std::string &payload); | ||||
|   void handleEvent(); | ||||
|   void setWorker(std::function<void()> &&func); | ||||
|  | ||||
|  protected: | ||||
|   static inline const std::string ipc_magic_ = "i3-ipc"; | ||||
| @@ -38,9 +40,10 @@ class Ipc { | ||||
|   struct ipc_response send(int fd, uint32_t type, const std::string &payload = ""); | ||||
|   struct ipc_response recv(int fd); | ||||
|  | ||||
|   int        fd_; | ||||
|   int        fd_event_; | ||||
|   std::mutex mutex_; | ||||
|   int                 fd_; | ||||
|   int                 fd_event_; | ||||
|   std::mutex          mutex_; | ||||
|   util::SleeperThread thread_; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar::modules::sway | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "client.hpp" | ||||
| #include "modules/sway/ipc/client.hpp" | ||||
| #include "util/json.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
|  | ||||
| @@ -18,14 +17,11 @@ class Mode : public ALabel, public sigc::trackable { | ||||
|  | ||||
|  private: | ||||
|   void onEvent(const struct Ipc::ipc_response&); | ||||
|   void worker(); | ||||
|  | ||||
|   std::string      mode_; | ||||
|   util::JsonParser parser_; | ||||
|   std::mutex       mutex_; | ||||
|  | ||||
|   util::SleeperThread thread_; | ||||
|   Ipc                 ipc_; | ||||
|   Ipc              ipc_; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar::modules::sway | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| #include "client.hpp" | ||||
| #include "modules/sway/ipc/client.hpp" | ||||
| #include "util/json.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
|  | ||||
| @@ -20,7 +19,6 @@ class Window : public ALabel, public sigc::trackable { | ||||
|  private: | ||||
|   void                                                   onEvent(const struct Ipc::ipc_response&); | ||||
|   void                                                   onCmd(const struct Ipc::ipc_response&); | ||||
|   void                                                   worker(); | ||||
|   std::tuple<std::size_t, int, std::string, std::string> getFocusedNode(const Json::Value& nodes, | ||||
|                                                                         std::string&       output); | ||||
|   void                                                   getTree(); | ||||
| @@ -33,9 +31,7 @@ class Window : public ALabel, public sigc::trackable { | ||||
|   std::size_t      app_nb_; | ||||
|   util::JsonParser parser_; | ||||
|   std::mutex       mutex_; | ||||
|  | ||||
|   util::SleeperThread thread_; | ||||
|   Ipc                 ipc_; | ||||
|   Ipc              ipc_; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar::modules::sway | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <unordered_map> | ||||
| #include <fmt/format.h> | ||||
| #include <gtkmm/button.h> | ||||
| #include <gtkmm/label.h> | ||||
| @@ -8,7 +9,6 @@ | ||||
| #include "client.hpp" | ||||
| #include "modules/sway/ipc/client.hpp" | ||||
| #include "util/json.hpp" | ||||
| #include "util/sleeper_thread.hpp" | ||||
|  | ||||
| namespace waybar::modules::sway { | ||||
|  | ||||
| @@ -21,7 +21,6 @@ class Workspaces : public AModule, public sigc::trackable { | ||||
|  private: | ||||
|   void              onCmd(const struct Ipc::ipc_response&); | ||||
|   void              onEvent(const struct Ipc::ipc_response&); | ||||
|   void              worker(); | ||||
|   bool              filterButtons(); | ||||
|   Gtk::Button&      addButton(const Json::Value&); | ||||
|   void              onButtonReady(const Json::Value&, Gtk::Button&); | ||||
| @@ -38,9 +37,7 @@ class Workspaces : public AModule, public sigc::trackable { | ||||
|   util::JsonParser                             parser_; | ||||
|   std::unordered_map<std::string, Gtk::Button> buttons_; | ||||
|   std::mutex                                   mutex_; | ||||
|  | ||||
|   util::SleeperThread thread_; | ||||
|   Ipc                 ipc_; | ||||
|   Ipc                                          ipc_; | ||||
| }; | ||||
|  | ||||
| }  // namespace waybar::modules::sway | ||||
|   | ||||
| @@ -72,7 +72,10 @@ inline struct res exec(std::string cmd) { | ||||
|   if (!fp) return {-1, ""}; | ||||
|   auto output = command::read(fp); | ||||
|   auto stat = command::close(fp, pid); | ||||
|   return {WEXITSTATUS(stat), output}; | ||||
|   if (WIFEXITED(stat)) { | ||||
|     return {WEXITSTATUS(stat), output}; | ||||
|   } | ||||
|   return {-1, output}; | ||||
| } | ||||
|  | ||||
| inline int32_t forkExec(std::string cmd) { | ||||
| @@ -88,6 +91,7 @@ inline int32_t forkExec(std::string cmd) { | ||||
|   // Child executes the command | ||||
|   if (!pid) { | ||||
|     setpgid(pid, pid); | ||||
|     signal(SIGCHLD, SIG_DFL); | ||||
|     execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)0); | ||||
|     exit(0); | ||||
|   } else { | ||||
|   | ||||
| @@ -36,6 +36,10 @@ The *backlight* module displays the current backlight level. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when the module is clicked. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right* ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when the module is right clicked. | ||||
|   | ||||
| @@ -18,6 +18,10 @@ The *battery* module displays the current capacity and state (eg. charging) of y | ||||
| 	typeof: string ++ | ||||
| 	The adapter to monitor, as in /sys/class/power_supply/ instead of auto detect. | ||||
|  | ||||
| *full-at* ++ | ||||
| 	typeof: integer ++ | ||||
| 	Define the max percentage of the battery, usefull for an old battery, e.g. 96 | ||||
|  | ||||
| *interval* ++ | ||||
| 	typeof: integer ++ | ||||
| 	default: 60 ++ | ||||
| @@ -37,32 +41,36 @@ The *battery* module displays the current capacity and state (eg. charging) of y | ||||
| 	default: {H} h {M} min ++ | ||||
| 	The format, how the time should be displayed. | ||||
|  | ||||
| *format-icons* | ||||
| 	typeof: array/object | ||||
| *format-icons*: ++ | ||||
| 	typeof: array/object ++ | ||||
| 	Based on the current capacity, the corresponding icon gets selected. ++ | ||||
| 	The order is *low* to *high*. Or by the state if it is an object. | ||||
|  | ||||
| *max-length* ++ | ||||
| *max-length*: ++ | ||||
| 	typeof: integer++ | ||||
| 	The maximum length in character the module should display. | ||||
|  | ||||
| *rotate* ++ | ||||
| *rotate*: ++ | ||||
| 	typeof: integer++ | ||||
| 	Positive value to rotate the text label. | ||||
|  | ||||
| *on-click* ++ | ||||
| *on-click*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right* ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|  | ||||
| *on-scroll-up* ++ | ||||
| *on-scroll-up*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when scrolling up on the module. | ||||
|  | ||||
| *on-scroll-down* ++ | ||||
| *on-scroll-down*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when scrolling down on the module. | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,18 @@ The *clock* module displays the current date and time. | ||||
| *format*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: {:%H:%M} ++ | ||||
| 	The format, how the date and time should be displayed. | ||||
| 	The format, how the date and time should be displayed. ++ | ||||
| 	It uses the format of the date library. See https://howardhinnant.github.io/date/date.html#to_stream_formatting for details. | ||||
|  | ||||
| *timezone*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: inferred local timezone ++ | ||||
| 	The timezone to display the time in, e.g. America/New_York. | ||||
|  | ||||
| *locale*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: inferred from current locale ++ | ||||
| 	A locale to be used to display the time. Intended to render times in custom timezones with the proper language and format. | ||||
|  | ||||
| *max-length*: ++ | ||||
| 	typeof: integer ++ | ||||
| @@ -32,6 +43,10 @@ The *clock* module displays the current date and time. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
| @@ -50,6 +65,10 @@ The *clock* module displays the current date and time. | ||||
|  | ||||
| View all valid format options in *strftime(3)*. | ||||
|  | ||||
| # FORMAT REPLACEMENTS | ||||
|  | ||||
| *{calendar}*: Current month calendar | ||||
|  | ||||
| # EXAMPLES | ||||
|  | ||||
| ``` | ||||
|   | ||||
| @@ -36,6 +36,10 @@ The *cpu* module displays the current cpu utilization. | ||||
| 	typeof: string  ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -33,6 +33,12 @@ Addressed by *custom/<name>* | ||||
| 	You can update it manually with a signal. If no *interval* is defined, | ||||
| 	it is assumed that the out script loops it self. | ||||
|  | ||||
| *restart-interval*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	The restart interval (in seconds). | ||||
| 	Can't be used with the *interval* option, so only with continuous scripts. | ||||
| 	Once the script exit, it'll be re-executed after the *restart-interval*. | ||||
|  | ||||
| *signal*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	The signal number used to update the module. | ||||
| @@ -59,6 +65,10 @@ Addressed by *custom/<name>* | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -39,6 +39,10 @@ Addressed by *disk* | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -31,6 +31,10 @@ screensaving, also known as "presentation mode". | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. A click also toggles the state | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -38,6 +38,10 @@ Addressed by *memory* | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -13,110 +13,118 @@ The *mpd* module displays information about a running "Music Player Daemon" inst | ||||
| Addressed by *mpd* | ||||
|  | ||||
| *server*: ++ | ||||
|     typeof: string ++ | ||||
|     The network address or Unix socket path of the MPD server. If empty, connect to the default host. | ||||
| 	typeof: string ++ | ||||
| 	The network address or Unix socket path of the MPD server. If empty, connect to the default host. | ||||
|  | ||||
| *port*: ++ | ||||
|     typeof: integer ++ | ||||
|     The port MPD listens to. If empty, use the default port. | ||||
| 	typeof: integer ++ | ||||
| 	The port MPD listens to. If empty, use the default port. | ||||
|  | ||||
| *interval*: ++ | ||||
|     typeof: integer++ | ||||
|     default: 5 ++ | ||||
|     The interval in which the connection to the MPD server is retried | ||||
| 	typeof: integer++ | ||||
| 	default: 5 ++ | ||||
| 	The interval in which the connection to the MPD server is retried | ||||
|  | ||||
| *timeout*: ++ | ||||
|     typeof: integer++ | ||||
|     default: 30 ++ | ||||
|     The timeout for the connection. Change this if your MPD server has a low `connection_timeout` setting | ||||
| 	typeof: integer++ | ||||
| 	default: 30 ++ | ||||
| 	The timeout for the connection. Change this if your MPD server has a low `connection_timeout` setting | ||||
|  | ||||
| *unknown-tag*: ++ | ||||
|     typeof: string ++ | ||||
|     default: "N/A" ++ | ||||
|     The text to display when a tag is not present in the current song, but used in `format` | ||||
| 	typeof: string ++ | ||||
| 	default: "N/A" ++ | ||||
| 	The text to display when a tag is not present in the current song, but used in `format` | ||||
|  | ||||
| *format*: ++ | ||||
|     typeof: string ++ | ||||
|     default: "{album} - {artist} - {title}" ++ | ||||
|     Information displayed when a song is playing or paused | ||||
| 	typeof: string ++ | ||||
| 	default: "{album} - {artist} - {title}" ++ | ||||
| 	Information displayed when a song is playing. | ||||
|  | ||||
| *format-stopped*: ++ | ||||
|     typeof: string ++ | ||||
|     default: "stopped" ++ | ||||
|     Information displayed when the player is stopped. | ||||
| 	typeof: string ++ | ||||
| 	default: "stopped" ++ | ||||
| 	Information displayed when the player is stopped. | ||||
|  | ||||
| *format-paused*: ++ | ||||
| 	typeof: string ++ | ||||
| 	This format is used when a song is paused. | ||||
|  | ||||
| *format-disconnected*: ++ | ||||
|     typeof: string ++ | ||||
|     default: "disconnected" ++ | ||||
|     Information displayed when the MPD server can't be reached. | ||||
| 	typeof: string ++ | ||||
| 	default: "disconnected" ++ | ||||
| 	Information displayed when the MPD server can't be reached. | ||||
|  | ||||
| *tooltip*: ++ | ||||
|     typeof: bool ++ | ||||
|     default: true ++ | ||||
|     Option to disable tooltip on hover. | ||||
| 	typeof: bool ++ | ||||
| 	default: true ++ | ||||
| 	Option to disable tooltip on hover. | ||||
|  | ||||
| *tooltip-format*: ++ | ||||
|     typeof: string ++ | ||||
|     default: "MPD (connected)" ++ | ||||
|     Tooltip information displayed when connected to MPD. | ||||
| 	typeof: string ++ | ||||
| 	default: "MPD (connected)" ++ | ||||
| 	Tooltip information displayed when connected to MPD. | ||||
|  | ||||
| *tooltip-format-disconnected*: ++ | ||||
|     typeof: string ++ | ||||
|     default: "MPD (disconnected)" ++ | ||||
|     Tooltip information displayed when the MPD server can't be reached. | ||||
| 	typeof: string ++ | ||||
| 	default: "MPD (disconnected)" ++ | ||||
| 	Tooltip information displayed when the MPD server can't be reached. | ||||
|  | ||||
| *rotate*: ++ | ||||
|     typeof: integer ++ | ||||
|     Positive value to rotate the text label. | ||||
| 	typeof: integer ++ | ||||
| 	Positive value to rotate the text label. | ||||
|  | ||||
| *max-length*: ++ | ||||
|     typeof: integer ++ | ||||
|     The maximum length in character the module should display. | ||||
| 	typeof: integer ++ | ||||
| 	The maximum length in character the module should display. | ||||
|  | ||||
| *on-click*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when clicked on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when you right clicked on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|  | ||||
| *on-scroll-up*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when scrolling up on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when scrolling up on the module. | ||||
|  | ||||
| *on-scroll-down*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when scrolling down on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when scrolling down on the module. | ||||
|  | ||||
| *smooth-scrolling-threshold*: ++ | ||||
|     typeof: double ++ | ||||
|     Threshold to be used when scrolling. | ||||
| 	typeof: double ++ | ||||
| 	Threshold to be used when scrolling. | ||||
|  | ||||
| *state-icons*: ++ | ||||
|     typeof: object ++ | ||||
|     default: {} ++ | ||||
|     Icon to show depending on the play/pause state of the player (*{ "playing": "...", "paused": "..." }*) | ||||
| 	typeof: object ++ | ||||
| 	default: {} ++ | ||||
| 	Icon to show depending on the play/pause state of the player (*{ "playing": "...", "paused": "..." }*) | ||||
|  | ||||
| *consume-icons*: ++ | ||||
|     typeof: object ++ | ||||
|     default: {} ++ | ||||
|     Icon to show depending on the "consume" option (*{ "on": "...", "off": "..." }*) | ||||
| 	typeof: object ++ | ||||
| 	default: {} ++ | ||||
| 	Icon to show depending on the "consume" option (*{ "on": "...", "off": "..." }*) | ||||
|  | ||||
| *random-icons*: ++ | ||||
|     typeof: object ++ | ||||
|     default: {} ++ | ||||
|     Icon to show depending on the "random" option (*{ "on": "...", "off": "..." }*) | ||||
| 	typeof: object ++ | ||||
| 	default: {} ++ | ||||
| 	Icon to show depending on the "random" option (*{ "on": "...", "off": "..." }*) | ||||
|  | ||||
| *repeat-icons*: ++ | ||||
|     typeof: object ++ | ||||
|     default: {} ++ | ||||
|     Icon to show depending on the "repeat" option (*{ "on": "...", "off": "..." }*) | ||||
| 	typeof: object ++ | ||||
| 	default: {} ++ | ||||
| 	Icon to show depending on the "repeat" option (*{ "on": "...", "off": "..." }*) | ||||
|  | ||||
| *single-icons*: ++ | ||||
|     typeof: object ++ | ||||
|     default: {} ++ | ||||
|     Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*) | ||||
| 	typeof: object ++ | ||||
| 	default: {} ++ | ||||
| 	Icon to show depending on the "single" option (*{ "on": "...", "off": "..." }*) | ||||
|  | ||||
| # FORMAT REPLACEMENTS | ||||
|  | ||||
|   | ||||
| @@ -21,6 +21,11 @@ Addressed by *network* | ||||
| 	default: 60 ++ | ||||
| 	The interval in which the network information gets polled (e.g. signal strength). | ||||
|  | ||||
| *family*: ++ | ||||
| 	typeof: string ++ | ||||
| 	default: *ipv4* ++ | ||||
| 	The address family that is used for the format replacement {ipaddr} and to determine if a network connection is present. | ||||
|  | ||||
| *format*: ++ | ||||
| 	typeof: string  ++ | ||||
| 	default: *{ifname}* ++ | ||||
| @@ -42,6 +47,11 @@ Addressed by *network* | ||||
| 	typeof: string ++ | ||||
| 	This format is used when the displayed interface is disconnected. | ||||
|  | ||||
| *format-icons*: ++ | ||||
| 	typeof: array/object ++ | ||||
| 	Based on the current signal strength, the corresponding icon gets selected. ++ | ||||
| 	The order is *low* to *high*. Or by the state if it is an object. | ||||
|  | ||||
| *rotate*: ++ | ||||
| 	typeof: integer ++ | ||||
| 	Positive value to rotate the text label. | ||||
| @@ -54,6 +64,10 @@ Addressed by *network* | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
| @@ -117,6 +131,8 @@ Addressed by *network* | ||||
|  | ||||
| *{bandwidthDownOctets}*: Instant down speed in octets/seconds. | ||||
|  | ||||
| *{icon}*: Icon, as defined in *format-icons*. | ||||
|  | ||||
| # EXAMPLES | ||||
|  | ||||
| ``` | ||||
|   | ||||
| @@ -59,6 +59,10 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
| @@ -96,16 +100,17 @@ The following strings for *format-icons* are supported. | ||||
| If they are found in the current PulseAudio port name, the corresponding icons will be selected. | ||||
|  | ||||
| - *default* (Shown, when no other port is found) | ||||
| - *headphones* | ||||
| - *headphone* | ||||
| - *speaker* | ||||
| - *hdmi* | ||||
| - *headset* | ||||
| - *handsfree* | ||||
| - *hands-free* | ||||
| - *portable* | ||||
| - *car* | ||||
| - *hifi* | ||||
| - *phone* | ||||
|  | ||||
|  | ||||
| # EXAMPLES | ||||
|  | ||||
| ``` | ||||
|   | ||||
| @@ -29,6 +29,10 @@ Addressed by *sway/mode* | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -29,6 +29,10 @@ Addressed by *sway/window* | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|   | ||||
| @@ -19,7 +19,7 @@ Addressed by *sway/workspaces* | ||||
|  | ||||
| *format*: ++ | ||||
|     typeof: string ++ | ||||
|     default: {name} ++ | ||||
|     default: {value} ++ | ||||
|     The format, how information should be displayed. | ||||
|  | ||||
| *format-icons*: ++ | ||||
| @@ -62,7 +62,9 @@ Addressed by *sway/workspaces* | ||||
|  | ||||
| # FORMAT REPLACEMENTS | ||||
|  | ||||
| *{name}*: Name of the workspace, as defined by sway. | ||||
| *{value}*: Name of the workspace, as defined by sway. | ||||
|  | ||||
| *{name}*: Number stripped from workspace value. | ||||
|  | ||||
| *{icon}*: Icon, as defined in *format-icons*. | ||||
|  | ||||
| @@ -75,6 +77,7 @@ Additional to workspace name matching, the following *format-icons* can be set. | ||||
| - *default*: Will be shown, when no string matches is found. | ||||
| - *urgent*: Will be shown, when workspace is flagged as urgent | ||||
| - *focused*: Will be shown, when workspace is focused | ||||
| - *persistent*: Will be shown, when workspace is persistent one. | ||||
|  | ||||
| # PERSISTENT WORKSPACES | ||||
|  | ||||
|   | ||||
| @@ -13,71 +13,83 @@ The *temperature* module displays the current temperature from a thermal zone. | ||||
| Addressed by *temperature* | ||||
|  | ||||
| *thermal-zone*: ++ | ||||
|     typeof: integer ++ | ||||
|     The thermal zone, as in */sys/class/thermal/*. | ||||
| 	typeof: integer ++ | ||||
| 	The thermal zone, as in */sys/class/thermal/*. | ||||
|  | ||||
| *hwmon-path*: ++ | ||||
|     typeof: string ++ | ||||
|     The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*. | ||||
| 	typeof: string ++ | ||||
| 	The temperature path to use, e.g. */sys/class/hwmon/hwmon2/temp1_input* instead of one in */sys/class/thermal/*. | ||||
|  | ||||
| *hwmon-path-abs*: ++ | ||||
| 	typeof: string ++ | ||||
| 	The path of the hwmon-directory of the device, e.g. */sys/devices/pci0000:00/0000:00:18.3/hwmon*. (Note that the subdirectory *hwmon/hwmon#*, where *#* is a number is not part of the path!) Has to be used together with *input-filename*. | ||||
|  | ||||
| *input-filename*: ++ | ||||
| 	typeof: string ++ | ||||
| 	The temperature filename of your *hwmon-path-abs*, e.g. *temp1_input* | ||||
|  | ||||
| *critical-threshold*: ++ | ||||
|     typeof: integer ++ | ||||
|     The threshold before it is considered critical (Celcius). | ||||
| 	typeof: integer ++ | ||||
| 	The threshold before it is considered critical (Celsius). | ||||
|  | ||||
| *interval*: ++ | ||||
|     typeof: integer ++ | ||||
|     default: 10 ++ | ||||
|     The interval in which the information gets polled. | ||||
| 	typeof: integer ++ | ||||
| 	default: 10 ++ | ||||
| 	The interval in which the information gets polled. | ||||
|  | ||||
| *format-critical*: ++ | ||||
|     typeof: string ++ | ||||
|     The format to use when temperature is considered critical | ||||
| 	typeof: string ++ | ||||
| 	The format to use when temperature is considered critical | ||||
|  | ||||
| *format*: ++ | ||||
|     typeof: string  ++ | ||||
|     default: {temperatureC}°C ++ | ||||
|     The format (Celcius/Farenheit) in which the temperature should be displayed. | ||||
| 	typeof: string  ++ | ||||
| 	default: {temperatureC}°C ++ | ||||
| 	The format (Celsius/Fahrenheit) in which the temperature should be displayed. | ||||
|  | ||||
| *format-icons*: ++ | ||||
|     typeof: array ++ | ||||
|     Based on the current temperature (Celcius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*. | ||||
| 	typeof: array ++ | ||||
| 	Based on the current temperature (Celsius) and *critical-threshold* if available, the corresponding icon gets selected. The order is *low* to *high*. | ||||
|  | ||||
| *rotate*: ++ | ||||
|     typeof: integer ++ | ||||
|     Positive value to rotate the text label. | ||||
| 	typeof: integer ++ | ||||
| 	Positive value to rotate the text label. | ||||
|  | ||||
| *max-length*: ++ | ||||
|     typeof: integer ++ | ||||
|     The maximum length in characters the module should display. | ||||
| 	typeof: integer ++ | ||||
| 	The maximum length in characters the module should display. | ||||
|  | ||||
| *on-click*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when you clicked on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you clicked on the module. | ||||
|  | ||||
| *on-click-middle*: ++ | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when middle-clicked on the module using mousewheel. | ||||
|  | ||||
| *on-click-right*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when you right clicked on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when you right clicked on the module. | ||||
|  | ||||
| *on-scroll-up*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when scrolling up on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when scrolling up on the module. | ||||
|  | ||||
| *on-scroll-down*: ++ | ||||
|     typeof: string ++ | ||||
|     Command to execute when scrolling down on the module. | ||||
| 	typeof: string ++ | ||||
| 	Command to execute when scrolling down on the module. | ||||
|  | ||||
| *smooth-scrolling-threshold*: ++ | ||||
|     typeof: double ++ | ||||
|     Threshold to be used when scrolling. | ||||
| 	typeof: double ++ | ||||
| 	Threshold to be used when scrolling. | ||||
|  | ||||
| *tooltip*: ++ | ||||
|     typeof: bool ++ | ||||
|     default: true ++ | ||||
|     Option to disable tooltip on hover. | ||||
| 	typeof: bool ++ | ||||
| 	default: true ++ | ||||
| 	Option to disable tooltip on hover. | ||||
|  | ||||
| # FORMAT REPLACEMENTS | ||||
|  | ||||
| *{temperatureC}*: Temperature in Celcius. | ||||
| *{temperatureC}*: Temperature in Celsius. | ||||
|  | ||||
| *{temperatureF}*: Temperature in Fahrenheit. | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,8 @@ Also a minimal example configuration can be found on the at the bottom of this m | ||||
| *layer* ++ | ||||
| 	typeof: string ++ | ||||
| 	default: bottom ++ | ||||
| 	Decide if the bar is displayed in front of the windows or behind them. | ||||
| 	Decide if the bar is displayed in front (*top*) of the windows or behind (*bottom*) | ||||
| 	them. | ||||
|  | ||||
| *output* ++ | ||||
| 	typeof: string|array ++ | ||||
| @@ -66,6 +67,12 @@ Also a minimal example configuration can be found on the at the bottom of this m | ||||
| 	typeof: string ++ | ||||
| 	Optional name added as a CSS class, for styling multiple waybars. | ||||
|  | ||||
| *gtk-layer-shell* ++ | ||||
| 	typeof: bool ++ | ||||
| 	default: true ++ | ||||
| 	Option to disable the use of gtk-layer-shell for popups. | ||||
| 	Only functional if compiled with gtk-layer-shell support. | ||||
|  | ||||
| # MODULE FORMAT | ||||
|  | ||||
| You can use PangoMarkupFormat (See https://developer.gnome.org/pango/stable/PangoMarkupFormat.html#PangoMarkupFormat). | ||||
|   | ||||
							
								
								
									
										41
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								meson.build
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | ||||
| project( | ||||
|     'waybar', 'cpp', 'c', | ||||
|     version: '0.8.0', | ||||
|     version: '0.9.2', | ||||
|     license: 'MIT', | ||||
|     default_options : [ | ||||
|         'cpp_std=c++17', | ||||
| @@ -9,6 +9,8 @@ project( | ||||
|     ], | ||||
| ) | ||||
|  | ||||
| compiler = meson.get_compiler('cpp') | ||||
|  | ||||
| cpp_args = [] | ||||
| cpp_link_args = [] | ||||
|  | ||||
| @@ -16,13 +18,14 @@ if get_option('libcxx') | ||||
|     cpp_args += ['-stdlib=libc++'] | ||||
|     cpp_link_args += ['-stdlib=libc++', '-lc++abi'] | ||||
|  | ||||
|     cpp_link_args += ['-lc++fs'] | ||||
|     if compiler.has_link_argument('-lc++fs') | ||||
|         cpp_link_args += ['-lc++fs'] | ||||
|     endif | ||||
| else | ||||
|     cpp_link_args += ['-lstdc++fs'] | ||||
| endif | ||||
|  | ||||
| compiler = meson.get_compiler('cpp') | ||||
| git = find_program('git', required: false) | ||||
| git = find_program('git', native: true, required: false) | ||||
|  | ||||
| if not git.found() | ||||
|     add_project_arguments('-DVERSION="@0@"'.format(meson.project_version()), language: 'cpp') | ||||
| @@ -42,6 +45,22 @@ if not compiler.has_header('filesystem') | ||||
|     endif | ||||
| endif | ||||
|  | ||||
| code = ''' | ||||
| #include <langinfo.h> | ||||
| #include <locale.h> | ||||
| int main(int argc, char** argv) { | ||||
|     locale_t locale = newlocale(LC_ALL, "en_US.UTF-8", nullptr); | ||||
|     char* str; | ||||
|     str = nl_langinfo_l(_NL_TIME_WEEK_1STDAY, locale); | ||||
|     str = nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, locale); | ||||
|     freelocale(locale); | ||||
|     return 0; | ||||
| } | ||||
| ''' | ||||
| if compiler.links(code, name : 'nl_langinfo with _NL_TIME_WEEK_1STDAY, _NL_TIME_FIRST_WEEKDAY') | ||||
|     add_project_arguments('-DHAVE_LANGINFO_1STDAY', language: 'cpp') | ||||
| endif | ||||
|  | ||||
| add_global_arguments(cpp_args, language : 'cpp') | ||||
| add_global_link_arguments(cpp_link_args, language : 'cpp') | ||||
|  | ||||
| @@ -52,7 +71,7 @@ spdlog = dependency('spdlog', version : ['>=1.3.1'], fallback : ['spdlog', 'spdl | ||||
| wayland_client = dependency('wayland-client') | ||||
| wayland_cursor = dependency('wayland-cursor') | ||||
| wayland_protos = dependency('wayland-protocols') | ||||
| gtkmm = dependency('gtkmm-3.0') | ||||
| gtkmm = dependency('gtkmm-3.0', version : ['>=3.22.0']) | ||||
| dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4', required: get_option('dbusmenu-gtk')) | ||||
| giounix = dependency('gio-unix-2.0', required: get_option('dbusmenu-gtk')) | ||||
| jsoncpp = dependency('jsoncpp') | ||||
| @@ -62,7 +81,11 @@ libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl')) | ||||
| libpulse = dependency('libpulse', required: get_option('pulseaudio')) | ||||
| libudev = dependency('libudev', required: get_option('libudev')) | ||||
| libmpdclient = dependency('libmpdclient', required: get_option('mpd')) | ||||
| gtk_layer_shell = dependency('gtk-layer-shell-0', | ||||
|         required: get_option('gtk-layer-shell'), | ||||
|         fallback : ['gtk-layer-shell', 'gtk_layer_shell_dep']) | ||||
| systemd = dependency('systemd', required: get_option('systemd')) | ||||
| tz_dep = dependency('date', default_options : [ 'use_system_tzdb=true' ], fallback: [ 'date', 'tz_dep' ]) | ||||
|  | ||||
| prefix = get_option('prefix') | ||||
| conf_data = configuration_data() | ||||
| @@ -136,6 +159,10 @@ if libmpdclient.found() | ||||
|     src_files += 'src/modules/mpd.cpp' | ||||
| endif | ||||
|  | ||||
| if gtk_layer_shell.found() | ||||
|     add_project_arguments('-DHAVE_GTK_LAYER_SHELL', language: 'cpp') | ||||
| endif | ||||
|  | ||||
| subdir('protocol') | ||||
|  | ||||
| executable( | ||||
| @@ -158,7 +185,9 @@ executable( | ||||
|         libnlgen, | ||||
|         libpulse, | ||||
|         libudev, | ||||
|         libmpdclient | ||||
|         libmpdclient, | ||||
|         gtk_layer_shell, | ||||
|         tz_dep | ||||
|     ], | ||||
|     include_directories: [include_directories('include')], | ||||
|     install: true, | ||||
|   | ||||
| @@ -7,3 +7,4 @@ option('dbusmenu-gtk', type: 'feature', value: 'auto', description: 'Enable supp | ||||
| option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') | ||||
| option('mpd', type: 'feature', value: 'auto', description: 'Enable support for the Music Player Daemon') | ||||
| option('out', type: 'string', value : '/', description: 'output prefix directory') | ||||
| option('gtk-layer-shell', type: 'feature', value: 'auto', description: 'Use gtk-layer-shell library for popups support') | ||||
|   | ||||
| @@ -31,7 +31,9 @@ | ||||
|     <property name='Id' type='s' access='read'/> | ||||
|     <property name='Title' type='s' access='read'/> | ||||
|     <property name='Status' type='s' access='read'/> | ||||
|     <!-- See discussion on pull #536 | ||||
|     <property name='WindowId' type='u' access='read'/> | ||||
|     --> | ||||
|     <property name='IconThemePath' type='s' access='read'/> | ||||
|     <property name='IconName' type='s' access='read'/> | ||||
|     <property name='IconPixmap' type='a(iiay)' access='read'/> | ||||
| @@ -44,4 +46,4 @@ | ||||
|     <property name='Menu' type='o' access='read'/> | ||||
|     <property name='ItemIsMenu' type='b' access='read'/> | ||||
|   </interface> | ||||
| </node> | ||||
| </node> | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| { | ||||
|     "layer": "top", // Waybar at top layer | ||||
|     // "layer": "top", // Waybar at top layer | ||||
|     // "position": "bottom", // Waybar position (top|bottom|left|right) | ||||
|     "height": 30, // Waybar height (to be removed for auto height) | ||||
|     // "width": 1280, // Waybar width | ||||
| @@ -64,7 +64,8 @@ | ||||
|         "spacing": 10 | ||||
|     }, | ||||
|     "clock": { | ||||
|         "tooltip-format": "{:%Y-%m-%d | %H:%M}", | ||||
|         // "timezone": "America/New_York", | ||||
|         "tooltip-format": "<big>{:%Y %B}</big>\n<tt><small>{calendar}</small></tt>", | ||||
|         "format-alt": "{:%Y-%m-%d}" | ||||
|     }, | ||||
|     "cpu": { | ||||
| @@ -121,8 +122,8 @@ | ||||
|         "format-source": "{volume}% ", | ||||
|         "format-source-muted": "", | ||||
|         "format-icons": { | ||||
|             "headphones": "", | ||||
|             "handsfree": "", | ||||
|             "headphone": "", | ||||
|             "hands-free": "", | ||||
|             "headset": "", | ||||
|             "phone": "", | ||||
|             "portable": "", | ||||
|   | ||||
| @@ -38,6 +38,8 @@ def on_metadata(player, metadata, manager): | ||||
|     elif player.get_artist() != '' and player.get_title() != '': | ||||
|         track_info = '{artist} - {title}'.format(artist=player.get_artist(), | ||||
|                                                  title=player.get_title()) | ||||
|     else: | ||||
|         track_info = player.get_title() | ||||
|  | ||||
|     if player.props.status != 'Playing' and track_info: | ||||
|         track_info = ' ' + track_info | ||||
| @@ -77,7 +79,7 @@ def signal_handler(sig, frame): | ||||
| def parse_arguments(): | ||||
|     parser = argparse.ArgumentParser() | ||||
|  | ||||
|     # Increase verbosity with every occurance of -v | ||||
|     # Increase verbosity with every occurence of -v | ||||
|     parser.add_argument('-v', '--verbose', action='count', default=0) | ||||
|  | ||||
|     # Define for which player we're listening | ||||
| @@ -123,4 +125,3 @@ def main(): | ||||
|  | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| Description=Highly customizable Wayland bar for Sway and Wlroots based compositors. | ||||
| Documentation=https://github.com/Alexays/Waybar/wiki/ | ||||
| PartOf=wayland-session.target | ||||
| After=wayland-session.target | ||||
|  | ||||
| [Service] | ||||
| Type=dbus | ||||
|   | ||||
							
								
								
									
										97
									
								
								src/bar.cpp
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								src/bar.cpp
									
									
									
									
									
								
							| @@ -1,3 +1,7 @@ | ||||
| #ifdef HAVE_GTK_LAYER_SHELL | ||||
| #include <gtk-layer-shell.h> | ||||
| #endif | ||||
|  | ||||
| #include "bar.hpp" | ||||
| #include "client.hpp" | ||||
| #include "factory.hpp" | ||||
| @@ -8,7 +12,7 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) | ||||
|       config(w_config), | ||||
|       window{Gtk::WindowType::WINDOW_TOPLEVEL}, | ||||
|       surface(nullptr), | ||||
|       layer_surface(nullptr), | ||||
|       layer_surface_(nullptr), | ||||
|       anchor_(ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP), | ||||
|       left_(Gtk::ORIENTATION_HORIZONTAL, 0), | ||||
|       center_(Gtk::ORIENTATION_HORIZONTAL, 0), | ||||
| @@ -28,11 +32,6 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) | ||||
|   height_ = config["height"].isUInt() ? config["height"].asUInt() : height_; | ||||
|   width_ = config["width"].isUInt() ? config["width"].asUInt() : width_; | ||||
|  | ||||
|   window.signal_realize().connect_notify(sigc::mem_fun(*this, &Bar::onRealize)); | ||||
|   window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap)); | ||||
|   window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure)); | ||||
|   window.set_size_request(width_, height_); | ||||
|  | ||||
|   if (config["position"] == "bottom") { | ||||
|     anchor_ = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; | ||||
|   } else if (config["position"] == "left") { | ||||
| @@ -98,6 +97,17 @@ waybar::Bar::Bar(struct waybar_output* w_output, const Json::Value& w_config) | ||||
|     margins_ = {.top = gaps, .right = gaps, .bottom = gaps, .left = gaps}; | ||||
|   } | ||||
|  | ||||
| #ifdef HAVE_GTK_LAYER_SHELL | ||||
|   use_gls_ = config["gtk-layer-shell"].isBool() ? config["gtk-layer-shell"].asBool() : true; | ||||
|   if (use_gls_) { | ||||
|     initGtkLayerShell(); | ||||
|   } | ||||
| #endif | ||||
|  | ||||
|   window.signal_realize().connect_notify(sigc::mem_fun(*this, &Bar::onRealize)); | ||||
|   window.signal_map_event().connect_notify(sigc::mem_fun(*this, &Bar::onMap)); | ||||
|   window.signal_configure_event().connect_notify(sigc::mem_fun(*this, &Bar::onConfigure)); | ||||
|   window.set_size_request(width_, height_); | ||||
|   setupWidgets(); | ||||
|  | ||||
|   if (window.get_realized()) { | ||||
| @@ -131,11 +141,48 @@ void waybar::Bar::onConfigure(GdkEventConfigure* ev) { | ||||
|       tmp_width = ev->width; | ||||
|     } | ||||
|   } | ||||
|   if (tmp_width != width_ || tmp_height != height_) { | ||||
|   if (use_gls_) { | ||||
|     width_ = tmp_width; | ||||
|     height_ = tmp_height; | ||||
|     spdlog::debug("Set surface size {}x{} for output {}", width_, height_, output->name); | ||||
|     setExclusiveZone(tmp_width, tmp_height); | ||||
|   } else if (tmp_width != width_ || tmp_height != height_) { | ||||
|     setSurfaceSize(tmp_width, tmp_height); | ||||
|   } | ||||
| } | ||||
|  | ||||
| #ifdef HAVE_GTK_LAYER_SHELL | ||||
| void waybar::Bar::initGtkLayerShell() { | ||||
|   auto gtk_window = window.gobj(); | ||||
|   // this has to be executed before GtkWindow.realize | ||||
|   gtk_layer_init_for_window(gtk_window); | ||||
|   gtk_layer_set_keyboard_interactivity(gtk_window, FALSE); | ||||
|   auto layer = config["layer"] == "top" ? GTK_LAYER_SHELL_LAYER_TOP : GTK_LAYER_SHELL_LAYER_BOTTOM; | ||||
|   gtk_layer_set_layer(gtk_window, layer); | ||||
|   gtk_layer_set_monitor(gtk_window, output->monitor->gobj()); | ||||
|   gtk_layer_set_namespace(gtk_window, "waybar"); | ||||
|  | ||||
|   gtk_layer_set_anchor( | ||||
|       gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); | ||||
|   gtk_layer_set_anchor( | ||||
|       gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); | ||||
|   gtk_layer_set_anchor( | ||||
|       gtk_window, GTK_LAYER_SHELL_EDGE_TOP, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP); | ||||
|   gtk_layer_set_anchor( | ||||
|       gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, anchor_ & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); | ||||
|  | ||||
|   gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_LEFT, margins_.left); | ||||
|   gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_RIGHT, margins_.right); | ||||
|   gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_TOP, margins_.top); | ||||
|   gtk_layer_set_margin(gtk_window, GTK_LAYER_SHELL_EDGE_BOTTOM, margins_.bottom); | ||||
|  | ||||
|   if (width_ > 1 && height_ > 1) { | ||||
|     /* configure events are not emitted if the bar is using initial size */ | ||||
|     setExclusiveZone(width_, height_); | ||||
|   } | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void waybar::Bar::onRealize() { | ||||
|   auto gdk_window = window.get_window()->gobj(); | ||||
|   gdk_wayland_window_set_use_custom_surface(gdk_window); | ||||
| @@ -145,16 +192,22 @@ void waybar::Bar::onMap(GdkEventAny* ev) { | ||||
|   auto gdk_window = window.get_window()->gobj(); | ||||
|   surface = gdk_wayland_window_get_wl_surface(gdk_window); | ||||
|  | ||||
|   if (use_gls_) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   auto client = waybar::Client::inst(); | ||||
|   // owned by output->monitor; no need to destroy | ||||
|   auto wl_output = gdk_wayland_monitor_get_wl_output(output->monitor->gobj()); | ||||
|   auto layer = | ||||
|       config["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; | ||||
|   layer_surface = zwlr_layer_shell_v1_get_layer_surface( | ||||
|       client->layer_shell, surface, output->output, layer, "waybar"); | ||||
|   layer_surface_ = zwlr_layer_shell_v1_get_layer_surface( | ||||
|       client->layer_shell, surface, wl_output, layer, "waybar"); | ||||
|  | ||||
|   zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, false); | ||||
|   zwlr_layer_surface_v1_set_anchor(layer_surface, anchor_); | ||||
|   zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface_, false); | ||||
|   zwlr_layer_surface_v1_set_anchor(layer_surface_, anchor_); | ||||
|   zwlr_layer_surface_v1_set_margin( | ||||
|       layer_surface, margins_.top, margins_.right, margins_.bottom, margins_.left); | ||||
|       layer_surface_, margins_.top, margins_.right, margins_.bottom, margins_.left); | ||||
|   setSurfaceSize(width_, height_); | ||||
|   setExclusiveZone(width_, height_); | ||||
|  | ||||
| @@ -162,7 +215,7 @@ void waybar::Bar::onMap(GdkEventAny* ev) { | ||||
|       .configure = layerSurfaceHandleConfigure, | ||||
|       .closed = layerSurfaceHandleClosed, | ||||
|   }; | ||||
|   zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this); | ||||
|   zwlr_layer_surface_v1_add_listener(layer_surface_, &layer_surface_listener, this); | ||||
|  | ||||
|   wl_surface_commit(surface); | ||||
|   wl_display_roundtrip(client->wl_display); | ||||
| @@ -182,7 +235,15 @@ void waybar::Bar::setExclusiveZone(uint32_t width, uint32_t height) { | ||||
|     } | ||||
|   } | ||||
|   spdlog::debug("Set exclusive zone {} for output {}", zone, output->name); | ||||
|   zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, zone); | ||||
|  | ||||
| #ifdef HAVE_GTK_LAYER_SHELL | ||||
|   if (use_gls_) { | ||||
|     gtk_layer_set_exclusive_zone(window.gobj(), zone); | ||||
|   } else | ||||
| #endif | ||||
|   { | ||||
|     zwlr_layer_surface_v1_set_exclusive_zone(layer_surface_, zone); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) { | ||||
| @@ -198,7 +259,7 @@ void waybar::Bar::setSurfaceSize(uint32_t width, uint32_t height) { | ||||
|     width += margins_.right + margins_.left; | ||||
|   } | ||||
|   spdlog::debug("Set surface size {}x{} for output {}", width, height, output->name); | ||||
|   zwlr_layer_surface_v1_set_size(layer_surface, width, height); | ||||
|   zwlr_layer_surface_v1_set_size(layer_surface_, width, height); | ||||
| } | ||||
|  | ||||
| // Converting string to button code rn as to avoid doing it later | ||||
| @@ -282,9 +343,9 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data, struct zwlr_layer_surf | ||||
|  | ||||
| void waybar::Bar::layerSurfaceHandleClosed(void* data, struct zwlr_layer_surface_v1* /*surface*/) { | ||||
|   auto o = static_cast<waybar::Bar*>(data); | ||||
|   if (o->layer_surface) { | ||||
|     zwlr_layer_surface_v1_destroy(o->layer_surface); | ||||
|     o->layer_surface = nullptr; | ||||
|   if (o->layer_surface_) { | ||||
|     zwlr_layer_surface_v1_destroy(o->layer_surface_); | ||||
|     o->layer_surface_ = nullptr; | ||||
|   } | ||||
|   o->modules_left_.clear(); | ||||
|   o->modules_center_.clear(); | ||||
|   | ||||
							
								
								
									
										136
									
								
								src/client.cpp
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								src/client.cpp
									
									
									
									
									
								
							| @@ -1,4 +1,5 @@ | ||||
| #include "client.hpp" | ||||
| #include <fmt/ostream.h> | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| @@ -33,11 +34,6 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint | ||||
|   if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { | ||||
|     client->layer_shell = static_cast<struct zwlr_layer_shell_v1 *>( | ||||
|         wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version)); | ||||
|   } else if (strcmp(interface, wl_output_interface.name) == 0) { | ||||
|     auto wl_output = static_cast<struct wl_output *>( | ||||
|         wl_registry_bind(registry, name, &wl_output_interface, version)); | ||||
|     client->outputs_.emplace_back(new struct waybar_output({wl_output, "", name, nullptr})); | ||||
|     client->handleOutput(client->outputs_.back()); | ||||
|   } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 && | ||||
|              version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) { | ||||
|     client->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>(wl_registry_bind( | ||||
| @@ -50,91 +46,51 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry, uint | ||||
|  | ||||
| void waybar::Client::handleGlobalRemove(void *   data, struct wl_registry * /*registry*/, | ||||
|                                         uint32_t name) { | ||||
|   auto client = static_cast<Client *>(data); | ||||
|   for (auto it = client->bars.begin(); it != client->bars.end();) { | ||||
|     if ((*it)->output->wl_name == name) { | ||||
|       auto output_name = (*it)->output->name; | ||||
|       (*it)->window.close(); | ||||
|       it = client->bars.erase(it); | ||||
|       spdlog::info("Bar removed from output: {}", output_name); | ||||
|     } else { | ||||
|       ++it; | ||||
|     } | ||||
|   } | ||||
|   auto it = std::find_if(client->outputs_.begin(), | ||||
|                          client->outputs_.end(), | ||||
|                          [&name](const auto &output) { return output->wl_name == name; }); | ||||
|   if (it != client->outputs_.end()) { | ||||
|     if ((*it)->xdg_output != nullptr) { | ||||
|       zxdg_output_v1_destroy((*it)->xdg_output); | ||||
|       (*it)->xdg_output = nullptr; | ||||
|     } | ||||
|     if ((*it)->output != nullptr) { | ||||
|       wl_output_destroy((*it)->output); | ||||
|       (*it)->output = nullptr; | ||||
|     } | ||||
|     client->outputs_.erase(it); | ||||
|   } | ||||
|   // Nothing here | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleOutput(std::unique_ptr<struct waybar_output> &output) { | ||||
| void waybar::Client::handleOutput(struct waybar_output &output) { | ||||
|   static const struct zxdg_output_v1_listener xdgOutputListener = { | ||||
|       .logical_position = handleLogicalPosition, | ||||
|       .logical_size = handleLogicalSize, | ||||
|       .done = handleDone, | ||||
|       .name = handleName, | ||||
|       .description = handleDescription, | ||||
|       .logical_position = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {}, | ||||
|       .logical_size = [](void *, struct zxdg_output_v1 *, int32_t, int32_t) {}, | ||||
|       .done = [](void *, struct zxdg_output_v1 *) {}, | ||||
|       .name = &handleOutputName, | ||||
|       .description = [](void *, struct zxdg_output_v1 *, const char *) {}, | ||||
|   }; | ||||
|   output->xdg_output = zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, output->output); | ||||
|   zxdg_output_v1_add_listener(output->xdg_output, &xdgOutputListener, &output->wl_name); | ||||
|   // owned by output->monitor; no need to destroy | ||||
|   auto wl_output = gdk_wayland_monitor_get_wl_output(output.monitor->gobj()); | ||||
|   output.xdg_output.reset(zxdg_output_manager_v1_get_xdg_output(xdg_output_manager, wl_output)); | ||||
|   zxdg_output_v1_add_listener(output.xdg_output.get(), &xdgOutputListener, &output); | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleLogicalPosition(void * /*data*/, | ||||
|                                            struct zxdg_output_v1 * /*zxdg_output_v1*/, | ||||
|                                            int32_t /*x*/, int32_t /*y*/) { | ||||
|   // Nothing here | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleLogicalSize(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/, | ||||
|                                        int32_t /*width*/, int32_t /*height*/) { | ||||
|   // Nothing here | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleDone(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/) { | ||||
|   // Nothing here | ||||
| } | ||||
|  | ||||
| bool waybar::Client::isValidOutput(const Json::Value &                    config, | ||||
|                                    std::unique_ptr<struct waybar_output> &output) { | ||||
| bool waybar::Client::isValidOutput(const Json::Value &config, struct waybar_output &output) { | ||||
|   bool found = true; | ||||
|   if (config["output"].isArray()) { | ||||
|     bool in_array = false; | ||||
|     for (auto const &output_conf : config["output"]) { | ||||
|       if (output_conf.isString() && output_conf.asString() == output->name) { | ||||
|       if (output_conf.isString() && output_conf.asString() == output.name) { | ||||
|         in_array = true; | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     found = in_array; | ||||
|   } | ||||
|   if (config["output"].isString() && config["output"].asString() != output->name) { | ||||
|   if (config["output"].isString() && config["output"].asString() != output.name) { | ||||
|     found = false; | ||||
|   } | ||||
|   return found; | ||||
| } | ||||
|  | ||||
| std::unique_ptr<struct waybar::waybar_output> &waybar::Client::getOutput(uint32_t wl_name) { | ||||
|   auto it = std::find_if(outputs_.begin(), outputs_.end(), [&wl_name](const auto &output) { | ||||
|     return output->wl_name == wl_name; | ||||
|   }); | ||||
| struct waybar::waybar_output &waybar::Client::getOutput(void *addr) { | ||||
|   auto it = std::find_if( | ||||
|       outputs_.begin(), outputs_.end(), [&addr](const auto &output) { return &output == addr; }); | ||||
|   if (it == outputs_.end()) { | ||||
|     throw std::runtime_error("Unable to find valid output"); | ||||
|   } | ||||
|   return *it; | ||||
| } | ||||
|  | ||||
| std::vector<Json::Value> waybar::Client::getOutputConfigs( | ||||
|     std::unique_ptr<struct waybar_output> &output) { | ||||
| std::vector<Json::Value> waybar::Client::getOutputConfigs(struct waybar_output &output) { | ||||
|   std::vector<Json::Value> configs; | ||||
|   if (config_.isArray()) { | ||||
|     for (auto const &config : config_) { | ||||
| @@ -148,27 +104,23 @@ std::vector<Json::Value> waybar::Client::getOutputConfigs( | ||||
|   return configs; | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleName(void *      data, struct zxdg_output_v1 * /*xdg_output*/, | ||||
|                                 const char *name) { | ||||
|   auto wl_name = *static_cast<uint32_t *>(data); | ||||
| void waybar::Client::handleOutputName(void *      data, struct zxdg_output_v1 * /*xdg_output*/, | ||||
|                                       const char *name) { | ||||
|   auto client = waybar::Client::inst(); | ||||
|   try { | ||||
|     auto &output = client->getOutput(wl_name); | ||||
|     output->name = name; | ||||
|     auto &output = client->getOutput(data); | ||||
|     output.name = name; | ||||
|     spdlog::debug("Output detected: {} ({} {})", | ||||
|                   name, | ||||
|                   output.monitor->get_manufacturer(), | ||||
|                   output.monitor->get_model()); | ||||
|     auto configs = client->getOutputConfigs(output); | ||||
|     if (configs.empty()) { | ||||
|       if (output->output != nullptr) { | ||||
|         wl_output_destroy(output->output); | ||||
|         output->output = nullptr; | ||||
|       } | ||||
|       if (output->xdg_output != nullptr) { | ||||
|         zxdg_output_v1_destroy(output->xdg_output); | ||||
|         output->xdg_output = nullptr; | ||||
|       } | ||||
|       output.xdg_output.reset(); | ||||
|     } else { | ||||
|       wl_display_roundtrip(client->wl_display); | ||||
|       for (const auto &config : configs) { | ||||
|         client->bars.emplace_back(std::make_unique<Bar>(output.get(), config)); | ||||
|         client->bars.emplace_back(std::make_unique<Bar>(&output, config)); | ||||
|         Glib::RefPtr<Gdk::Screen> screen = client->bars.back()->window.get_screen(); | ||||
|         client->style_context_->add_provider_for_screen( | ||||
|             screen, client->css_provider_, GTK_STYLE_PROVIDER_PRIORITY_USER); | ||||
| @@ -179,9 +131,25 @@ void waybar::Client::handleName(void *      data, struct zxdg_output_v1 * /*xdg_ | ||||
|   } | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleDescription(void * /*data*/, struct zxdg_output_v1 * /*zxdg_output_v1*/, | ||||
|                                        const char * /*description*/) { | ||||
|   // Nothing here | ||||
| void waybar::Client::handleMonitorAdded(Glib::RefPtr<Gdk::Monitor> monitor) { | ||||
|   auto &output = outputs_.emplace_back(); | ||||
|   output.monitor = monitor; | ||||
|   handleOutput(output); | ||||
| } | ||||
|  | ||||
| void waybar::Client::handleMonitorRemoved(Glib::RefPtr<Gdk::Monitor> monitor) { | ||||
|   spdlog::debug("Output removed: {} {}", monitor->get_manufacturer(), monitor->get_model()); | ||||
|   for (auto it = bars.begin(); it != bars.end();) { | ||||
|     if ((*it)->output->monitor == monitor) { | ||||
|       auto output_name = (*it)->output->name; | ||||
|       (*it)->window.close(); | ||||
|       it = bars.erase(it); | ||||
|       spdlog::info("Bar removed from output: {}", output_name); | ||||
|     } else { | ||||
|       ++it; | ||||
|     } | ||||
|   } | ||||
|   outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; }); | ||||
| } | ||||
|  | ||||
| std::tuple<const std::string, const std::string> waybar::Client::getConfigs( | ||||
| @@ -240,6 +208,14 @@ void waybar::Client::bindInterfaces() { | ||||
|   if (layer_shell == nullptr || xdg_output_manager == nullptr) { | ||||
|     throw std::runtime_error("Failed to acquire required resources."); | ||||
|   } | ||||
|   // add existing outputs and subscribe to updates | ||||
|   for (auto i = 0; i < gdk_display->get_n_monitors(); ++i) { | ||||
|     auto monitor = gdk_display->get_monitor(i); | ||||
|     handleMonitorAdded(monitor); | ||||
|   } | ||||
|   gdk_display->signal_monitor_added().connect(sigc::mem_fun(*this, &Client::handleMonitorAdded)); | ||||
|   gdk_display->signal_monitor_removed().connect( | ||||
|       sigc::mem_fun(*this, &Client::handleMonitorRemoved)); | ||||
| } | ||||
|  | ||||
| int waybar::Client::main(int argc, char *argv[]) { | ||||
|   | ||||
| @@ -115,6 +115,16 @@ const std::tuple<uint8_t, float, std::string> waybar::modules::Battery::getInfos | ||||
|       time_remaining = -(float)(total_energy_full - total_energy) / total_power; | ||||
|     } | ||||
|     uint16_t capacity = total / batteries_.size(); | ||||
|     // Handle full-at | ||||
|     if (config_["full-at"].isUInt()) { | ||||
|       auto full_at = config_["full-at"].asUInt(); | ||||
|       if (full_at < 100) { | ||||
|         capacity = static_cast<float>(capacity / full_at) * 100; | ||||
|         if (capacity > full_at) { | ||||
|           capacity = full_at; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return {capacity, time_remaining, status}; | ||||
|   } catch (const std::exception& e) { | ||||
|     spdlog::error("Battery: {}", e.what()); | ||||
| @@ -163,7 +173,12 @@ auto waybar::modules::Battery::update() -> void { | ||||
|     } | ||||
|     label_.set_tooltip_text(tooltip_text); | ||||
|   } | ||||
|   // Transform to lowercase | ||||
|   std::transform(status.begin(), status.end(), status.begin(), ::tolower); | ||||
|   // Replace space with dash | ||||
|   std::transform(status.begin(), status.end(), status.begin(), [](char ch) { | ||||
|     return ch == ' ' ? '-' : ch; | ||||
|   }); | ||||
|   auto format = format_; | ||||
|   auto state = getState(capacity, true); | ||||
|   if (!old_status_.empty()) { | ||||
|   | ||||
| @@ -1,8 +1,28 @@ | ||||
| #include "modules/clock.hpp" | ||||
| #include <time.h> | ||||
| #include <sstream> | ||||
| #include <type_traits> | ||||
| #ifdef HAVE_LANGINFO_1STDAY | ||||
| #include <langinfo.h> | ||||
| #include <locale.h> | ||||
| #endif | ||||
|  | ||||
| using waybar::modules::waybar_time; | ||||
|  | ||||
| waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) | ||||
|     : ALabel(config, "clock", id, "{:%H:%M}", 60) { | ||||
|     : ALabel(config, "clock", id, "{:%H:%M}", 60) | ||||
|     , fixed_time_zone_(false) | ||||
| { | ||||
|   if (config_["timezone"].isString()) { | ||||
|     time_zone_ = date::locate_zone(config_["timezone"].asString()); | ||||
|     fixed_time_zone_ = true; | ||||
|   } | ||||
|  | ||||
|   if (config_["locale"].isString()) { | ||||
|     locale_ = std::locale(config_["locale"].asString()); | ||||
|   } else { | ||||
|     locale_ = std::locale(""); | ||||
|   } | ||||
|  | ||||
|   thread_ = [this] { | ||||
|     dp.emit(); | ||||
|     auto now = std::chrono::system_clock::now(); | ||||
| @@ -13,21 +33,115 @@ waybar::modules::Clock::Clock(const std::string& id, const Json::Value& config) | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::update() -> void { | ||||
|   tzset(); // Update timezone information | ||||
|   auto now = std::chrono::system_clock::now(); | ||||
|   auto localtime = fmt::localtime(std::chrono::system_clock::to_time_t(now)); | ||||
|   auto text = fmt::format(format_, localtime); | ||||
|   if (!fixed_time_zone_) { | ||||
|     // Time zone can change. Be sure to pick that. | ||||
|     time_zone_ = date::current_zone(); | ||||
|   } | ||||
|   auto        now = std::chrono::system_clock::now(); | ||||
|   waybar_time wtime = {locale_, | ||||
|                        date::make_zoned(time_zone_, date::floor<std::chrono::seconds>(now))}; | ||||
|  | ||||
|   auto text = fmt::format(format_, wtime); | ||||
|   label_.set_markup(text); | ||||
|  | ||||
|   if (tooltipEnabled()) { | ||||
|     if (config_["tooltip-format"].isString()) { | ||||
|       const auto calendar = calendar_text(wtime); | ||||
|       auto tooltip_format = config_["tooltip-format"].asString(); | ||||
|       auto tooltip_text = fmt::format(tooltip_format, localtime); | ||||
|       label_.set_tooltip_text(tooltip_text); | ||||
|       auto tooltip_text = fmt::format(tooltip_format, wtime, fmt::arg("calendar", calendar)); | ||||
|       label_.set_tooltip_markup(tooltip_text); | ||||
|     } else { | ||||
|       label_.set_tooltip_text(text); | ||||
|       label_.set_tooltip_markup(text); | ||||
|     } | ||||
|   } | ||||
|   // Call parent update | ||||
|   ALabel::update(); | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::calendar_text(const waybar_time& wtime) -> std::string { | ||||
|   const auto daypoint = date::floor<date::days>(wtime.ztime.get_local_time()); | ||||
|   const auto ymd = date::year_month_day(daypoint); | ||||
|   if (cached_calendar_ymd_ == ymd) { | ||||
|     return cached_calendar_text_; | ||||
|   } | ||||
|  | ||||
|   const date::year_month ym(ymd.year(), ymd.month()); | ||||
|   const auto curr_day = ymd.day(); | ||||
|  | ||||
|   std::stringstream os; | ||||
|   const auto first_dow = first_day_of_week(); | ||||
|   weekdays_header(first_dow, os); | ||||
|  | ||||
|   // First week prefixed with spaces if needed. | ||||
|   auto wd = date::weekday(ym/1); | ||||
|   auto empty_days = (wd - first_dow).count(); | ||||
|   if (empty_days > 0) { | ||||
|     os << std::string(empty_days * 3 - 1, ' '); | ||||
|   } | ||||
|   auto last_day = (ym/date::literals::last).day(); | ||||
|   for (auto d = date::day(1); d <= last_day; ++d, ++wd) { | ||||
|     if (wd != first_dow) { | ||||
|       os << ' '; | ||||
|     } else if (unsigned(d) != 1) { | ||||
|       os << '\n'; | ||||
|     } | ||||
|     if (d == curr_day) { | ||||
|       os << "<b><u>" << date::format("%e", d) << "</u></b>"; | ||||
|     } else { | ||||
|       os << date::format("%e", d); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   auto result = os.str(); | ||||
|   cached_calendar_ymd_ = ymd; | ||||
|   cached_calendar_text_ = result; | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std::ostream& os) -> void { | ||||
|   auto wd = first_dow; | ||||
|   do { | ||||
|     if (wd != first_dow) os << ' '; | ||||
|     Glib::ustring wd_ustring(date::format(locale_, "%a", wd)); | ||||
|     auto wd_len = wd_ustring.length(); | ||||
|     if (wd_len > 2) { | ||||
|       wd_ustring = wd_ustring.substr(0, 2); | ||||
|       wd_len = 2; | ||||
|     } | ||||
|     const std::string pad(2 - wd_len, ' '); | ||||
|     os << pad << wd_ustring; | ||||
|   } while (++wd != first_dow); | ||||
|   os << "\n"; | ||||
| } | ||||
|  | ||||
| #ifdef HAVE_LANGINFO_1STDAY | ||||
| template <auto fn> | ||||
| using deleter_from_fn = std::integral_constant<decltype(fn), fn>; | ||||
|  | ||||
| template <typename T, auto fn> | ||||
| using deleting_unique_ptr = std::unique_ptr<T, deleter_from_fn<fn>>; | ||||
| #endif | ||||
|  | ||||
| // Computations done similarly to Linux cal utility. | ||||
| auto waybar::modules::Clock::first_day_of_week() -> date::weekday { | ||||
| #ifdef HAVE_LANGINFO_1STDAY | ||||
|   deleting_unique_ptr<std::remove_pointer<locale_t>::type, freelocale> | ||||
|     posix_locale{newlocale(LC_ALL, locale_.name().c_str(), nullptr)}; | ||||
|   if (posix_locale) { | ||||
|     const int i = (std::intptr_t) nl_langinfo_l(_NL_TIME_WEEK_1STDAY, posix_locale.get()); | ||||
|     auto ymd = date::year(i / 10000)/(i / 100 % 100)/(i % 100); | ||||
|     auto wd = date::weekday(ymd); | ||||
|     uint8_t j = *nl_langinfo_l(_NL_TIME_FIRST_WEEKDAY, posix_locale.get()); | ||||
|     return wd + date::days(j - 1); | ||||
|   } | ||||
| #endif | ||||
|   return date::Sunday; | ||||
| } | ||||
|  | ||||
| template <> | ||||
| struct fmt::formatter<waybar_time> : fmt::formatter<std::tm> { | ||||
|   template <typename FormatContext> | ||||
|   auto format(const waybar_time& t, FormatContext& ctx) { | ||||
|     return format_to(ctx.out(), "{}", date::format(t.locale, fmt::to_string(tm_format), t.ztime)); | ||||
|   } | ||||
| }; | ||||
|   | ||||
| @@ -49,19 +49,24 @@ void waybar::modules::Custom::continuousWorker() { | ||||
|   thread_ = [&] { | ||||
|     char*  buff = nullptr; | ||||
|     size_t len = 0; | ||||
|     bool restart = false; | ||||
|     if (getline(&buff, &len, fp_) == -1) { | ||||
|       int exit_code = 1; | ||||
|       if (fp_) { | ||||
|         exit_code = WEXITSTATUS(util::command::close(fp_, pid_)); | ||||
|         fp_ = nullptr; | ||||
|       } | ||||
|       thread_.stop(); | ||||
|       if (exit_code != 0) { | ||||
|         output_ = {exit_code, ""}; | ||||
|         dp.emit(); | ||||
|         spdlog::error("{} stopped unexpectedly, is it endless?", name_); | ||||
|       } | ||||
|       return; | ||||
|       if (config_["restart-interval"].isUInt()) { | ||||
|         restart = true; | ||||
|       } else { | ||||
|         thread_.stop(); | ||||
|         return; | ||||
|       } | ||||
|     } | ||||
|     std::string output = buff; | ||||
|  | ||||
| @@ -71,6 +76,14 @@ void waybar::modules::Custom::continuousWorker() { | ||||
|     } | ||||
|     output_ = {0, output}; | ||||
|     dp.emit(); | ||||
|     if (restart) { | ||||
|       pid_ = -1; | ||||
|       fp_ = util::command::open(cmd, pid_); | ||||
|       if (!fp_) { | ||||
|         throw std::runtime_error("Unable to open " + cmd); | ||||
|       } | ||||
|       thread_.sleep_for(std::chrono::seconds(config_["restart-interval"].asUInt())); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -10,11 +10,23 @@ waybar::modules::Memory::Memory(const std::string& id, const Json::Value& config | ||||
|  | ||||
| auto waybar::modules::Memory::update() -> void { | ||||
|   parseMeminfo(); | ||||
|   if (memtotal_ > 0 && memfree_ >= 0) { | ||||
|     auto total_ram_gigabytes = memtotal_ / std::pow(1024, 2); | ||||
|     int  used_ram_percentage = 100 * (memtotal_ - memfree_) / memtotal_; | ||||
|     auto used_ram_gigabytes = (memtotal_ - memfree_) / std::pow(1024, 2); | ||||
|     auto available_ram_gigabytes = memfree_ / std::pow(1024, 2); | ||||
|  | ||||
|   unsigned long memtotal = meminfo_["MemTotal"]; | ||||
|   unsigned long memfree; | ||||
|   if (meminfo_.count("MemAvailable")) { | ||||
|     // New kernels (3.4+) have an accurate available memory field. | ||||
|     memfree = meminfo_["MemAvailable"]; | ||||
|   } else { | ||||
|     // Old kernel; give a best-effort approximation of available memory. | ||||
|     memfree = meminfo_["MemFree"] + meminfo_["Buffers"] + meminfo_["Cached"] + | ||||
|               meminfo_["SReclaimable"] - meminfo_["Shmem"]; | ||||
|   } | ||||
|  | ||||
|   if (memtotal > 0 && memfree >= 0) { | ||||
|     auto total_ram_gigabytes = memtotal / std::pow(1024, 2); | ||||
|     int  used_ram_percentage = 100 * (memtotal - memfree) / memtotal; | ||||
|     auto used_ram_gigabytes = (memtotal - memfree) / std::pow(1024, 2); | ||||
|     auto available_ram_gigabytes = memfree / std::pow(1024, 2); | ||||
|  | ||||
|     getState(used_ram_percentage); | ||||
|     label_.set_markup(fmt::format(format_, | ||||
| @@ -35,7 +47,6 @@ auto waybar::modules::Memory::update() -> void { | ||||
| } | ||||
|  | ||||
| void waybar::modules::Memory::parseMeminfo() { | ||||
|   int64_t       memfree = -1, membuffer = -1, memcache = -1, memavail = -1; | ||||
|   std::ifstream info(data_dir_); | ||||
|   if (!info.is_open()) { | ||||
|     throw std::runtime_error("Can't open " + data_dir_); | ||||
| @@ -46,23 +57,9 @@ void waybar::modules::Memory::parseMeminfo() { | ||||
|     if (posDelim == std::string::npos) { | ||||
|       continue; | ||||
|     } | ||||
|  | ||||
|     std::string name = line.substr(0, posDelim); | ||||
|     int64_t     value = std::stol(line.substr(posDelim + 1)); | ||||
|  | ||||
|     if (name.compare("MemTotal") == 0) { | ||||
|       memtotal_ = value; | ||||
|     } else if (name.compare("MemAvailable") == 0) { | ||||
|       memavail = value; | ||||
|     } else if (name.compare("MemFree") == 0) { | ||||
|       memfree = value; | ||||
|     } else if (name.compare("Buffers") == 0) { | ||||
|       membuffer = value; | ||||
|     } else if (name.compare("Cached") == 0) { | ||||
|       memcache = value; | ||||
|     } | ||||
|     if (memtotal_ > 0 && (memavail >= 0 || (memfree > -1 && membuffer > -1 && memcache > -1))) { | ||||
|       break; | ||||
|     } | ||||
|     meminfo_[name] = value; | ||||
|   } | ||||
|   memfree_ = memavail >= 0 ? memavail : memfree + membuffer + memcache; | ||||
| } | ||||
|   | ||||
| @@ -143,7 +143,9 @@ void waybar::modules::MPD::setLabel() { | ||||
|     if (playing()) { | ||||
|       label_.get_style_context()->add_class("playing"); | ||||
|       label_.get_style_context()->remove_class("paused"); | ||||
|     } else { | ||||
|     } else if (paused()) { | ||||
|       format = | ||||
|         config_["format-paused"].isString() ? config_["format-paused"].asString() : config_["format"].asString(); | ||||
|       label_.get_style_context()->add_class("paused"); | ||||
|       label_.get_style_context()->remove_class("playing"); | ||||
|     } | ||||
| @@ -349,3 +351,5 @@ bool waybar::modules::MPD::stopped() { | ||||
| } | ||||
|  | ||||
| bool waybar::modules::MPD::playing() { return connection_ != nullptr && state_ == MPD_STATE_PLAY; } | ||||
|  | ||||
| bool waybar::modules::MPD::paused() { return connection_ != nullptr && state_ == MPD_STATE_PAUSE; } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <sys/eventfd.h> | ||||
| #include <fstream> | ||||
| #include <cassert> | ||||
| #include "util/format.hpp" | ||||
|  | ||||
|  | ||||
| @@ -278,8 +279,13 @@ auto waybar::modules::Network::update() -> void { | ||||
|       fmt::arg("bandwidthUpBits", pow_format(bandwidth_up * 8ull / interval_.count(), "b/s")), | ||||
|       fmt::arg("bandwidthDownOctets", pow_format(bandwidth_down / interval_.count(), "o/s")), | ||||
|       fmt::arg("bandwidthUpOctets", pow_format(bandwidth_up / interval_.count(), "o/s"))); | ||||
|   if (text != label_.get_label()) { | ||||
|   if (text.compare(label_.get_label()) != 0) { | ||||
|     label_.set_markup(text); | ||||
|     if (text.empty()) { | ||||
|       event_box_.hide(); | ||||
|     } else { | ||||
|       event_box_.show(); | ||||
|     } | ||||
|   } | ||||
|   if (tooltipEnabled()) { | ||||
|     if (tooltip_format.empty() && config_["tooltip-format"].isString()) { | ||||
| @@ -437,7 +443,6 @@ out: | ||||
| } | ||||
|  | ||||
| void waybar::modules::Network::getInterfaceAddress() { | ||||
|   unsigned int    cidrRaw; | ||||
|   struct ifaddrs *ifaddr, *ifa; | ||||
|   cidr_ = 0; | ||||
|   int success = getifaddrs(&ifaddr); | ||||
| @@ -449,18 +454,34 @@ void waybar::modules::Network::getInterfaceAddress() { | ||||
|     if (ifa->ifa_addr != nullptr && ifa->ifa_addr->sa_family == family_ && | ||||
|         ifa->ifa_name == ifname_) { | ||||
|       char ipaddr[INET6_ADDRSTRLEN]; | ||||
|       ipaddr_ = inet_ntop(family_, | ||||
|                           &reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr)->sin_addr, | ||||
|                           ipaddr, | ||||
|                           INET6_ADDRSTRLEN); | ||||
|       char netmask[INET6_ADDRSTRLEN]; | ||||
|       auto net_addr = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask); | ||||
|       netmask_ = inet_ntop(family_, &net_addr->sin_addr, netmask, INET6_ADDRSTRLEN); | ||||
|       cidrRaw = net_addr->sin_addr.s_addr; | ||||
|       unsigned int cidr = 0; | ||||
|       while (cidrRaw) { | ||||
|         cidr += cidrRaw & 1; | ||||
|         cidrRaw >>= 1; | ||||
|       if (family_ == AF_INET) { | ||||
|         ipaddr_ = inet_ntop(AF_INET, | ||||
|                             &reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr)->sin_addr, | ||||
|                             ipaddr, | ||||
|                             INET_ADDRSTRLEN); | ||||
|         auto net_addr = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_netmask); | ||||
|         netmask_ = inet_ntop(AF_INET, &net_addr->sin_addr, netmask, INET_ADDRSTRLEN); | ||||
|         unsigned int cidrRaw = net_addr->sin_addr.s_addr; | ||||
|         while (cidrRaw) { | ||||
|           cidr += cidrRaw & 1; | ||||
|           cidrRaw >>= 1; | ||||
|         } | ||||
|       } else { | ||||
|         ipaddr_ = inet_ntop(AF_INET6, | ||||
|                             &reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr)->sin6_addr, | ||||
|                             ipaddr, | ||||
|                             INET6_ADDRSTRLEN); | ||||
|         auto net_addr = reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_netmask); | ||||
|         netmask_ = inet_ntop(AF_INET6, &net_addr->sin6_addr, netmask, INET6_ADDRSTRLEN); | ||||
|         for (size_t i = 0; i < sizeof(net_addr->sin6_addr.s6_addr); ++i) { | ||||
|           unsigned char cidrRaw = net_addr->sin6_addr.s6_addr[i]; | ||||
|           while (cidrRaw) { | ||||
|             cidr += cidrRaw & 1; | ||||
|             cidrRaw >>= 1; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       cidr_ = cidr; | ||||
|       break; | ||||
|   | ||||
| @@ -21,7 +21,7 @@ waybar::modules::Pulseaudio::Pulseaudio(const std::string &id, const Json::Value | ||||
|   if (context_ == nullptr) { | ||||
|     throw std::runtime_error("pa_context_new() failed."); | ||||
|   } | ||||
|   if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOAUTOSPAWN, nullptr) < 0) { | ||||
|   if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) { | ||||
|     auto err = | ||||
|         fmt::format("pa_context_connect() failed: {}", pa_strerror(pa_context_errno(context_))); | ||||
|     throw std::runtime_error(err); | ||||
| @@ -52,7 +52,8 @@ void waybar::modules::Pulseaudio::contextStateCb(pa_context *c, void *data) { | ||||
|       pa_context_set_subscribe_callback(c, subscribeCb, data); | ||||
|       pa_context_subscribe( | ||||
|           c, | ||||
|           static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) | | ||||
|           static_cast<enum pa_subscription_mask>(static_cast<int>(PA_SUBSCRIPTION_MASK_SERVER) | | ||||
|                                                  static_cast<int>(PA_SUBSCRIPTION_MASK_SINK) | | ||||
|                                                  static_cast<int>(PA_SUBSCRIPTION_MASK_SOURCE)), | ||||
|           nullptr, | ||||
|           nullptr); | ||||
| @@ -109,7 +110,9 @@ void waybar::modules::Pulseaudio::subscribeCb(pa_context *                 conte | ||||
|   if (operation != PA_SUBSCRIPTION_EVENT_CHANGE) { | ||||
|     return; | ||||
|   } | ||||
|   if (facility == PA_SUBSCRIPTION_EVENT_SINK) { | ||||
|   if (facility == PA_SUBSCRIPTION_EVENT_SERVER) { | ||||
|     pa_context_get_server_info(context, serverInfoCb, data); | ||||
|   } else if (facility == PA_SUBSCRIPTION_EVENT_SINK) { | ||||
|     pa_context_get_sink_info_by_index(context, idx, sinkInfoCb, data); | ||||
|   } else if (facility == PA_SUBSCRIPTION_EVENT_SOURCE) { | ||||
|     pa_context_get_source_info_by_index(context, idx, sourceInfoCb, data); | ||||
| @@ -131,15 +134,15 @@ void waybar::modules::Pulseaudio::volumeModifyCb(pa_context *c, int success, voi | ||||
|  */ | ||||
| void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const pa_source_info *i, | ||||
|                                                int /*eol*/, void *data) { | ||||
|   if (i != nullptr) { | ||||
|     auto self = static_cast<waybar::modules::Pulseaudio *>(data); | ||||
|   auto pa = static_cast<waybar::modules::Pulseaudio *>(data); | ||||
|   if (i != nullptr && pa->default_source_name_ == i->name) { | ||||
|     auto source_volume = static_cast<float>(pa_cvolume_avg(&(i->volume))) / float{PA_VOLUME_NORM}; | ||||
|     self->source_volume_ = std::round(source_volume * 100.0F); | ||||
|     self->source_idx_ = i->index; | ||||
|     self->source_muted_ = i->mute != 0; | ||||
|     self->source_desc_ = i->description; | ||||
|     self->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown"; | ||||
|     self->dp.emit(); | ||||
|     pa->source_volume_ = std::round(source_volume * 100.0F); | ||||
|     pa->source_idx_ = i->index; | ||||
|     pa->source_muted_ = i->mute != 0; | ||||
|     pa->source_desc_ = i->description; | ||||
|     pa->source_port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown"; | ||||
|     pa->dp.emit(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -147,9 +150,9 @@ void waybar::modules::Pulseaudio::sourceInfoCb(pa_context * /*context*/, const p | ||||
|  * Called when the requested sink information is ready. | ||||
|  */ | ||||
| void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, | ||||
|                                              int /*eol*/, void *                           data) { | ||||
|   if (i != nullptr) { | ||||
|     auto pa = static_cast<waybar::modules::Pulseaudio *>(data); | ||||
|                                              int /*eol*/, void *data) { | ||||
|   auto pa = static_cast<waybar::modules::Pulseaudio *>(data); | ||||
|   if (i != nullptr && pa->default_sink_name_ == i->name) { | ||||
|     pa->pa_volume_ = i->volume; | ||||
|     float volume = static_cast<float>(pa_cvolume_avg(&(pa->pa_volume_))) / float{PA_VOLUME_NORM}; | ||||
|     pa->sink_idx_ = i->index; | ||||
| @@ -158,6 +161,9 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_ | ||||
|     pa->desc_ = i->description; | ||||
|     pa->monitor_ = i->monitor_source_name; | ||||
|     pa->port_name_ = i->active_port != nullptr ? i->active_port->name : "Unknown"; | ||||
|     if (auto ff = pa_proplist_gets(i->proplist, PA_PROP_DEVICE_FORM_FACTOR)) { | ||||
|       pa->form_factor_ = ff; | ||||
|     } | ||||
|     pa->dp.emit(); | ||||
|   } | ||||
| } | ||||
| @@ -168,16 +174,20 @@ void waybar::modules::Pulseaudio::sinkInfoCb(pa_context * /*context*/, const pa_ | ||||
|  */ | ||||
| void waybar::modules::Pulseaudio::serverInfoCb(pa_context *context, const pa_server_info *i, | ||||
|                                                void *data) { | ||||
|   auto pa = static_cast<waybar::modules::Pulseaudio *>(data); | ||||
|   pa->default_sink_name_ = i->default_sink_name; | ||||
|   pa->default_source_name_ = i->default_source_name; | ||||
|  | ||||
|   pa_context_get_sink_info_by_name(context, i->default_sink_name, sinkInfoCb, data); | ||||
|   pa_context_get_source_info_by_name(context, i->default_source_name, sourceInfoCb, data); | ||||
| } | ||||
|  | ||||
| static const std::array<std::string, 9> ports = { | ||||
|     "headphones", | ||||
|     "headphone", | ||||
|     "speaker", | ||||
|     "hdmi", | ||||
|     "headset", | ||||
|     "handsfree", | ||||
|     "hands-free", | ||||
|     "portable", | ||||
|     "car", | ||||
|     "hifi", | ||||
| @@ -185,7 +195,7 @@ static const std::array<std::string, 9> ports = { | ||||
| }; | ||||
|  | ||||
| const std::string waybar::modules::Pulseaudio::getPortIcon() const { | ||||
|   std::string nameLC = port_name_; | ||||
|   std::string nameLC = port_name_ + form_factor_; | ||||
|   std::transform(nameLC.begin(), nameLC.end(), nameLC.begin(), ::tolower); | ||||
|   for (auto const &port : ports) { | ||||
|     if (nameLC.find(port) != std::string::npos) { | ||||
| @@ -197,21 +207,27 @@ const std::string waybar::modules::Pulseaudio::getPortIcon() const { | ||||
|  | ||||
| auto waybar::modules::Pulseaudio::update() -> void { | ||||
|   auto format = format_; | ||||
|   std::string format_name = "format"; | ||||
|   if (monitor_.find("a2dp_sink") != std::string::npos) { | ||||
|     format_name = format_name + "-bluetooth"; | ||||
|     label_.get_style_context()->add_class("bluetooth"); | ||||
|   } else { | ||||
|     label_.get_style_context()->remove_class("bluetooth"); | ||||
|   if (!alt_) { | ||||
|     std::string format_name = "format"; | ||||
|     if (monitor_.find("a2dp_sink") != std::string::npos) { | ||||
|       format_name = format_name + "-bluetooth"; | ||||
|       label_.get_style_context()->add_class("bluetooth"); | ||||
|     } else { | ||||
|       label_.get_style_context()->remove_class("bluetooth"); | ||||
|     } | ||||
|     if (muted_) { | ||||
|       // Check muted bluetooth format exist, otherwise fallback to default muted format | ||||
|       if (format_name != "format" && !config_[format_name + "-muted"].isString()) { | ||||
|         format_name = "format"; | ||||
|       } | ||||
|       format_name = format_name + "-muted"; | ||||
|       label_.get_style_context()->add_class("muted"); | ||||
|     } else { | ||||
|       label_.get_style_context()->remove_class("muted"); | ||||
|     } | ||||
|     format = | ||||
|       config_[format_name].isString() ? config_[format_name].asString() : format; | ||||
|   } | ||||
|   if (muted_ ) { | ||||
|     format_name = format_name + "-muted"; | ||||
|     label_.get_style_context()->add_class("muted"); | ||||
|   } else { | ||||
|     label_.get_style_context()->remove_class("muted"); | ||||
|   } | ||||
|   format = | ||||
|     config_[format_name].isString() ? config_[format_name].asString() : format; | ||||
|   // TODO: find a better way to split source/sink | ||||
|   std::string format_source = "{volume}%"; | ||||
|   if (source_muted_ && config_["format-source-muted"].isString()) { | ||||
|   | ||||
| @@ -265,7 +265,11 @@ void Item::updateImage() { | ||||
|         if (pixbuf->gobj() != nullptr) { | ||||
|           // An icon specified by path and filename may be the wrong size for | ||||
|           // the tray | ||||
|           pixbuf = pixbuf->scale_simple(icon_size, icon_size, Gdk::InterpType::INTERP_BILINEAR); | ||||
|           // Keep the aspect ratio and scale to make the height equal to icon_size | ||||
|           // If people have non square icons, assume they want it to grow in width not height | ||||
|           int width = icon_size * pixbuf->get_width() / pixbuf->get_height(); | ||||
|  | ||||
|           pixbuf = pixbuf->scale_simple(width, icon_size, Gdk::InterpType::INTERP_BILINEAR); | ||||
|           image.set(pixbuf); | ||||
|         } | ||||
|       } else { | ||||
|   | ||||
| @@ -6,7 +6,7 @@ namespace waybar::modules::SNI { | ||||
| Tray::Tray(const std::string& id, const Bar& bar, const Json::Value& config) | ||||
|     : AModule(config, "tray", id), | ||||
|       box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), | ||||
|       watcher_(nb_hosts_), | ||||
|       watcher_(SNI::Watcher::getInstance()), | ||||
|       host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1), | ||||
|             std::bind(&Tray::onRemove, this, std::placeholders::_1)) { | ||||
|   spdlog::warn( | ||||
|   | ||||
| @@ -3,14 +3,13 @@ | ||||
|  | ||||
| using namespace waybar::modules::SNI; | ||||
|  | ||||
| Watcher::Watcher(std::size_t id) | ||||
| Watcher::Watcher() | ||||
|     : bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION, | ||||
|                                        "org.kde.StatusNotifierWatcher", | ||||
|                                        sigc::mem_fun(*this, &Watcher::busAcquired), | ||||
|                                        Gio::DBus::SlotNameAcquired(), Gio::DBus::SlotNameLost(), | ||||
|                                        Gio::DBus::BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | | ||||
|                                            Gio::DBus::BUS_NAME_OWNER_FLAGS_REPLACE)), | ||||
|       watcher_id_(id), | ||||
|       watcher_(sn_watcher_skeleton_new()) {} | ||||
|  | ||||
| Watcher::~Watcher() { | ||||
| @@ -23,6 +22,7 @@ Watcher::~Watcher() { | ||||
|     g_slist_free_full(items_, gfWatchFree); | ||||
|     items_ = nullptr; | ||||
|   } | ||||
|   Gio::DBus::unown_name(bus_name_id_); | ||||
|   auto iface = G_DBUS_INTERFACE_SKELETON(watcher_); | ||||
|   g_dbus_interface_skeleton_unexport(iface); | ||||
| } | ||||
| @@ -34,7 +34,7 @@ void Watcher::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib: | ||||
|   if (error != nullptr) { | ||||
|     // Don't print an error when a watcher is already present | ||||
|     if (error->code != 2) { | ||||
|       spdlog::error("Watcher {}: {}", watcher_id_, error->message); | ||||
|       spdlog::error("Watcher: {}", error->message); | ||||
|     } | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   | ||||
| @@ -10,19 +10,23 @@ Ipc::Ipc() { | ||||
| } | ||||
|  | ||||
| Ipc::~Ipc() { | ||||
|   // To fail the IPC header | ||||
|   write(fd_, "close-sway-ipc", 14); | ||||
|   write(fd_event_, "close-sway-ipc", 14); | ||||
|   thread_.stop(); | ||||
|  | ||||
|   if (fd_ > 0) { | ||||
|     // To fail the IPC header | ||||
|     write(fd_, "close-sway-ipc", 14); | ||||
|     close(fd_); | ||||
|     fd_ = -1; | ||||
|   } | ||||
|   if (fd_event_ > 0) { | ||||
|     write(fd_event_, "close-sway-ipc", 14); | ||||
|     close(fd_event_); | ||||
|     fd_event_ = -1; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Ipc::setWorker(std::function<void()>&& func) { thread_ = func; } | ||||
|  | ||||
| const std::string Ipc::getSocketPath() const { | ||||
|   const char* env = getenv("SWAYSOCK"); | ||||
|   if (env != nullptr) { | ||||
|   | ||||
| @@ -8,7 +8,13 @@ Mode::Mode(const std::string& id, const Json::Value& config) | ||||
|   ipc_.subscribe(R"(["mode"])"); | ||||
|   ipc_.signal_event.connect(sigc::mem_fun(*this, &Mode::onEvent)); | ||||
|   // Launch worker | ||||
|   worker(); | ||||
|   ipc_.setWorker([this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception& e) { | ||||
|       spdlog::error("Mode: {}", e.what()); | ||||
|     } | ||||
|   }); | ||||
|   dp.emit(); | ||||
| } | ||||
|  | ||||
| @@ -31,16 +37,6 @@ void Mode::onEvent(const struct Ipc::ipc_response& res) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Mode::worker() { | ||||
|   thread_ = [this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception& e) { | ||||
|       spdlog::error("Mode: {}", e.what()); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| auto Mode::update() -> void { | ||||
|   if (mode_.empty()) { | ||||
|     event_box_.hide(); | ||||
|   | ||||
| @@ -11,7 +11,13 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config) | ||||
|   // Get Initial focused window | ||||
|   getTree(); | ||||
|   // Launch worker | ||||
|   worker(); | ||||
|   ipc_.setWorker([this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception& e) { | ||||
|       spdlog::error("Window: {}", e.what()); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| void Window::onEvent(const struct Ipc::ipc_response& res) { getTree(); } | ||||
| @@ -28,16 +34,6 @@ void Window::onCmd(const struct Ipc::ipc_response& res) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Window::worker() { | ||||
|   thread_ = [this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception& e) { | ||||
|       spdlog::error("Window: {}", e.what()); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| auto Window::update() -> void { | ||||
|   if (!old_app_id_.empty()) { | ||||
|     bar_.window.get_style_context()->remove_class(old_app_id_); | ||||
|   | ||||
| @@ -22,7 +22,13 @@ Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value | ||||
|     window.signal_scroll_event().connect(sigc::mem_fun(*this, &Workspaces::handleScroll)); | ||||
|   } | ||||
|   // Launch worker | ||||
|   worker(); | ||||
|   ipc_.setWorker([this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception &e) { | ||||
|       spdlog::error("Workspaces: {}", e.what()); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| void Workspaces::onEvent(const struct Ipc::ipc_response &res) { | ||||
| @@ -102,16 +108,6 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) { | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Workspaces::worker() { | ||||
|   thread_ = [this] { | ||||
|     try { | ||||
|       ipc_.handleEvent(); | ||||
|     } catch (const std::exception &e) { | ||||
|       spdlog::error("Workspaces: {}", e.what()); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
|  | ||||
| bool Workspaces::filterButtons() { | ||||
|   bool needReorder = false; | ||||
|   for (auto it = buttons_.begin(); it != buttons_.end();) { | ||||
| @@ -161,12 +157,13 @@ auto Workspaces::update() -> void { | ||||
|     if (needReorder) { | ||||
|       box_.reorder_child(button, it - workspaces_.begin()); | ||||
|     } | ||||
|     std::string output = getIcon((*it)["name"].asString(), *it); | ||||
|     std::string output = (*it)["name"].asString(); | ||||
|     if (config_["format"].isString()) { | ||||
|       auto format = config_["format"].asString(); | ||||
|       output = fmt::format(format, | ||||
|                            fmt::arg("icon", output), | ||||
|                            fmt::arg("name", trimWorkspaceName((*it)["name"].asString())), | ||||
|                            fmt::arg("icon", getIcon(output, *it)), | ||||
|                            fmt::arg("value", output), | ||||
|                            fmt::arg("name", trimWorkspaceName(output)), | ||||
|                            fmt::arg("index", (*it)["num"].asString())); | ||||
|     } | ||||
|     if (!config_["disable-markup"].asBool()) { | ||||
| @@ -211,6 +208,8 @@ std::string Workspaces::getIcon(const std::string &name, const Json::Value &node | ||||
|       if (config_["format-icons"][key].isString() && node[key].asBool()) { | ||||
|         return config_["format-icons"][key].asString(); | ||||
|       } | ||||
|     } else if (config_["format_icons"]["persistent"].isString() && node["target_output"].isString()) { | ||||
|       return config_["format-icons"]["persistent"].asString(); | ||||
|     } else if (config_["format-icons"][key].isString()) { | ||||
|       return config_["format-icons"][key].asString(); | ||||
|     } | ||||
|   | ||||
| @@ -1,9 +1,12 @@ | ||||
| #include "modules/temperature.hpp" | ||||
| #include <filesystem> | ||||
|  | ||||
| waybar::modules::Temperature::Temperature(const std::string& id, const Json::Value& config) | ||||
|     : ALabel(config, "temperature", id, "{temperatureC}°C", 10) { | ||||
|   if (config_["hwmon-path"].isString()) { | ||||
|     file_path_ = config_["hwmon-path"].asString(); | ||||
|   } else if (config_["hwmon-path-abs"].isString() && config_["input-filename"].isString()) { | ||||
|     file_path_ = (*std::filesystem::directory_iterator(config_["hwmon-path-abs"].asString())).path().u8string() + "/" + config_["input-filename"].asString(); | ||||
|   } else { | ||||
|     auto zone = config_["thermal-zone"].isInt() ? config_["thermal-zone"].asInt() : 0; | ||||
|     file_path_ = fmt::format("/sys/class/thermal/thermal_zone{}/temp", zone); | ||||
|   | ||||
							
								
								
									
										9
									
								
								subprojects/date.wrap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								subprojects/date.wrap
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| [wrap-file] | ||||
| source_url=https://github.com/HowardHinnant/date/archive/v2.4.1.tar.gz | ||||
| source_filename=date-2.4.1.tar.gz | ||||
| source_hash=98907d243397483bd7ad889bf6c66746db0d7d2a39cc9aacc041834c40b65b98 | ||||
| directory=date-2.4.1 | ||||
|  | ||||
| patch_url = https://github.com/mesonbuild/hinnant-date/releases/download/2.4.1-1/hinnant-date.zip | ||||
| patch_filename = hinnant-date-2.4.1-1-wrap.zip | ||||
| patch_hash = 2061673a6f8e6d63c3a40df4da58fa2b3de2835fd9b3e74649e8279599f3a8f6 | ||||
| @@ -5,6 +5,6 @@ source_url = https://github.com/fmtlib/fmt/archive/5.3.0.tar.gz | ||||
| source_filename = fmt-5.3.0.tar.gz | ||||
| source_hash = defa24a9af4c622a7134076602070b45721a43c51598c8456ec6f2c4dbb51c89 | ||||
|  | ||||
| patch_url = https://wrapdb.mesonbuild.com/v1/projects/fmt/5.3.0/1/get_zip | ||||
| patch_url = https://github.com/mesonbuild/fmt/releases/download/5.3.0-1/fmt.zip | ||||
| patch_filename = fmt-5.3.0-1-wrap.zip | ||||
| patch_hash = 18f21a3b8833949c35d4ac88a7059577d5fa24b98786e4b1b2d3d81bb811440f | ||||
							
								
								
									
										5
									
								
								subprojects/gtk-layer-shell.wrap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								subprojects/gtk-layer-shell.wrap
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| [wrap-file] | ||||
| directory = gtk-layer-shell-0.1.0 | ||||
| source_filename = gtk-layer-shell-0.1.0.tar.gz | ||||
| source_hash = f7569e27ae30b1a94c3ad6c955cf56240d6bc272b760d9d266ce2ccdb94a5cf0 | ||||
| source_url = https://github.com/wmww/gtk-layer-shell/archive/v0.1.0/gtk-layer-shell-0.1.0.tar.gz | ||||
| @@ -5,6 +5,6 @@ source_url = https://github.com/gabime/spdlog/archive/v1.3.1.tar.gz | ||||
| source_filename = v1.3.1.tar.gz | ||||
| source_hash = 160845266e94db1d4922ef755637f6901266731c4cb3b30b45bf41efa0e6ab70 | ||||
|  | ||||
| patch_url = https://wrapdb.mesonbuild.com/v1/projects/spdlog/1.3.1/1/get_zip | ||||
| patch_url = https://github.com/mesonbuild/spdlog/releases/download/1.3.1-1/spdlog.zip | ||||
| patch_filename = spdlog-1.3.1-1-wrap.zip | ||||
| patch_hash = 715a0229781019b853d409cc0bf891ee4b9d3a17bec0cf87f4ad30b28bbecc87 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Alex
					Alex